Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
NXP 微控制器
【NXP-MCXA153】eFlexPWM驱动移植
发布于 2024-12-31 14:48:41 浏览:31
订阅该版
[tocm] ## 介绍 PWM(Pulse Width Modulation),脉冲宽度调制,是一种数字量控制模拟量的技术,常用于电机驱动、显示屏背光控制、逆变控制等;NXP-MCXA153开发板上虽然只有一路flexPWM,但它支持多路IO输出,分为三个submodule,每一个subomdule支持3路引脚输出(B、A、X) ## 移植流程 ① 在board里边添加相应的外设:eFlexPWM外设复位、相关引脚功能复用等 ② 添加相应的config开关、Kconfig开关,用以指示相应的外设开启与关闭(本质是通过宏定义或者条件编译的方式) ③ 根据[SDK_2_14_2_FRDM-MCXA153](https://mcuxpresso.nxp.com/zh/builder?hw=FRDM-MCXA153)提供的pwm示例工程编写pwm总线驱动,需要实现几个关键的函数 - mcx_pwm_init - mcx_drv_pwm_control - mcx_drv_pwm_enable - mcx_drv_pwm_disable ④ 添加相应的库文件依赖:fsl_pwm.c ## 驱动文件 ### pin_mux.c 在`BOARD_InitPins`函数里加入以下代码:配置eFlexPWM外设为复位状态、设置P3_0、P3_8、P3_10引脚功能为对应的PWM通道 ```c /* FLEXPWM0 peripheral is released from reset */ RESET_ReleasePeripheralReset(kFLEXPWM0_RST_SHIFT_RSTn); #ifdef BSP_USING_PWM0 const port_pin_config_t port3_0_pin46_config = {/* Internal pull-up/down resistor is disabled */ kPORT_PullDisable, /* Low internal pull resistor value is selected. */ kPORT_LowPullResistor, /* Fast slew rate is configured */ kPORT_FastSlewRate, /* Passive input filter is disabled */ kPORT_PassiveFilterDisable, /* Open drain output is disabled */ kPORT_OpenDrainDisable, /* Low drive strength is configured */ kPORT_LowDriveStrength, /* Normal drive strength is configured */ kPORT_NormalDriveStrength, /* Pin is configured as PWM0_A0 */ kPORT_MuxAlt5, /* Digital input enabled */ kPORT_InputBufferEnable, /* Digital input is not inverted */ kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ kPORT_UnlockRegister}; /* PORT3_0 (pin 38) is configured as PWM0_A0 */ PORT_SetPinConfig(PORT3, 0U, &port3_0_pin46_config); #endif #ifdef BSP_USING_PWM1 const port_pin_config_t port3_8_pin42_config = {/* Internal pull-up/down resistor is disabled */ kPORT_PullDisable, /* Low internal pull resistor value is selected. */ kPORT_LowPullResistor, /* Fast slew rate is configured */ kPORT_FastSlewRate, /* Passive input filter is disabled */ kPORT_PassiveFilterDisable, /* Open drain output is disabled */ kPORT_OpenDrainDisable, /* Low drive strength is configured */ kPORT_LowDriveStrength, /* Normal drive strength is configured */ kPORT_NormalDriveStrength, /* Pin is configured as PWM0_A0 */ kPORT_MuxAlt5, /* Digital input enabled */ kPORT_InputBufferEnable, /* Digital input is not inverted */ kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ kPORT_UnlockRegister}; /* PORT3_8 (pin 42) is configured as PWM0_A1 */ PORT_SetPinConfig(PORT3, 8U, &port3_8_pin42_config); #endif #ifdef BSP_USING_PWM2 const port_pin_config_t port3_10_pin40_config = {/* Internal pull-up/down resistor is disabled */ kPORT_PullDisable, /* Low internal pull resistor value is selected. */ kPORT_LowPullResistor, /* Fast slew rate is configured */ kPORT_FastSlewRate, /* Passive input filter is disabled */ kPORT_PassiveFilterDisable, /* Open drain output is disabled */ kPORT_OpenDrainDisable, /* Low drive strength is configured */ kPORT_LowDriveStrength, /* Normal drive strength is configured */ kPORT_NormalDriveStrength, /* Pin is configured as PWM0_A0 */ kPORT_MuxAlt5, /* Digital input enabled */ kPORT_InputBufferEnable, /* Digital input is not inverted */ kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ kPORT_UnlockRegister}; /* PORT3_10 (pin 40) is configured as PWM0_A2 */ PORT_SetPinConfig(PORT3, 10U, &port3_10_pin40_config); #endif ``` ### board/Kconfig 加入PWM0、PWM1、PWM2相关配置 ``` menuconfig BSP_USING_PWM config BSP_USING_PWM bool "Enable PWM" select RT_USING_PWM default N if BSP_USING_PWM config BSP_USING_PWM0 bool "Enable PWM0" default N config BSP_USING_PWM1 bool "Enable PWM1" default N config BSP_USING_PWM2 bool "Enable PWM2" default N endif ``` ### drv_pwm.c pwm驱动层适配如下 ```c /* * Copyright (c) 2006-2024 RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2024-12-18 hywing Initial version. */ #include
#include
#include "fsl_pwm.h" #ifdef RT_USING_PWM #define BOARD_PWM_BASEADDR (FLEXPWM0) #define PWM_SRC_CLK_FREQ (CLOCK_GetFreq(kCLOCK_BusClk)) #define FLEX_PWM_CLOCK_DEVIDER (kPWM_Prescale_Divide_2) #define FLEX_PWM_FAULT_LEVEL true typedef struct { struct rt_device_pwm pwm_device; pwm_submodule_t submodule; pwm_module_control_t control; pwm_channels_t channel; pwm_clock_prescale_t prescale; char *name; } mcx_pwm_obj_t; static mcx_pwm_obj_t mcx_pwm_list[]= { #ifdef BSP_USING_PWM0 { .submodule = kPWM_Module_0, .control = kPWM_Control_Module_0, .channel = kPWM_PwmA, .prescale = FLEX_PWM_CLOCK_DEVIDER, .name = "pwm0", }, #endif #ifdef BSP_USING_PWM1 { .submodule = kPWM_Module_1, .control = kPWM_Control_Module_1, .channel = kPWM_PwmA, .prescale = FLEX_PWM_CLOCK_DEVIDER, .name = "pwm1", }, #endif #ifdef BSP_USING_PWM2 { .submodule = kPWM_Module_2, .control = kPWM_Control_Module_2, .channel = kPWM_PwmA, .prescale = FLEX_PWM_CLOCK_DEVIDER, .name = "pwm2", }, #endif }; static rt_err_t mcx_drv_pwm_get(mcx_pwm_obj_t *pwm, struct rt_pwm_configuration *configuration) { return RT_EOK; } static rt_err_t mcx_drv_pwm_set(mcx_pwm_obj_t *pwm, struct rt_pwm_configuration *configuration) { uint8_t dutyCyclePercent = configuration->pulse * 100 / configuration->period; pwm_signal_param_t pwmSignal[1]; uint32_t pwmFrequencyInHz = 1000000000 / configuration->period; pwmSignal[0].pwmChannel = pwm->channel; pwmSignal[0].level = kPWM_HighTrue; pwmSignal[0].dutyCyclePercent = dutyCyclePercent; pwmSignal[0].deadtimeValue = 0; pwmSignal[0].faultState = kPWM_PwmFaultState0; pwmSignal[0].pwmchannelenable = true; PWM_SetupPwm(BOARD_PWM_BASEADDR, pwm->submodule, pwmSignal, 1, kPWM_SignedCenterAligned, pwmFrequencyInHz, PWM_SRC_CLK_FREQ); PWM_UpdatePwmDutycycle(BOARD_PWM_BASEADDR, pwm->submodule, pwm->channel, kPWM_SignedCenterAligned, dutyCyclePercent); PWM_SetPwmLdok(BOARD_PWM_BASEADDR, pwm->control, true); return 0; } static rt_err_t mcx_drv_pwm_enable(mcx_pwm_obj_t *pwm, struct rt_pwm_configuration *configuration) { PWM_StartTimer(BOARD_PWM_BASEADDR, pwm->control); return 0; } static rt_err_t mcx_drv_pwm_disable(mcx_pwm_obj_t *pwm, struct rt_pwm_configuration *configuration) { PWM_StopTimer(BOARD_PWM_BASEADDR, pwm->control); return 0; } static rt_err_t mcx_drv_pwm_control(struct rt_device_pwm *device, int cmd, void *args) { mcx_pwm_obj_t *pwm = device->parent.user_data; struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)args; switch (cmd) { case PWM_CMD_ENABLE: return mcx_drv_pwm_enable(pwm, configuration); case PWM_CMD_DISABLE: return mcx_drv_pwm_disable(pwm, configuration); case PWM_CMD_SET: return mcx_drv_pwm_set(pwm, configuration); case PWM_CMD_GET: return mcx_drv_pwm_get(pwm, configuration); default: return -RT_EINVAL; } return RT_EOK; } static struct rt_pwm_ops mcx_pwm_ops = { .control = mcx_drv_pwm_control, }; int mcx_pwm_init(void) { rt_err_t ret; pwm_config_t pwmConfig; pwm_fault_param_t faultConfig; PWM_GetDefaultConfig(&pwmConfig); pwmConfig.prescale = FLEX_PWM_CLOCK_DEVIDER; pwmConfig.reloadLogic = kPWM_ReloadPwmFullCycle; int i; for (i = 0; i < sizeof(mcx_pwm_list) / sizeof(mcx_pwm_list[0]); i++) { pwm_config_t pwmConfig; pwm_fault_param_t faultConfig; PWM_GetDefaultConfig(&pwmConfig); pwmConfig.prescale = mcx_pwm_list[i].prescale; pwmConfig.reloadLogic = kPWM_ReloadPwmFullCycle; if (PWM_Init(BOARD_PWM_BASEADDR, mcx_pwm_list[i].submodule, &pwmConfig) == kStatus_Fail) { rt_kprintf("PWM Init Failed\n"); } ret = rt_device_pwm_register(&mcx_pwm_list[i].pwm_device, mcx_pwm_list[i].name, &mcx_pwm_ops, &mcx_pwm_list[i]); } /* * config->faultClearingMode = kPWM_Automatic; * config->faultLevel = false; * config->enableCombinationalPath = true; * config->recoverMode = kPWM_NoRecovery; */ PWM_FaultDefaultConfig(&faultConfig); faultConfig.faultLevel = FLEX_PWM_FAULT_LEVEL; /* Sets up the PWM fault protection */ PWM_SetupFaults(BOARD_PWM_BASEADDR, kPWM_Fault_0, &faultConfig); PWM_SetupFaults(BOARD_PWM_BASEADDR, kPWM_Fault_1, &faultConfig); PWM_SetupFaults(BOARD_PWM_BASEADDR, kPWM_Fault_2, &faultConfig); PWM_SetupFaults(BOARD_PWM_BASEADDR, kPWM_Fault_3, &faultConfig); /* Set PWM fault disable mapping for submodule 0/1/2 */ PWM_SetupFaultDisableMap(BOARD_PWM_BASEADDR, kPWM_Module_0, kPWM_PwmA, kPWM_faultchannel_0, kPWM_FaultDisable_0 | kPWM_FaultDisable_1 | kPWM_FaultDisable_2 | kPWM_FaultDisable_3); PWM_SetupFaultDisableMap(BOARD_PWM_BASEADDR, kPWM_Module_1, kPWM_PwmA, kPWM_faultchannel_0, kPWM_FaultDisable_0 | kPWM_FaultDisable_1 | kPWM_FaultDisable_2 | kPWM_FaultDisable_3); PWM_SetupFaultDisableMap(BOARD_PWM_BASEADDR, kPWM_Module_2, kPWM_PwmA, kPWM_faultchannel_0, kPWM_FaultDisable_0 | kPWM_FaultDisable_1 | kPWM_FaultDisable_2 | kPWM_FaultDisable_3); /* Set the load okay bit for all submodules to load registers from their buffer */ PWM_SetPwmLdok(BOARD_PWM_BASEADDR, kPWM_Control_Module_0 | kPWM_Control_Module_1 | kPWM_Control_Module_2, true); return ret; } INIT_DEVICE_EXPORT(mcx_pwm_init); #endif /* RT_USING_PWM */ ``` ### SConscript 在`Libraries/MCXA153/SConscript`文件里边加上以下代码 ``` src += ['MCXA153/drivers/fsl_pwm.c'] ``` 在`Libraries/drivers/SConscript`文件里边加上以下代码 ``` if GetDepend('BSP_USING_PWM'): src += ['drv_pwm.c'] ``` ## 测试用例 打开menuconfig使能pwm0、pwm1、pwm2驱动,保存配置退出menuconfig ![flexPWM.png](https://oss-club.rt-thread.org/uploads/20241231/00bdfdbd5507ecc8d2e8500b9df3a9b0.png.webp) 导出MDK5工程 ``` scons --target=mdk5 ``` 使用pwm2生成频率1KHz占空比为5%的方波,最后编译并烧录到开发板上去 ```c #include
#include
#include
#include "board.h" #include
#define PWM_LED_DEV "pwm2" #define PWM_CHANNEL 0 int main(void) { struct rt_device_pwm *pwm_dev = RT_NULL; rt_uint32_t period, pulse; period = 1000000; pulse = 50000; pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM_LED_DEV); if (pwm_dev == RT_NULL) { rt_kprintf("pwm device (%s) not found!\n", PWM_LED_DEV); return RT_ERROR; } rt_pwm_enable(pwm_dev, PWM_CHANNEL); rt_pwm_set(pwm_dev, PWM_CHANNEL, period, pulse); while (1) { rt_thread_mdelay(1000); } return 0; } ``` ## 实验效果 使用逻辑分析仪测量P3_10引脚生成的波形,波形刚好频率为1KHz,占空比为5% ![eflexPWM实验.png](https://oss-club.rt-thread.org/uploads/20241231/9869500a926a5644980e56f5978da26c.png.webp) ## 总结 这个是NXP原生的PWM,BSP里边只移植了kPWM_PwmA对应的3个submodule通道
0
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
hywing
嵌入式系统开发工程师,从事物联网、工业自动化、汽车电子开发工作
文章
9
回答
3
被采纳
0
关注TA
发私信
相关文章
1
试贴-消灭0主题
2
LPC M4的一些资料
3
LPC4088的临时分支
4
lpc1788 ad 不稳定
5
1788 LCD控制器缓冲区字节问题
6
一起来学习LPC4088吧
7
上传LPC4088的realtouch主工程
8
RealBoard 4088预定帖 [第一批板子不多,预定提前结束]
9
晒RealBoard LPC4088开箱照啦,速带小板凳前来围观
10
4088主程序需要的SD卡资源
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
PWM
cubemx
freemodbus
flash
BSP
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
编译报错
Debug
rt_mq_消息队列_msg_queue
SFUD
keil_MDK
msh
ulog
MicroPython
C++_cpp
本月问答贡献
出出啊
1517
个答案
342
次被采纳
小小李sunny
1444
个答案
290
次被采纳
张世争
812
个答案
177
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
148
次被采纳
本月文章贡献
出出啊
1
篇文章
2
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
2
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部