树莓派PWM几乎可以用在每一个IO上,有8对,文档里写是16个CH,但其实是8对(但是并不互补,也没有死区功能.),对于传统单片机只会说自己是8个CH,不知道树莓派是怎么说自己16的... 感觉有点扯,另外B输入可以选择很多条,当选择多条时候是OR逻辑到芯片内部.

RP2040的PWM只有向上计数法和中心对齐,当比较值为0或最高时(等于比较值的最大),他可以输出0或者1且不变,由于双缓冲的存在,具有分频器,当在125MHz外设时钟时,可以取得实际频率范围从7.5 Hz ~ 125 MHz,另外B引脚可以用作PWM的启动信号,这就是前面说到的,为什么多个B输入会以OR方式输入到芯片内部,可以配置多种逻辑,上升沿/下降沿时触发一次或高电平连续输出PWM,这个操作也可以用来做占空比测量.
下面代码用于占空比测量,当然用GPIO等待法,毕竟有读取系统运行us的函数,所以也可以测出来.下面这个函数的原理是当B输入达到100个时钟周期,PWM计数+1,延迟10ms后,计算出1s的总周期数量counting_rate,得出10ms的总周期数量max_possible_count,然后取出pwm_get_counter数量,即是占空比比例,这个计算有局限性,比如B输入不是一个单蠢H->L或者L->H周期,而是H->L->H->.....->L这样交替,只能计算出其中的H的比例.
float measure_duty_cycle(uint gpio) {
// Only the PWM B pins can be used as inputs.
assert(pwm_gpio_to_channel(gpio) == PWM_CHAN_B);
uint slice_num = pwm_gpio_to_slice_num(gpio);
// Count once for every 100 cycles the PWM B input is high
pwm_config cfg = pwm_get_default_config();
pwm_config_set_clkdiv_mode(&cfg, PWM_DIV_B_HIGH);
pwm_config_set_clkdiv(&cfg, 100);
pwm_init(slice_num, &cfg, false);
gpio_set_function(gpio, GPIO_FUNC_PWM);
pwm_set_enabled(slice_num, true);
sleep_ms(10);
pwm_set_enabled(slice_num, false);
float counting_rate = clock_get_hz(clk_sys) / 100;
float max_possible_count = counting_rate * 0.01;
return pwm_get_counter(slice_num) / max_possible_count;
}
现在看到默认PWM例子,会占用stdio串口,看起来不太舒服,还是改掉他.
int main() {
///tag::setup_pwm[]
// Tell GPIO 0 and 1 they are allocated to the PWM
gpio_set_function(2, GPIO_FUNC_PWM);
gpio_set_function(3, GPIO_FUNC_PWM);
// Find out which PWM slice is connected to GPIO 0 (it's slice 0)
uint slice_num = pwm_gpio_to_slice_num(2);
pwm_config config = pwm_get_default_config();
pwm_config_set_clkdiv(&config, 4.f);
pwm_init(slice_num, &config, true);
// Set period of 4 cycles (0 to 3 inclusive)
pwm_set_wrap(slice_num, 4);
// Set channel A output high for one cycle before dropping
pwm_set_chan_level(slice_num, PWM_CHAN_A, 1);
// Set initial B output high for three cycles before dropping
pwm_set_chan_level(slice_num, PWM_CHAN_B, 3);
// Set the PWM running
pwm_set_enabled(slice_num, true);
///end::setup_pwm[]
// Note we could also use pwm_set_gpio_level(gpio, x) which looks up the
// correct slice and channel for a given GPIO.
}
最终结果:

可见,当到达比较时候会拉低,符合预期,计算频率6.25MHz是因为4分频后,PWM自身时钟为125/4=31.25MHz,然后设定周期是5,所以实际频率是31.25/5=6.25MHz,符合预期.另外的例子led_fade是使用板载的LED进行呼吸灯实验,占空比是在中断里修改的.
最后一点在例子中没写的就是pwm_config_set_phase_correct,如果开启之后,就从向上计数变成中心对齐模式.
总体来说,这个芯片的PWM功能也太基础了点,感觉做控制搞不定,是用来驱动舵机什么的吧.
按照逻辑分析仪中显示周期为5,但是代码中
pwm_set_wrap(slice_num, 4)
为4,这里是不是写错了?
@cl-ei 因为从0开始计数。
@TaterLi 哦没事了,看走眼了。官方例程是
pwm_set_wrap(slice_num, 3);
设置了4个周期,这里注释没有改,看的就绕进去了