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


    脉冲宽度调制(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
    };
    
    • 1
    • 2
    • 3
    • 4
    • 设备创建注册

    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);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125

    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);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

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

    请添加图片描述

    请添加图片描述

  • 相关阅读:
    【WEEK15】学习目标及总结【Spring Boot】【中文版】
    常用排序算法时间与空间复杂度
    基于RHEL 8的Linux发行版的初始服务器设置
    前端安全问题——暴破登录
    从滑动窗口到YOLO、Transformer:目标检测的技术革新
    安全运营中心自动化究竟是好还是坏
    【机器学习13】生成对抗网络
    10 Minimax估计和Bayes估计
    测试管理之一定条件下的测试管理
    如何解决Win11系统崩溃的问题?
  • 原文地址:https://blog.csdn.net/weixin_38426553/article/details/125600794