【Zephyr开发实践系列】04_精准裁剪的PWM外设驱动开发

文章目录

  • 前言
  • 一、PWM驱动模型
      • 1.1 核心应用API(必须)
      • 1.2 设置数据结构
      • 1.3 硬件初始化
      • 1.4 设备实例化
  • 二、数据结构定义
      • 2.1 普通PWM模式结构体
      • 2.2 预分频枚举
  • 三、核心功能实现
      • 3.1 分频系数映射(get_prescaler_value)
      • 3.2 周期设置(set_cycles)
      • 3.3 频率获取(get_cycles_per_sec)
      • 3.4 初始化(pwm_init)
  • 四、HAL层寄存器操作说明
      • 4.1 数据抽象层初始化
      • 4.2 周期配置
      • 4.3 通道控制与使能
  • 总结


前言

在嵌入式系统开发中,PWM(脉冲宽度调制)是实现电机控制、LED调光等功能的常用外设。本文将详细介绍如何在Zephyr RTOS中为自研的芯片开发定制化的PWM驱动,重点展示其精简高效的驱动架构设计。(仅保留PWM方波输出功能)

一、PWM驱动模型

保留PWM方波输出功能的驱动模型包括以下几个要点:

1.1 核心应用API(必须)

  • set_cycles:设置PWM周期和脉冲宽度的核心函数
  • get_cycles_per_sec: 获取PWM时钟频率,用于周期计算

1.2 设置数据结构

  • 配置结构: 只保留寄存器基地址、时钟频率/设备、复位信息
  • 驱动API结构: 只包含上述两个函数指针
  • 运行时数据: 可以完全省略,或只保留必要的状态信息

1.3 硬件初始化

  • 时钟使能: 确保PWM模块时钟开启
  • 复位操作: 将PWM模块复位到初始状态
  • 基本寄存器配置: 设置工作模式为PWM输出模式

1.4 设备实例化

  • 配置结构初始化: 从设备树提取基本配置
  • 设备注册宏: 使用DEVICE_DT_INST_DEFINE注册设备
  • 初始化优先级: 设置为POST_KERNEL

二、数据结构定义

2.1 普通PWM模式结构体

struct pwm_xx_config {
    PWM_TypeDef *pwm;                  // PWM寄存器基地址
    enum pwm_prescal_e prescaler;      // 分频系数
    struct x_pclken *pclken;      // 时钟使能配置
    const struct device *clock_dev;    // 时钟设备
    const struct reset_dt_spec reset;  // 复位控制
};

2.2 预分频枚举

enum pwm_prescal_e {
    PWM_PRESCAL_120 = 0x0, //24MHz/120 = 200KHz (t=5us)
    PWM_PRESCAL_180 = 0x1, //24MHz/180 = 133KHz (t=7.5us)
    PWM_PRESCAL_240 = 0x2, //24MHz/240 = 100KHz (t=10us)
    PWM_PRESCAL_360 = 0x3, //24MHz/360 = 66KHz (t=15us)
    PWM_PRESCAL_480 = 0x4, //24MHz/480 = 50KHz (t=20us)
    ----
    };

三、核心功能实现

3.1 分频系数映射(get_prescaler_value)

说明:

  • 根据分频系数枚举值获取分频系数,支持从枚举值到数值的转换
  • 用于计算pwm的实际工作频率
int get_prescaler_value(enum pwm_prescal_e prescaler) {
    switch (prescaler) {
        case PWM_PRESCAL_120: return 120;
        // ... 其他分频值
        default: return -1;
    }
}

3.2 周期设置(set_cycles)

说明:

  • channel: PWM 通道号
  • period_cycles: PWM 周期(以时钟周期为单位)
  • pulse_cycles: 高电平持续时间(以时钟周期为单位)
  • flags: PWM 标志位,包含极性信息
static int pwm_set_cycles(const struct device *dev, uint32_t channel,
                uint32_t period_cycles, uint32_t pulse_cycles,
                pwm_flags_t flags)
{
    hal_pwm_ch_config(channel, period_cycles, pulse_cycles, 
                     ~(flags & PWM_POLARITY_INVERTED));
    return 0;
}

3.3 频率获取(get_cycles_per_sec)

说明:

  • 周期数 = PWM时钟频率 / 分频器值
    实现步骤:
  • 通过时钟控制子系统获取 PWM 时钟频率
  • 获取指定通道的分频器值
  • 计算并返回每秒的时钟周期数
static int pwm_get_cycles_per_sec(const struct device *dev,
                uint32_t channel, uint64_t *cycles)
{
    // 获取时钟频率并计算实际周期
    *cycles = pwm_clk / get_prescaler_value(hal_get_ch_prescaler(channel));
    return 0;
}

3.4 初始化(pwm_init)

说明:

  • 设备检查
  • 复位时钟与时钟配置
  • hal层初始化
static int pwm_init(const struct device *dev)
{
    // 1. 复位和时钟配置
    reset_line_toggle_dt(&config->reset);
    clock_control_configure(...);
    clock_control_on(...);
    
    // 3. HAL层初始化
    hal_pwm_module_init();
    
    // 4. 配置各通道分频器
    for (size_t i = 0; i < PWM_CH_NUM; i++) {
        hal_pwm_ch_perscal_config(i, config->prescaler);
    }
    
    return 0;
}

四、HAL层寄存器操作说明

4.1 数据抽象层初始化

  • 对数据结构体完成关键地址映射
void hal_pwm_module_init(void)
{
    // 中断寄存器基地址映射
    uPwmHdl.PwmInt = PWM_INT; 
    
    // 组寄存器地址计算 (0x10间隔,每组4字节)
    for(int i=0; i<PWM_GROUP_NUM; i++){
        uPwmHdl.PwmGroup[i] = (PWM_Group_TypeDef*)(PWM_BASE+0x10+0x04*i);
    }
    
    // 通道寄存器地址计算 (0x20间隔,每个通道32字节)
    for(int i=0; i<PWM_CH_NUM; i++){
        uPwmHdl.PwmCH[i] = (PWM_TypeDef*)(PWM_BASE+0x20+0x20*i);
    }
}

4.2 周期配置

  • entire:整周期计数
  • active: 有效计数
void hal_pwm_per_config(PWM_TypeDef* hpwmch, uint16_t entire, uint16_t active)
{
    // 组合周期参数到32位寄存器
    uint32_t per_val = (entire<<16) | active;
    
    // 直接寄存器写入
    hpwmch->PER = per_val;
    
    // 等待配置生效
    while(hpwmch->CTRL & PWM_CTRL_PERIOD_READY);
}

4.3 通道控制与使能

  • 分频器控制
  • 通道使能

总结

这种寄存器级的精准裁剪使驱动在保持精简代码的同时,能够充分发挥硬件性能,为高要求的PWM应用场景提供了可靠基础。开发者可根据此设计思路,灵活适配其他芯片的PWM驱动开发。

你可能感兴趣的:(Zephyr实践开发,驱动开发,单片机,嵌入式硬件,物联网,mcu)