RISCV_PWM使用参考


REVISION HISTORY

Revision No.
Description
Date
1.0
  • Initial release
  • 10/30/2022
    2.0
  •  Framework updates
  • 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_configdrv_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_configdrv_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