【RT-Thread】nxp rt10xx 设备驱动框架之--pwm搭建和使用

本文详细介绍使用RT-Thread实时操作系统进行脉冲宽度调制(PWM)驱动开发的过程,包括Kconfig配置、驱动文件修改及应用层示例。适用于nxprt10xx单片机,涵盖PWM设备初始化、配置与控制等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

脉冲宽度调制(PWM),全称:Pulse Width Modulation。常用于电机控制,屏幕显示等功能。具体功能网上自行搜索。

开发前准备

  • 硬件平台:nxp rt10xx单片机
  • IDE: Keil

1.Kconfig 修改和menuconfig配置

Env环境menuconfigRT-Thread Components->Device Drivers 设备驱动默认为n,所以需要开启。

请添加图片描述

从git下来的drv_pwm.c文件开头宏可知(如果没有,那就自己搭建个这个文件吧),需在Kconfig中添加如下语句,然后在Env环境menuconfigHardware Drivers Config->On-Chip Peripheral Drivers 使能PWM,特别注意下左边配置,BSP_USING_PWM1,由于PWM可用的选择很多PWM1,2,3,4,每个PWM还分很多通道,为了偷懒,也觉得没必要都加上,所以这里只加了PWM1

请添加图片描述

2.工程添加PWM驱动框架和BSP驱动接口

添加设备驱动的时候笔者发现怎么也找不到pwm.c文件,好家伙官方组件命名怎么又叫 rt_drv_pwm.c 没明白rt命名规范到底是啥规则(全局搜索rt_drv_xxx命名的,也只有它了,希望官方能规范下)

请添加图片描述

设备驱动框架:rt_drv_pwm.c BSP接口:drv_pwm.c fsl_pwm.c

请添加图片描述

3.添加或修改drv_pwm.c

笔者查阅了文件,实际没啥要改的

  • 定义pwm device
static struct rt_pwm_ops imxrt_drv_ops =
{
    .control = imxrt_drv_pwm_control
};
  • 设备创建注册

imxrt_pwm1_init 实现了外设初始化(注意IO的初始化,笔者统一放到pin_mux.c);rt_device_pwm_register 实现设备驱动注册

int rt_hw_pwm_init(void)
{
    rt_err_t ret = RT_EOK;
	
	// XBARA_Init(XBARA1);
	// XBARA_SetSignalsConnection(XBARA1,kXBARA1_InputLogicHigh,kXBARA1_OutputFlexpwm1Fault0);
	// XBARA_SetSignalsConnection(XBARA1,kXBARA1_InputLogicHigh,kXBARA1_OutputFlexpwm1Fault1);
	// XBARA_SetSignalsConnection(XBARA1,kXBARA1_InputLogicHigh,kXBARA1_OutputFlexpwm1234Fault2);
	// XBARA_SetSignalsConnection(XBARA1,kXBARA1_InputLogicHigh,kXBARA1_OutputFlexpwm1234Fault3);
	
#ifdef BSP_USING_PWM1

    static struct rt_device_pwm pwm1_device;

    if (imxrt_pwm1_init(PWM1) != RT_EOK)
    {
        LOG_E("init pwm1 failed\n");
    }

    ret = rt_device_pwm_register(&pwm1_device, "pwm1", &imxrt_drv_ops, PWM1);

    if (ret != RT_EOK)
    {
        LOG_E("%s register failed", "pwm1");
    }

#endif /* BSP_USING_PWM1 */

#ifdef BSP_USING_PWM2

    static struct rt_device_pwm pwm2_device;

    if (imxrt_pwm2_init(PWM2) != RT_EOK)
    {
        LOG_E("init pwm2 failed\n");
    }

    ret = rt_device_pwm_register(&pwm2_device, "pwm2", &imxrt_drv_ops, PWM2);

    if (ret != RT_EOK)
    {
        LOG_E("%s register failed", "pwm2");
    }
#endif /* BSP_USING_PWM2 */

#ifdef BSP_USING_PWM3

    static struct rt_device_pwm pwm3_device;

    if (imxrt_pwm3_init(PWM3) != RT_EOK)
    {
        LOG_E("init pwm3 failed\n");
    }

    ret = rt_device_pwm_register(&pwm3_device, "pwm3", &imxrt_drv_ops, PWM3);

    if (ret != RT_EOK)
    {
        LOG_E("%s register failed", "pwm3");
    }

#endif /* BSP_USING_PWM3 */

#ifdef BSP_USING_PWM4

    static struct rt_device_pwm pwm4_device;

    if (imxrt_pwm4_init(PWM4) != RT_EOK)
    {
        LOG_E("init pwm4 failed\n");
    }

    ret = rt_device_pwm_register(&pwm4_device, "pwm4", &imxrt_drv_ops, PWM4);

    if (ret != RT_EOK)
    {
        LOG_E("%s register failed", "pwm4");
    }
#endif /* BSP_USING_PWM4 */

#if defined(BSP_USING_QTMR1) || defined(BSP_USING_QTMR2) || defined(BSP_USING_QTMR3) || defined(BSP_USING_QTMR4)
    if (imxrt_qtmr_init() != RT_EOK)
    {
        LOG_E(LOG_TAG" init qtmr failed");
    }
#endif

#ifdef BSP_USING_QTMR1
    static struct rt_device_pwm qtmr1_device;
    ret = rt_device_pwm_register(&qtmr1_device, "pwm5", &imxrt_drv_qtmr_ops, TMR1);
    if (ret != RT_EOK)
    {
        LOG_E("%s register failed", "pwm5");
    }
#endif /* BSP_USING_QTMR1 */

#ifdef BSP_USING_QTMR2
    static struct rt_device_pwm qtmr2_device;
    ret = rt_device_pwm_register(&qtmr2_device, "pwm6", &imxrt_drv_qtmr_ops, TMR2);
    if (ret != RT_EOK)
    {
        LOG_E("%s register failed", "pwm6");
    }
#endif /* BSP_USING_QTMR2 */

#ifdef BSP_USING_QTMR3
    static struct rt_device_pwm qtmr3_device;
    ret = rt_device_pwm_register(&qtmr3_device, "pwm7", &imxrt_drv_qtmr_ops, TMR3);
    if (ret != RT_EOK)
    {
        LOG_E("%s register failed", "pwm7");
    }
#endif /* BSP_USING_QTMR3 */

#ifdef BSP_USING_QTMR4
    static struct rt_device_pwm qtmr4_device;
    ret = rt_device_pwm_register(&qtmr4_device, "pwm8", &imxrt_drv_qtmr_ops, TMR4);
    if (ret != RT_EOK)
    {
        LOG_E("%s register failed", "pwm8");
    }
#endif /* BSP_USING_QTMR4 */

    return ret;
}

