在嵌入式系统开发中,PWM(脉冲宽度调制)是实现电机控制、LED调光等功能的常用外设。本文将详细介绍如何在Zephyr RTOS中为自研的芯片开发定制化的PWM驱动,重点展示其精简高效的驱动架构设计。(仅保留PWM方波输出功能)
保留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; // 复位控制
};
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)
----
};
说明:
int get_prescaler_value(enum pwm_prescal_e prescaler) {
switch (prescaler) {
case PWM_PRESCAL_120: return 120;
// ... 其他分频值
default: return -1;
}
}
说明:
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;
}
说明:
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;
}
说明:
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;
}
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);
}
}
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);
}
这种寄存器级的精准裁剪使驱动在保持精简代码的同时,能够充分发挥硬件性能,为高要求的PWM应用场景提供了可靠基础。开发者可根据此设计思路,灵活适配其他芯片的PWM驱动开发。