6.1.4.Drv/PWM(Character Device Drv)

本文详细解析了Nuttx操作系统中PWM驱动的实现原理,从启动流程到数据结构,包括stm32_pwmtimer_s、pwm_ops_s及pwm_lowerhalf_s等关键组件的作用与交互。

转载请注明出处:http://blog.youkuaiyun.com/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_PULSECOUNT
static int pwm_start(FAR struct pwm_lowerhalf_s *dev,
  FAR const struct pwm_info_s *info,
  FAR void *handle);
#else
static int pwm_start(FAR struct pwm_lowerhalf_s *dev,
  FAR const struct pwm_info_s *info);
#endif

static 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驱动的一致性而设立的变量,目的是让驱动结构的一致性和可读性更强。

<think>好的,我现在需要帮用户解决Java SpringBoot项目中遇到的类文件版本错误的问题,具体是关于GetMapping注解的错误提示:“类文件具有错误的版本61.0,应为52.0”。首先,我得理解这个问题出现的原因。 根据用户提供的引用内容,特别是引用[1]和引用[3],错误信息显示类文件的版本不兼容。Java的类文件版本对应着不同的JDK版本,版本61.0对应的是JDK 17,而52.0对应的是JDK 8。这说明用户的项目可能使用了较高版本的JDK编译的依赖,而实际运行时使用的是较低版本的JDK。比如,Spring Boot可能用了JDK 17编译,但用户的环境是JDK 8,导致不兼容。 接下来,我需要考虑解决方案。根据引用[3]的建议,用户需要检查Spring Boot的版本是否与JDK版本匹配。如果用户的项目使用的是Spring Boot 3.x,它需要JDK 17或更高版本,而Spring Boot 2.x则兼容JDK 8。所以,用户可能需要降级Spring Boot版本到2.x,或者升级JDK到17及以上。 另外,用户需要确认项目中的JDK配置是否正确。包括检查IDE中的项目SDK设置、Maven或Gradle的编译器插件配置,确保编译版本和目标版本与使用的JDK一致。例如,Maven的maven-compiler-plugin应该设置为对应的Java版本。 用户提到的错误中涉及GetMapping,这是Spring Web的注解,属于Spring Boot Starter Web的一部分。如果Spring Boot版本过高,而JDK版本过低,就会导致这个问题。因此,调整依赖版本和JDK版本是关键步骤。 可能还需要检查构建工具中的依赖管理,确保所有Spring Boot相关的依赖版本一致,避免部分依赖使用了高版本而其他部分使用低版本,造成冲突。 最后,用户可能需要清理并重新构建项目,确保所有类文件都是使用正确的JDK版本生成的。例如,在Maven中使用clean install命令,或者在IDE中执行Clean and Rebuild操作。 总结一下,解决方案的步骤应该是:1. 确认JDK版本;2. 调整Spring Boot版本;3. 配置构建工具;4. 清理和重建项目。同时,需要引导用户检查各个配置点,确保版本一致。</think>### 问题分析:Java SpringBoot项目出现`GetMapping`类文件版本错误 错误信息`类文件具有错误的版本 61.0, 应为 52.0`表明**Java版本不兼容**: - 类文件版本`61.0`对应JDK 17,而`52.0`对应JDK 8[^1][^3] - Spring Boot 3.x及以上版本需要**JDK 17+**,而旧版本(如Spring Boot 2.x)支持JDK 8[^4] --- ### 解决方案步骤 1. **检查JDK版本** - 命令行输入`java -version`确认当前JDK版本 - 若版本为JDK 8,需升级到**JDK 17**或降级Spring Boot到**2.x版本** 2. **调整Spring Boot版本** - 在`pom.xml`中修改Spring Boot版本(例如使用兼容JDK 8的版本): ```xml <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.18</version> <!-- 支持JDK 8的版本 --> </parent> ``` 3. **检查构建工具配置** - Maven项目需确认编译器插件配置: ```xml <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <!-- 与JDK版本一致 --> <target>1.8</target> </configuration> </plugin> ``` 4. **清理并重新构建项目** - 执行`mvn clean install`或IDE的**Clean and Rebuild**操作 - 删除`target`目录或`build`文件夹以清除旧版本编译文件 --- ### 验证是否解决 - 重新启动Spring Boot应用,若不再报错且能正常访问`@GetMapping`接口则修复成功[^4] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值