SylixOS的imx1050平台PWM捕获驱动
2018-05-14 14:08
435 查看
概述
本文档是对IMXRT1050平台上的SylixOS PWM波的产生和捕获功能的详细分析。代码在IMXRT1050的板级支持包的“bsp_rt1050/SylixOs/driver/pwm/”目录下的pwm.c文件中,该文件会依赖于bsp_rt1050/SylixOs/driver/lib目录,这个目录是NXP官方提供的库文件。
本文档描述的应用场景是这样的:PWM需要根据用户自己设置的参数,达到控制输出波形的频率和精确的周期个数,以达到控制3D打印机的目的。
PWM波的输出
IMXRT1050包含4个PWM模块,每个子模块有3路,PWM_A/PWM_B/PWM_X, 如图 2.1所示。暂时只关心PWM_A/PWM_B。
图 2.1 PWM子模块
可以想象PWM只要确定一个上升沿和一个下降沿的时刻就能确定一个周期,从而可以确定一个频率的波形。因此需要用到一个定时器和几个比较器。如图 2.2所示显示的是中心对齐的波形产生示意图。设置VAL2和VAL3寄存器,作为比较器的值,当计数器的值匹配VAL2,PWM_A会产生一个上升边沿,当计数器的值匹配VAL3,PWM_A会产生一个下降沿,这样循环下去,PWM_A就会产生一连串波形。PWM_B同样如此。
图 2.2 PWM波形产生
PWM的捕获
PWM同样可以设置为输入捕获功能。电路图如图 3.1所示。输入有两路,由INP_SEL控制。第一路直接输入捕获到电路,并可设置在输入波形的上升沿/下降沿/双边沿触发中断,在中断中可以关闭PWM用来实现控制输出波形周期数,第二路输入波形先经过一个8bit计数器,计数器记录输入波形双边沿个数,存储在EDGCNT里。可以设置期望比较值EDGCPM。比较器comparator比较EDGCNT和EDGCPM的值,当匹配时,reset边沿计数器的值,同时进入捕获电路。并可产生中断。第二路将很好的减少中断的次数,提高PWM的性能。捕获电路Circuit 0 Capture和Circuit 1 Capture将会交替工作。使能Arming Logic 将使捕获电路开始工作。
图 3.1输入捕获功能逻辑
代码编写
4.1 编码思路
PWM_A作为输出,PWM_B作为捕获输入。应用程序传两个参数,分别指定PWM_A输出波形的频率、PWM_B应该捕获的周期数。当PWM_B捕获到指定周期数,会触发中断处理函数,中断处理函数关闭PWM_A的输出波,这样就达到了控制输出周期的个数的目的。同时需要实现同步功能,即在中断函数中需要post一个信号量,告知pend的一方已经产生了指定个数的周期,并关闭了PWM_A。
综上所述,应该实现一下几个函数:
pwmConfig配置PWM输出功能
pwmCaptureInputConfig 配置捕获功能
pwmIsr 中断处理函数
PWM_StopTimer 停止PWM输出功能
PWM_StartTimer 打开PWM 输出功能
除了中断处理函数,其他函数都可以挂在字符驱动函数pwmIoctl中。
4.2 代码分析
4.2.1 初始化部分
程序清单 4.1
/
为pwm0创建同步信号量
/
_G_pwm[kPWM_Module_0].PWMC_CapSem = API_SemaphoreBCreate("pwm_sync",LW_FALSE,LW_OPTION_OBJECT_GLOBAL,LW_NULL);
if(LW_OBJECT_HANDLE_INVALID == _G_pwm[kPWM_Module_0].PWMC_CapSem)
{
PWM_DEBUG("Pwm API_SemaphoreBCreate Failed\n");
return (PX_ERROR);
}
PwmIRQ = PWM1_0_IRQn;
API_InterVectorSetPriority(BSP_IRQ_TO_VECTOR(PwmIRQ), LW_INTER_PRIO_LOWEST);
API_InterVectorConnect(BSP_IRQ_TO_VECTOR(PwmIRQ),(PINT_SVR_ROUTINE)__pwmIsr0,NULL,"pwm_isr0"); / 注册中断服务函数 /
API_InterVectorEnable(BSP_IRQ_TO_VECTOR(PwmIRQ));
4.2.2 __pwmIoctl
程序清单 4.2
static INT pwmIoctl (PLW_FD_ENTRY pFdEntry, INT iCmd, LONG lArg)
{
INT iRet;
INT iIrq;
PPWM_USER_CONFIG pPwmUserConfig;
PPWM_DUTY_CONFIG pPwmDutyConfig;
INT iModuleCtr;
PPWM_CAPTURE_CONFIG pCapParaCfg;
__PPWM_CONTROLER pPwmDev = (__PPWM_CONTROLER)pFdEntry->FDENTRY_pdevhdrHdr;
}
4.3 捕获配部分
程序清单 4.3
static INT __pwmCaptureInputConfig (PWM_Type *pBase, __PPWM_CAPTURE_CONFIG pPwmCaptureConfig)
{
uint32_t irq;
uint32_t status = 0;
PWM_SetupInputCapture(pBase, pPwmCaptureConfig->subModule, pPwmCaptureConfig->pwmChannel, pPwmCaptureConfig->inputCaptureParams);
status = PWM_GetStatusFlags(pBase, pPwmCaptureConfig->subModule);
}
4.4 中断部分
程序清单 4.4
static irqreturn_t __pwmIsr0(PVOID pvArg, ULONG ulVector)
{
uint32_t status = 0;
}
本文档是对IMXRT1050平台上的SylixOS PWM波的产生和捕获功能的详细分析。代码在IMXRT1050的板级支持包的“bsp_rt1050/SylixOs/driver/pwm/”目录下的pwm.c文件中,该文件会依赖于bsp_rt1050/SylixOs/driver/lib目录,这个目录是NXP官方提供的库文件。
本文档描述的应用场景是这样的:PWM需要根据用户自己设置的参数,达到控制输出波形的频率和精确的周期个数,以达到控制3D打印机的目的。
PWM波的输出
IMXRT1050包含4个PWM模块,每个子模块有3路,PWM_A/PWM_B/PWM_X, 如图 2.1所示。暂时只关心PWM_A/PWM_B。
图 2.1 PWM子模块
可以想象PWM只要确定一个上升沿和一个下降沿的时刻就能确定一个周期,从而可以确定一个频率的波形。因此需要用到一个定时器和几个比较器。如图 2.2所示显示的是中心对齐的波形产生示意图。设置VAL2和VAL3寄存器,作为比较器的值,当计数器的值匹配VAL2,PWM_A会产生一个上升边沿,当计数器的值匹配VAL3,PWM_A会产生一个下降沿,这样循环下去,PWM_A就会产生一连串波形。PWM_B同样如此。
图 2.2 PWM波形产生
PWM的捕获
PWM同样可以设置为输入捕获功能。电路图如图 3.1所示。输入有两路,由INP_SEL控制。第一路直接输入捕获到电路,并可设置在输入波形的上升沿/下降沿/双边沿触发中断,在中断中可以关闭PWM用来实现控制输出波形周期数,第二路输入波形先经过一个8bit计数器,计数器记录输入波形双边沿个数,存储在EDGCNT里。可以设置期望比较值EDGCPM。比较器comparator比较EDGCNT和EDGCPM的值,当匹配时,reset边沿计数器的值,同时进入捕获电路。并可产生中断。第二路将很好的减少中断的次数,提高PWM的性能。捕获电路Circuit 0 Capture和Circuit 1 Capture将会交替工作。使能Arming Logic 将使捕获电路开始工作。
图 3.1输入捕获功能逻辑
代码编写
4.1 编码思路
PWM_A作为输出,PWM_B作为捕获输入。应用程序传两个参数,分别指定PWM_A输出波形的频率、PWM_B应该捕获的周期数。当PWM_B捕获到指定周期数,会触发中断处理函数,中断处理函数关闭PWM_A的输出波,这样就达到了控制输出周期的个数的目的。同时需要实现同步功能,即在中断函数中需要post一个信号量,告知pend的一方已经产生了指定个数的周期,并关闭了PWM_A。
综上所述,应该实现一下几个函数:
pwmConfig配置PWM输出功能
pwmCaptureInputConfig 配置捕获功能
pwmIsr 中断处理函数
PWM_StopTimer 停止PWM输出功能
PWM_StartTimer 打开PWM 输出功能
除了中断处理函数,其他函数都可以挂在字符驱动函数pwmIoctl中。
4.2 代码分析
4.2.1 初始化部分
程序清单 4.1
/
为pwm0创建同步信号量
/
_G_pwm[kPWM_Module_0].PWMC_CapSem = API_SemaphoreBCreate("pwm_sync",LW_FALSE,LW_OPTION_OBJECT_GLOBAL,LW_NULL);
if(LW_OBJECT_HANDLE_INVALID == _G_pwm[kPWM_Module_0].PWMC_CapSem)
{
PWM_DEBUG("Pwm API_SemaphoreBCreate Failed\n");
return (PX_ERROR);
}
/* 初始化PWM0中断,用于pwm捕获 */
PwmIRQ = PWM1_0_IRQn;
API_InterVectorSetPriority(BSP_IRQ_TO_VECTOR(PwmIRQ), LW_INTER_PRIO_LOWEST);
API_InterVectorConnect(BSP_IRQ_TO_VECTOR(PwmIRQ),(PINT_SVR_ROUTINE)__pwmIsr0,NULL,"pwm_isr0"); / 注册中断服务函数 /
API_InterVectorEnable(BSP_IRQ_TO_VECTOR(PwmIRQ));
4.2.2 __pwmIoctl
程序清单 4.2
static INT pwmIoctl (PLW_FD_ENTRY pFdEntry, INT iCmd, LONG lArg)
{
INT iRet;
INT iIrq;
PPWM_USER_CONFIG pPwmUserConfig;
PPWM_DUTY_CONFIG pPwmDutyConfig;
INT iModuleCtr;
PPWM_CAPTURE_CONFIG pCapParaCfg;
__PPWM_CONTROLER pPwmDev = (__PPWM_CONTROLER)pFdEntry->FDENTRY_pdevhdrHdr;
switch (iCmd) { case PWM_MODE_SET: /* PWM 模式设置 */ pPwmUserConfig = (__PPWM_USER_CONFIG)lArg; if(LW_NULL == pPwmUserConfig) { return (PX_ERROR); } iRet = __pwmConfig(pPwmDev->PWMC_pBase, pPwmUserConfig); break; case PWM_STOP_SET: /* 停止 PWM */ iModuleCtr = (INT)lArg; if (iModuleCtr > kPWM_Control_Module_3 || iModuleCtr < kPWM_Control_Module_0) { PWM_DEBUG("larg error\r\n"); return PX_ERROR; } PWM_StopTimer(pPwmDev->PWMC_pBase, iModuleCtr); iRet = ERROR_NONE; break; case PWM_START_SET: /* 打开 PWM */ iModuleCtr = (INT)lArg; if (iModuleCtr > kPWM_Control_Module_3 || iModuleCtr < kPWM_Control_Module_0) { PWM_DEBUG("larg error\r\n"); return PX_ERROR; } PWM_StartTimer(pPwmDev->PWMC_pBase, iModuleCtr); iRet = ERROR_NONE; break; case PWM_INCAPT_SET: /* 捕获输入 */ pCapParaCfg = (__PPWM_CAPTURE_CONFIG)lArg; iRet = __pwmCaptureInputConfig(pPwmDev->PWMC_pBase,pCapParaCfg); break; case PWM_CAPT_WAITE: /*用于捕获同步*/ iRet = API_SemaphoreBPend(_G_pwm[kPWM_Module_0].PWMC_CapSem,LW_OPTION_WAIT_INFINITE); break; default: return (PX_ERROR); } return (iRet);
}
4.3 捕获配部分
程序清单 4.3
static INT __pwmCaptureInputConfig (PWM_Type *pBase, __PPWM_CAPTURE_CONFIG pPwmCaptureConfig)
{
uint32_t irq;
uint32_t status = 0;
PWM_SetupInputCapture(pBase, pPwmCaptureConfig->subModule, pPwmCaptureConfig->pwmChannel, pPwmCaptureConfig->inputCaptureParams);
status = PWM_GetStatusFlags(pBase, pPwmCaptureConfig->subModule);
/* 先清中断 */ if(status & (PWM_STS_CFB0_MASK)) { //bspDebugMsg("PWM_ClearStatusFlags>>>>>>\n"); PWM_ClearStatusFlags(pBase,pPwmCaptureConfig->subModule,status & (PWM_STS_CFB0_MASK)); } /* 中断的开启必须要在PWM_SetupInputCapture 配置之后,否则可能会出现配置没有完成就进入中断 */ irq = PWM_GetEnabledInterrupts(pBase, kPWM_Module_0); PWM_EnableInterrupts(pBase, kPWM_Module_0, (uint32_t)(irq | PWM_INTEN_CB0IE(1) |PWM_INTEN_CB1IE(1))); /* 使配置生效 */ PWM_SetPwmLdok(pBase, 1 << kPWM_Module_0, LW_TRUE); return (ERROR_NONE);
}
4.4 中断部分
程序清单 4.4
static irqreturn_t __pwmIsr0(PVOID pvArg, ULONG ulVector)
{
uint32_t status = 0;
status = PWM_GetStatusFlags(_G_pwm[kPWM_Module_0].PWMC_pBase, kPWM_Module_0); if(status & PWM_STS_CFB0_MASK) //clear int { PWM_ClearStatusFlags(_G_pwm[kPWM_Module_0].PWMC_pBase, kPWM_Module_0,status & PWM_STS_CFB0_MASK); PWM_StopTimer(_G_pwm[kPWM_Module_0].PWMC_pBase,1 << kPWM_Module_0); } if(status & PWM_STS_CFB1_MASK) //clear int { PWM_ClearStatusFlags(_G_pwm[kPWM_Module_0].PWMC_pBase, kPWM_Module_0,status & PWM_STS_CFB1_MASK); PWM_StopTimer(_G_pwm[kPWM_Module_0].PWMC_pBase,1 << kPWM_Module_0); //_DebugFormat(__PRINTMESSAGE_LEVEL, "2"); } API_SemaphoreBPost(_G_pwm[kPWM_Module_0].PWMC_CapSem); return (LW_IRQ_HANDLED);
}
相关文章推荐
- SylixOS基于Nuc970平台的SD驱动移植
- SylixOS 基于STM32平台的GPIO模仿I2C总线的驱动开发流程
- SylixOS NUC970平台SPI总线驱动移植
- SylixOS NUC970平台SPI总线驱动移植
- SylixOS基于Nuc970平台的SD驱动移植
- SylixOS 里NUC970平台上SPI总线驱动移植
- SylixOS iMX6平台I2C总线驱动
- SylixOS iMX6平台I2C总线驱动
- SylixOS 基于STM32平台的GPIO模仿I2C总线的驱动开发流程
- iMX6平台SylixOS I2C总线驱动开发
- SylixOS基于Nuc970平台的SD驱动移植
- SylixOS 基于STM32平台的GPIO模仿I2C总线的驱动开发流程
- 字符设备驱动、平台设备驱动、设备驱动模型、sysfs的比较和关联
- android系统平台显示驱动开发简要:Samsung LCD接口篇『三』
- ceph存储 字符设备驱动示例x86Linux平台
- 高通平台中用devicetree注册设备及驱动匹配
- Linux驱动基础:三星平台Linux SPI驱动
- platform_driver平台驱动注册和注销过程
- S3C2440裸机驱动--PWM基础
- 字符设备驱动之蜂鸣器与PWM——FS2410