RISCV_PWM使用参考
REVISION HISTORY¶
Revision No. | Description |
Date |
---|---|---|
1.0 | 10/30/2022 | |
2.0 | 05/05/2023 |
1. 概述¶
1.1. 概述¶
PWM (Pulse Width Modulation) 模块通过改变占空比来改变输出的电流、电压进而控制电机转速、液晶屏调光等,其硬件模块特征如下:
-
频率的工作范围是(OSCCLK/2)到(OSCCLK/2^34) ,例如OSCCLK = 12MHz,则范围是(0.0007Hz~6MHz);
-
支持的source clock的频率为:86M、24M、12M、6M、3M、1.5M、750K;
-
支持double buffer来防止产生错误波形,即波形更新会等待当前波形完全生成之后;
-
支持sync功能,即group内的PWM在同一个时刻产生波形,一般一组group中会包含4个channel的PWM;
-
支持round功能,即同group内的PWM会在产生特定数量的脉冲后停止;
-
支持hold功能,即同group内的PWM会在完成当前周期的波形后暂停,常用于改变波形的设定,可设定暂停时间内的高低电平;
-
支持stop功能,即同group内的PWM会紧急停止。
1.2. 频率和占空比¶
-
频率(frequency)
每秒钟信号从高电平到低电平再回到高电平的次数。
-
占空比(duty)
高电平持续时间和低电平持续时间之间的比例。
-
寄存器配置举例
假设PWM的source clock的频率为12M,可以设置的频率范围为:0.0007Hz~6MHz;
配置举例:PWM0和PWM1设定为频率120Hz,占空比25%的波形,且PWM1相对于PWM0有180°的相位偏移,相关的寄存器配置算法如下:
Period = (source clock) / frequency
Shift = period * (phase shift / 360)
Duty = Shift + (Period *(duty cycle)/100)
2.驱动配置¶
2.1. CONFIG配置¶
PWM相关的CONFIG:
CONFIG_SYSDESC_SUPPORT CONFIG_CAMCLK_SUPPORT CONFIG_PADMUX_SUPPORT CONFIG_GPIO_SUPPORT CONFIG_PWM_SUPPORT CONFIG_SSTAR_PWM_EXTEND
2.2.CONFIG_SYSDESC_SUPPORT¶
CONFIG_SYSDESC_SUPPORT=TRUE,PWM初始化配置选项在sc/driver/sysdriver/sysdesc/hal/pioneer5/pub/pioneer5-default.sys文件:
<pwm0> [reg_u32_u16] 0x2203200 0x37; [group_u32] 0; [camclk_u16] CAMCLK_pwm; [clk_level_u8] 0; [interrupts_u32] INT_IRQ_PWM; [status_u8] 0;
标签 | 描述 | 设定值 | 备注 |
---|---|---|---|
pwm0 | 匹配驱动初始化 | 下标为channel index | 禁止修改 |
reg_u32_u16 | 指定PWM寄存器bank的地址 | 详见DTS配置 | 禁止修改 |
group_u32 | 指定是否加入group | 详见DTS配置 | 可根据需要修改 |
camclk_u16 | 指定使用的时钟源 | 详见DTS配置 | 不需要更改 |
clk_level_u8 | 用于选择时钟挡位 | 0~6分别对应12M/6M/3M/1.5M/750K/86M/24M | 每个channel选择必须一致 |
interrupts_u32 | 指定使用的硬件中断号及属性 | 详见DTS配置 | 不需要修改 |
status_u8 | 选择是否使能PWM驱动 | 1:enable,0:disable | 可根据需要修改 |
CONFIG_SYSDESC_SUPPORT=FALSE,PWM初始化配置选项在sc/driver/sysdriver/pwm/hal/pioneer5/inc/hal_pwm_cfg.h文件:
struct hal_pwm_config pwm_cfg[HAL_PWM_CHANNEL] = { { // PWM0 ...... .enable = 1, //使能pwm0, 1:enable,0:disable .group = 0, //指定是否加入group .channel = 0, //pwm0,无需修改 .irq = INT_IRQ_PWM,//中断号,无需修改 }, ......
2.3.CONFIG_CAMCLK_SUPPORT¶
CONFIG_CAMCLK_SUPPORT=TRUE,clock的选择详见2.2.CONFIG_SYSDESC_SUPPORT 对clk_level_u8
的描述;
CONFIG_CAMCLK_SUPPORT=FALSE,clock的选择在sc/driver/sysdriver/pwm/hal/pioneer5/inc/hal_pwm_cfg.h文件:
struct hal_pwm_config pwm_cfg[HAL_PWM_CHANNEL] = { { // PWM0 ...... #ifdef CONFIG_CAMCLK_SUPPORT .camclk_id = CAMCLK_pwm, #else .clk_mod = 0, .clk_freq = 12000000, #endif ......
clk_mod | clk_freq/HZ | 对应Period范围 |
---|---|---|
0x0 | 12000000 | 0.0007HZ~6MHZ |
0x4 | 6000000 | 0.0004HZ~3MHZ |
0x8 | 3000000 | 0.0002HZ~1.5MHZ |
0xC | 1500000 | 0.00009HZ~750KHZ |
0x10 | 750000 | 0.00005HZ~375KHZ |
0x14 | 86000000 | 0.006HZ~43MHZ |
0x18 | 24000000 | 0.002HZ~12MHZ |
2.4. CONFIG_PADMUX_SUPPORT¶
CONFIG_PADMUX_SUPPORT=TRUE,PAD设定在sc/driver/sysdriver/sysdesc/hal/pioneer5/pub/pioneer5-default.sys文件,
在padmux节点中配置mode格式如下图的,<>
中第一个值为PAD值,第二个值为要设置的mode,第三个值为PAD在该mode下对应的功能,示例如下:
1. <padmux> 2. [schematic_u32_u32_u32] 3. PAD_PWM_OUT0 PINMUX_FOR_PWM_OUT0_MODE_1 MDRV_PUSE_PWM0, 4. PAD_PWM_OUT1 PINMUX_FOR_PWM_OUT1_MODE_1 MDRV_PUSE_PWM1, 5. PAD_PWM_OUT2 PINMUX_FOR_PWM_OUT2_MODE_1 MDRV_PUSE_PWM2, 6. PAD_PWM_OUT3 PINMUX_FOR_PWM_OUT3_MODE_1 MDRV_PUSE_PWM3, 7. PAD_FUART_RX PINMUX_FOR_PWM_OUT4_MODE_2 MDRV_PUSE_PWM4, 8. PAD_FUART_TX PINMUX_FOR_PWM_OUT5_MODE_2 MDRV_PUSE_PWM5, 9. PAD_FUART_RTS PINMUX_FOR_PWM_OUT6_MODE_2 MDRV_PUSE_PWM6, 10. PAD_FUART_CTS PINMUX_FOR_PWM_OUT7_MODE_2 MDRV_PUSE_PWM7, 11. PAD_EMMC_DS PINMUX_FOR_PWM_OUT8_MODE_2 MDRV_PUSE_PWM8, 12. PAD_EMMC_D4 PINMUX_FOR_PWM_OUT9_MODE_2 MDRV_PUSE_PWM9, 13. PAD_EMMC_D5 PINMUX_FOR_PWM_OUT10_MODE_2 MDRV_PUSE_PWM10, 14. PAD_EMMC_D6 PINMUX_FOR_PWM_OUT11_MODE_2 MDRV_PUSE_PWM11, 15. PAD_SAR_ADC_0 PINMUX_FOR_PWM_OUT12_MODE_1 MDRV_PUSE_PWM12, 16. PAD_SAR_ADC_1 PINMUX_FOR_PWM_OUT13_MODE_1 MDRV_PUSE_PWM13, 17. PAD_SAR_ADC_2 PINMUX_FOR_PWM_OUT14_MODE_1 MDRV_PUSE_PWM14, 18. PAD_SAR_ADC_3 PINMUX_FOR_PWM_OUT15_MODE_1 MDRV_PUSE_PWM15, 19. PAD_SAR_ADC_4 PINMUX_FOR_PWM_OUT16_MODE_1 MDRV_PUSE_PWM16, 20. PAD_SAR_ADC_5 PINMUX_FOR_PWM_OUT17_MODE_1 MDRV_PUSE_PWM17, 21. PAD_SAR_ADC_6 PINMUX_FOR_PWM_OUT18_MODE_1 MDRV_PUSE_PWM18, 22. PAD_SAR_ADC_7 PINMUX_FOR_PWM_OUT19_MODE_1 MDRV_PUSE_PWM19,
CONFIG_PADMUX_SUPPORT=FALSE,PAD设定在sc/driver/sysdriver/pwm/hal/pioneer5/inc/hal_pwm_cfg.h文件:
struct hal_pwm_config pwm_cfg[HAL_PWM_CHANNEL] = { { // PWM0 ...... #ifdef CONFIG_GPIO_SUPPORT .pad_mod = PINMUX_FOR_PWM_OUT0_MODE_1, //CONFIG_GPIO_SUPPORT=TRUE #else .pad_mod = 1, //CONFIG_GPIO_SUPPORT=FALSE #endif ......
2.5. CONFIG_PWM_SUPPORT¶
CONFIG_PWM_SUPPORT=TRUE编译PWM driver, 路径为/sc/driver/sysdriver/pwm;
CONFIG_SSTAR_PWM_EXTEND=FALSE,普通精度模式,可以配置pwm周期与占空比的精度相对较低,period的单位为Hz,duty的单位为百分比,只能设置整数,如peiod=100HZ;
CONFIG_SSTAR_PWM_EXTEND=TRUE,高精度模式,可以配置pwm周期与占空比的精度相对较高,配置方法与普通精度也不同,这种模式下配置PWM的period和duty_cycle使用纳秒为单位,所以要先计算周期和占空比的值。
假设要设置PWM0频率为10.5KHZ占空比为50%,则: period = 10^9^ ÷ 10500 = 95238 duty cycle = 1/2 × 95238/2= 47619
3. API使用说明¶
参考sc/driver/sysdriver/pwm/drv/pub/drv_pwm.h文件:
struct pwm_ch_cfg { u8 polar; u32 channel; u64 duty; u64 shift; u64 period; }; struct pwm_gp_cfg { u8 polar; u32 group; u64 duty; u64 shift; u64 period; }; extern int drv_pwm_channel_config(struct pwm_ch_cfg * pwm_ch); extern int drv_pwm_channel_enable(u32 channel, u8 enable); extern int drv_pwm_group_config(struct pwm_gp_cfg *pwm_gp); extern int drv_pwm_group_enable(u32 group, u8 enable); extern void drv_pwm_stop_enable(u32 group, u8 stop_en); extern int drv_pwm_round_enable(u32 group, u32 round_num); extern int drv_pwm_update_enable(u32 grou);
3.1. channel属性设定¶
struct pwm_ch_cfg
的成员只要是设定单个channel的属性,对应使用的API为drv_pwm_channel_config
, drv_pwm_channel_enable
,使用举例:
struct pwm_ch_cfg pwm_ch; #高精度模式设定pwm0输出100.5HZ,占空比50%的波形 pwm_ch.channel = 0; pwm_ch.period = 9950248; // 计算方式为10^9 / 100.5 pwm_ch.shift = 0; //duty和shift的差值决定最终的波形占空比 pwm_ch.duty = 4975124; //计算方式为10^9 / 100.5 * 50% pwm_ch.polar = 0; //极性为normal ret = drv_pwm_channel_config(&pwm_ch); if(ret) return -1; ret =drv_pwm_channel_enable(channel, 1); if(ret) return -1; #普通精度模式设定pwm0输出100HZ,占空比50%的波形 pwm_ch.channel = 0; pwm_ch.period = 100; pwm_ch.shift = 0; pwm_ch.duty = 50; pwm_ch.polar = 0; ret = drv_pwm_channel_config(&pwm_ch); if(ret) return -1; ret =drv_pwm_channel_enable(pwm_ch.channel, 1); if(ret) return -1;
3.2. Group相关概念¶
3.2.1. Sync mode¶
sync mode可以将每个pwm channel加入到group群组中,完成同时对多个PWM进行控制的目的,正常一个group有4个pwm channel,且对应关系如下:
Group | Group Member |
---|---|
Group0 | PWM0、PWM1、PWM2、PWM3 |
Group1 | PWM4、PWM5、PWM6、PWM7 |
Group2 | PWM8、PWM9、PWM10、PWM11 |
Group3 | PWM12、PWM13、PWM14、PWM15 |
Group4 | PWM16、PWM17、PWM18、PWM19 |
P5 Group0也支持控制8个pwm channel:
Group | Group Member |
---|---|
Group0 | PWM0、PWM1、PWM2、PWM3、PWM4、PWM5、PWM6、PWM7 |
Group2 | PWM8、PWM9、PWM10、PWM11 |
Group3 | PWM12、PWM13、PWM14、PWM15 |
Group4 | PWM16、PWM17、PWM18、PWM19 |
决定各个channel是否加入Group的方法详见2.2.CONFIG_SYSDESC_SUPPORT
。
struct pwm_gp_cfg
的成员可以设定整个group内所有channel的属性,对应使用的API为drv_pwm_group_config
, drv_pwm_group_enable
,使用举例:
struct pwm_gp_cfg pwm_gp; #高精度模式设定group0所有pwm channel输出100.5HZ,占空比50%的波形 pwm_gp.group= 0; pwm_gp.period = 9950248; // 计算方式为10^9 / 100.5 pwm_gp.shift = 0; //duty和shift的差值决定最终的波形占空比 pwm_gp.duty = 4975124; //计算方式为10^9 / 100.5 * 50% pwm_gp.polar = 0; //极性为normal ret = drv_pwm_group_config(&pwm_gp); if(ret) return -1; ret =drv_pwm_group_enable(pwm_gp.group, 1); if(ret) return -1; ret = drv_pwm_update_enable(pwm_gp.group);//group的设定需要update才生效 if(ret) return -1; #低精度模式设定group0所有pwm channel输出100HZ,占空比50%的波形 pwm_gp.group= 0; pwm_gp.period = 100; pwm_gp.shift = 0; pwm_gp.duty = 50; pwm_gp.polar = 0; ret = drv_pwm_group_config(&pwm_gp); if(ret) return -1; ret =drv_pwm_group_enable(pwm_gp.group, 1); if(ret) return -1; ret = drv_pwm_update_enable(pwm_gp.group); if(ret) return -1;
3.2.2 Hold mode¶
Group的Hold功能会在pwm完成当前周期的波形后停止,并触发中断,此时可以改变各channel波形的配置以保持同步,完成修改后会关闭hold 功能,pwm就会重新产生新的波形,每组group都有自己独立的hold功能 。
hold功能对应的API为drv_pwm_update_enable
,使用时机为更新group相关参数设定时
struct pwm_gp_cfg pwm_gp; #高精度模式设定group0所有pwm channel输出100.5HZ,占空比50%的波形 pwm_gp.group= 0; pwm_gp.period = 9950248; // 计算方式为10^9 / 100.5 pwm_gp.shift = 0; //duty和shift的差值决定最终的波形占空比 pwm_gp.duty = 4975124; //计算方式为10^9 / 100.5 * 50% pwm_gp.polar = 0; //极性为normal ret = drv_pwm_group_config(&pwm_gp); if(ret) return -1; ret =drv_pwm_group_enable(pwm_gp.group, 1); if(ret) return -1; ret = drv_pwm_update_enable(pwm_gp.group);//group的设定需要update才生效 if(ret) return -1; #在上述基础上,更新group0所有pwm channel输出200.5HZ, 占空比50%的波形 pwm_gp.period = 4987532;// 计算方式为10^9 / 200.5 ret = drv_pwm_update_enable(pwm_gp.group); if(ret) return -1;
3.2.3.Round mode¶
round功能会在同group内的所有channel完成一定数量的脉冲后停止,每组group都有自己独立的round功能。
round功能对应的API为drv_pwm_round_enable
struct pwm_gp_cfg pwm_gp; #高精度模式设定group0所有pwm channel输出100.5HZ,占空比50%的波形 pwm_gp.group= 0; pwm_gp.period = 9950248; // 计算方式为10^9 / 100.5 pwm_gp.shift = 0; //duty和shift的差值决定最终的波形占空比 pwm_gp.duty = 4975124; //计算方式为10^9 / 100.5 * 50% pwm_gp.polar = 0; //极性为normal ret = drv_pwm_group_config(&pwm_gp); if(ret) return -1; ret =drv_pwm_group_enable(pwm_gp.group, 1); if(ret) return -1; ret = drv_pwm_update_enable(pwm_gp.group); if(ret) return -1; #在上述基础上触发100个脉冲 ret =drv_pwm_round_enable(pwm_gp.group, 100); if(ret) return -1;
3.2.4.Stop mode¶
stop功能可以让当前group中的PWM立即停止(不会等当前周期完成)并维持结束时的电平,每组group都有自己独立的stop功能。
stop功能对应的API为drv_pwm_stop_enable
struct pwm_gp_cfg pwm_gp; #高精度模式设定group0所有pwm channel输出100.5HZ,占空比50%的波形 pwm_gp.group= 0; pwm_gp.period = 9950248; // 计算方式为10^9 / 100.5 pwm_gp.shift = 0; //duty和shift的差值决定最终的波形占空比 pwm_gp.duty = 4975124; //计算方式为10^9 / 100.5 * 50% pwm_gp.polar = 0; //极性为normal ret = drv_pwm_group_config(&pwm_gp); if(ret) return -1; ret =drv_pwm_group_enable(pwm_gp.group, 1); if(ret) return -1; ret = drv_pwm_update_enable(pwm_gp.group); if(ret) return -1; #紧急停止波形 drv_pwm_stop_enable(pwm_gp.group, 1); #恢复波形 drv_pwm_stop_enable(pwm_gp.group, 0);
4. Demo路径¶
rtk/proj/sc/driver/sysdriver/pwm/drv/src/drv_pwm_test.c