INIT_BOARD_EXPORT(rt_hw_pwm_init);
  • pwm device 相关函数

内容很简单直接贴代码,不用修改啥

static rt_err_t imxrt_drv_pwm_enable(struct rt_device_pwm *device, struct rt_pwm_configuration *configuration, rt_bool_t enable)
{
    PWM_Type *base;
    pwm_module_control_t pwm_module_control;

    base = (PWM_Type *)device->parent.user_data;
    pwm_module_control = (pwm_module_control_t)(1 << configuration->channel);

    if (!enable)
    {
        PWM_StopTimer(base, pwm_module_control);
    }
    else
    {
        PWM_StartTimer(base, pwm_module_control);
    }

    return RT_EOK;
}

static rt_err_t imxrt_drv_pwm_get(struct rt_device_pwm *device, struct rt_pwm_configuration *configuration)
{
    uint8_t get_duty;
    uint16_t pulseCnt = 0, pwmHighPulse = 0;
    uint32_t get_frequence;
    uint32_t pwmClock;
    PWM_Type *base;
    pwm_submodule_t pwm_submodule;

    base = (PWM_Type *)device->parent.user_data;
    pwm_submodule = (pwm_submodule_t)configuration->channel;

    /* get frequence */
    get_frequence = base->SM[pwm_submodule].VAL1;
    pwmClock = (PWM_SRC_CLK_FREQ / (1U << ((base->SM[pwm_submodule].CTRL & PWM_CTRL_PRSC_MASK) >> PWM_CTRL_PRSC_SHIFT)));
    get_frequence = pwmClock / get_frequence;

    /* get dutycycle */
    pulseCnt = base->SM[pwm_submodule].VAL1;
    pwmHighPulse = pulseCnt - (base->SM[pwm_submodule].VAL2) * 2;
    get_duty = pwmHighPulse * 100 / pulseCnt;

    /* conversion */
    configuration->period = 1000000000 / get_frequence;
    configuration->pulse = get_duty * configuration->period / 100;

    return RT_EOK;
}

