6.1.4.Drv/PWM(Character Device Drv)
来源:互联网 发布:java两年经验工资多少 编辑:程序博客网 时间:2024/06/14 10:43
转载请注明出处:http://blog.csdn.net/alvin_jack/article/details/70665462
文章均出自个人理解,错误之处敬请指出;
前言
上篇1.1Drv/Character Device Drv(字符型驱动设备)的叙述方式感觉没有逻辑性,只是从框架的角度进行了阐述,这篇换个思路,从调用顺序上来描述PWM驱动设备的实现原理;
基础知识
在ARM单片机中,PWM实际实现机制就是通过TIMER定时器来实现的,不管是调频还是脉宽,核心的思想就是通过一个计数器和两个寄存器(计算频率/调节脉宽),我之前遇到过有把PWM单独拿出来作为外设模块的MCU(例如飞思卡尔的),也有归类到定时器下的(例如意法半导体的),不管怎么算,核心的思想是不会变的,所以这次就从意法的mcu出发来叙述Nuttx下的PWM驱动的实现原理。
启动流程
Nuttx的启动就不再详细叙述,有空再写篇关于Nuttx启动详细讲解文章,这里从PWM的入口驱动开始讲解,也就是在config/stm32f103-minimum/src/stm32_appinit.c文件中board_app_initialize()函数;
board_app_initialize-- #板载应用初始化 | v stm32_bringup()------ #逐个启动板载应用 | v stm32_pwm_setup()---- #执行pwm初始化 | v stm32_pwminitialize(STM32F103MINIMUM_PWMTIMER)--- #初始化指定的TIMx pwm_register("/dev/pwm0", pwm)--- #注册PWM驱动到内核文件按系统 ..... #初始化其他板载应用 .....
其实咋一看流程非常清晰,几乎和写单片机程序没什么两样,但是越是看起来简单的东西实际实现起来就越不简单;
stm32_pwminitialize(STM32F103MINIMUM_PWMTIMER)
Nuttx中的驱动是类linux的,和上一篇讲到的串口一样也是需要一些特定的文件结构(我们尝试着以字符型驱动去理解分析试试);
在开始之前首先分析下层级关系,在PWM的驱动中也存在和串口(uart_dev_s、uart_ops_s)类似的数据结构(stm32_pwmtimer_s、pwm_ops_s),说明Nuttx的套路是一样的,我们的估计没有错,对上的接口都是*_dev_s和*_ops_s两种数据接口;现在先分析流程,后面来分析数据结构;
stm32_pwminitialize(int timer)-- #stm32pwm初始化,形参为指定定时器通道(硬件层面) | v stm32_pwmtimer_s *lower = &g_pwm3dev; #此处的g_pwm3dev,就是定义的*_dev_s(硬件有多少就定义多少) | v pwm_register("/dev/pwm0", pwm); #将获得的*_dev_s注册到系统(pwm就是g_pwm3dev)
好像和上面的有点重复 --!,这里主要是要分析stm32_pwmtimer_s、pwm_ops_s、pwm_lowerhalf_s三个数据结构,好像和uart的驱动有点区别了;
stm32_pwmtimer_s
这个结构体主要是描述驱动的主要模块,板卡的所有PWM驱动模块都是被封装成这样的结构体变量的;所处的路径是:
nuttx/arch/arm/src/stm32/stm32_pwm.c中,这个文件貌是是所有stm32公用的(不然怎么这么多定时器);
static struct stm32_pwmtimer_s g_pwm1dev;static struct stm32_pwmtimer_s g_pwm2dev;...static struct stm32_pwmtimer_s g_pwm16dev;static struct stm32_pwmtimer_s g_pwm17dev;static struct stm32_pwmtimer_s g_pwm1dev ={ .ops = &g_pwmops, #ops结构,老熟人了 .timid = 1, #用的硬件Timer1就填1 .channels = #通道数据结构 {#ifdef CONFIG_STM32_TIM1_CHANNEL1 { .channel = 1, #用的通道1就填1 .pincfg = PWM_TIM1_CH1CFG, #映射实际的GPIO .mode = CONFIG_STM32_TIM1_CH1MODE, #PWM通道的工作模式(频率/脉宽) },#endif...#这里还有很多个通道,分析结构就先省略掉 .timtype = TIMTYPE_TIM1, #定时器的工作模式(向上计数/向下计数...) .mode = CONFIG_STM32_TIM1_MODE,#ifdef CONFIG_PWM_PULSECOUNT .irq = STM32_IRQ_TIM1UP, #计数中断#endif .base = STM32_TIM1_BASE, #stm32定时器的基地址,也是老熟人了 .pclk = TIMCLK_TIM1, #stm32定时器的时钟分频系数};
其实这么一看,和uart的dev比起来,pwm简单太多了;
pwm_ops_s
这个数据结构应该也是用来操作timer寄存器组的结构体了,
所处的路径是:
nuttx/arch/arm/src/stm32/stm32_pwm.c中,这个结构体也是多个dev公用的,全文也只是定义了一个;
static const struct pwm_ops_s g_pwmops ={ .setup = pwm_setup, #pwm初始设置 .shutdown = pwm_shutdown, # .start = pwm_start, # .stop = pwm_stop, # .ioctl = pwm_ioctl, #};static int pwm_setup(FAR struct pwm_lowerhalf_s *dev);static int pwm_shutdown(FAR struct pwm_lowerhalf_s *dev);#ifdef CONFIG_PWM_PULSECOUNTstatic int pwm_start(FAR struct pwm_lowerhalf_s *dev, FAR const struct pwm_info_s *info, FAR void *handle);#elsestatic int pwm_start(FAR struct pwm_lowerhalf_s *dev, FAR const struct pwm_info_s *info);#endifstatic int pwm_stop(FAR struct pwm_lowerhalf_s *dev);static int pwm_ioctl(FAR struct pwm_lowerhalf_s *dev, int cmd, unsigned long arg);
毫无疑问,ops都会使用到dev的数据结构,但是pwm这里面偏偏要搞一个pwm_lowerhalf_s这个数据结构,不知道干啥的,但会儿收拾ta;简单来说ops就是之前用来写裸机配置单片机外设那一套,只是把所有配置参数都封装在了中,配置方法封装在了ops中;所以具体的方法就不分析了,具体问题具体解决吧;
pwm_lowerhalf_s
所处的路径:nuttx/include/nuttx/drivers/pwm.h
/* This structure is a set a callback functions used to call from the upper- * half, generic PWM driver into lower-half, platform-specific logic that * supports the low-level timer outputs. */struct pwm_lowerhalf_s;
说出来你可能不信,这货是个空的结构体,大概表达的意思是说,上半部分调用的回调函数可以通过这个结构进入PWM驱动器的下半部分,平台专用逻辑,支持低电平定时器输出。按这么说,就是个傀儡呗...为了验证这一说法,我们截取一段ops的代码来佐证:
static int pwm_start(FAR struct pwm_lowerhalf_s *dev, FAR const struct pwm_info_s *info){ int ret = OK; FAR struct stm32_pwmtimer_s *priv = (FAR struct stm32_pwmtimer_s *)dev;......... return ret;}
明显可以看出来,在ops实际使用的情况,是强行转换为了stm32_pwmtimer_s,也就是说pwm_lowerhalf_s是为整个os驱动的一致性而设立的变量,目的是让驱动结构的一致性和可读性更强。
0 0
- 6.1.4.Drv/PWM(Character Device Drv)
- 6.1.1Drv/Serial(Character Device Drv)
- 6.3.3Drv/I2C(Specialized Device Drivers)
- Drv总结
- IPCAM?还是DRV?
- xorg-x11-drv-vmware
- experiment : thread on drv
- drv experiment : FOLLOW_JMP parse
- GD25Q32C FLASH DRV
- experiment : 字符串分解 on drv
- int platform_driver_register(struct platform_driver *drv)
- int driver_register(struct device_driver *drv)
- int uart_register_driver(struct uart_driver *drv)
- alg : 单向链表逆序 on drv
- alg : 单向链表排序 on drv
- src/hwif和src/drv的区别
- linux 内核专题— drv术语
- DDI DEV DRV 之间的关系
- 跨域详解
- Java正则表达式
- Windows终端颜色设置
- CSU 1903: Tricky数
- 51nod 1091 线段重叠
- 6.1.4.Drv/PWM(Character Device Drv)
- HDU---1829 A Bug's Life【并查集】
- 面试14之请实现一种数据结构SetOfStacks
- Js选择框脚本 移动操作select 标签中的 option 项的操作事项
- Linux——分区时出现This partition should be marked for use as an "EFI boot partition"
- 多频段融合方法——图像拼接
- Android与h5交互
- 【Eclipse】安装Eclipse Color Theme 插件
- struts2_json