static rt_err_t imxrt_drv_pwm_set(struct rt_device_pwm *device, struct rt_pwm_configuration *configuration)
{
    RT_ASSERT(configuration->period > 0);
    RT_ASSERT(configuration->pulse <= configuration->period);

    PWM_Type *base;
    pwm_submodule_t pwm_submodule;
    pwm_module_control_t pwm_module_control;
    uint32_t period = 0;
    uint8_t duty = 0;

    base = (PWM_Type *)device->parent.user_data;
    pwm_submodule = (pwm_submodule_t)configuration->channel;
    pwm_module_control = (pwm_module_control_t)(1 << configuration->channel);

    duty = configuration->pulse * 100 / configuration->period;
    Pwm_Signal.dutyCyclePercent = duty;
    period = (uint32_t)(1000000000 / configuration->period);

    PWM_SetupPwm(base, pwm_submodule, &Pwm_Signal, 1, kPWM_CenterAligned, period, PWM_SRC_CLK_FREQ);
    PWM_UpdatePwmDutycycle(base, pwm_submodule, DEFAULT_COMPLEMENTARY_PAIR, kPWM_CenterAligned, duty);
    PWM_SetPwmLdok(base, pwm_module_control, true);

    return RT_EOK;
}

static rt_err_t imxrt_drv_pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
{
    struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg;

    switch (cmd)
    {
    case PWM_CMD_ENABLE:
        return imxrt_drv_pwm_enable(device, configuration, RT_TRUE);
    case PWM_CMD_DISABLE:
        return imxrt_drv_pwm_enable(device, configuration, RT_FALSE);
    case PWM_CMD_SET:
        return imxrt_drv_pwm_set(device, configuration);
    case PWM_CMD_GET:
        return imxrt_drv_pwm_get(device, configuration);
    default:
        return RT_EINVAL;
    }
}

static rt_err_t imxrt_drv_pwm_init(PWM_Type *base, pwm_submodule_t pwm_submodule, uint16_t psc, uint32_t fre, uint8_t duty)
{
    pwm_config_t PwmConfig;
    uint8_t fault_input;
    pwm_clock_prescale_t pwm_prescale = (pwm_clock_prescale_t)psc;
    fault_input = (uint8_t)pwm_submodule;
    PWM_GetDefaultConfig(&PwmConfig);

    PwmConfig.prescale = pwm_prescale;
    PwmConfig.reloadLogic = kPWM_ReloadPwmFullCycle;
    PwmConfig.pairOperation = kPWM_Independent;
    PwmConfig.enableDebugMode = true;

    if (PWM_Init(base, pwm_submodule, &PwmConfig) == kStatus_Fail)
    {
        LOG_E("init pwm failed \n");
        return -RT_ERROR;
    }

    base->SM[fault_input].DISMAP[0] = 0x00;
    base->SM[fault_input].DISMAP[1] = 0x00;

    Pwm_Signal.pwmChannel = DEFAULT_COMPLEMENTARY_PAIR;
    Pwm_Signal.level = DEFAULT_POLARITY;
    Pwm_Signal.dutyCyclePercent = duty;

    PWM_SetupPwm(base, pwm_submodule, &Pwm_Signal, 1, kPWM_CenterAligned, fre, PWM_SRC_CLK_FREQ);
    PWM_SetPwmLdok(base, pwm_submodule, true);

    return RT_EOK;
}

4.搭建应用层demo

输出1KHz频率,占空比50的波形

#define PWM_DEV_NAME        "pwm1"  /* PWM设备名称 */
#define PWM_DEV_CHANNEL     0       /* PWM通道 */


/*------------------------------------------------------------------------------------------------------------------
Variables
*/
struct rt_device_pwm *pwm_dev;      /* PWM设备句柄 */

/*------------------------------------------------------------------------------------------------------------------
Functions
*/
int pwmsample(void)
{
    rt_uint32_t period;

    period = 1000000;    /*单位ns 周期为:1ms (1KHz)*/

    /* 查找设备 */
    pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM_DEV_NAME);
    if (pwm_dev == RT_NULL)
    {
        rt_kprintf("pwm sample run failed! can't find %s device!\n", PWM_DEV_NAME);
        return RT_ERROR;
    }

    rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period, period/2);
	//rt_device_control(pwm_dev, PWM_CMD_ENABLE, &configuration);
    rt_pwm_enable(pwm_dev, PWM_DEV_CHANNEL);
	
	rt_kprintf("pwm start\r\n");
	
	return 0;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(pwmsample, pwm sample);

输入命令pwmsample运行应用,用虚拟示波器测试波形验证结果

请添加图片描述

请添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值