RISVC_SPWM USER GUIDE


REVISION HISTORY

Revision No.
Description
Date
1.0
  • Initial release
  • 09/06/2024
    1.1
  • Adjust the directory hierarchy and improve FAQ description
  • 04/14/2025

    1. OVERVIEW

    SPWM (Sinusoidal Pulse Width Modulation) is a pulse width modulation technology commonly used in AC motor drive and inverter control. It achieves precise control of AC motor speed and power by converting DC voltage into AC voltage close to a sine waveform.

    SPWM technology is based on the PWM (Pulse Width Modulation) principle, but unlike traditional square wave PWM, it uses a series of narrow pulses to simulate a sine waveform. The pulse width and frequency of these narrow pulses can be reasonably adjusted to produce an output close to a sine wave.

    1.1. Modulation Process

    Taking the carrier frequency as 8 times the sine wave frequency (i.e., modulation index = 8) as an example, the modulation process can be explained as follows:

    The sine wave is divided into eight equal segments and each segment is marked with a number <1> to <8>;

    According to the principle of equal area in automatic control, the duty cycle of the square wave (the red highlighted part) is adjusted so that its area matches the area under the sine wave (the blue highlighted part) in each interval. For example, as shown in the interval <1> in the figure, the control effect on the motor is equivalent.

    In this way, we can achieve the same control effect as a sine wave by using a series of square waves.

    1.2. Motor Control

    Take a two-phase and four-wire motor as an example, there are four terminals: A-, A+, B- and B+. A- and A+ combine to form a sine wave for phase A, while B- and B+ combine to form a sine wave for phase B. The phase difference between phase A and phase B is 90°. The higher the frequency of the sine wave, the faster the motor speed.

    Three-phase motors are similar to two-phase motors, the main difference is that three-phase motors have three phases, and the phase difference between adjacent phases is 60°.

    2. FUNCTION DESCRIPTION

    • The number of channels supporting SPWM is 18, of which channels 0~17 need to be added to their own groups. For details, see Correspondence between Group and Channel. Under normal circumstances, 4 channels or 6 channels need to be added to the group. From the perspective of motor control, it supports up to 3 two-phase four-wire motors and 1 three-phase six-wire motor (if 4 two-phase four-wire motors are used, the remaining two channels can be used as PWM).

    • The SPWM carrier frequency is 50Hz~50KHz, and the supported OSCCLK (Hz) is: 86M, 24M, 12M, 6M, 3M, 1.5M, 750K.

    • The sine wave cannot be distorted, that is, the new configuration of the period and duty cycle will take effect only after the current sine wave period ends.

    • The modulation modes supported by SPWM are Full-wave mode, Half-wave mode and Symmetric half-wave mode, the corresponding maximum modulation index is 64, 128 and 256.

    • The same group of SPWMs share a duty table, supporting up to 16bits * 64 duty configurations, that is, one modulation cycle supports up to 64 different duty cycle settings.

    • Support phase adjustment, that is, you can select any duty in the duty table as the starting point to start outputting SPWM.

    • Support scale function, that is, you can configure the scaling ratio for all duties in the duty table, which can be used to adjust the amplitude of the modulation wave.

    • Support clamp function, that is, you can set a clamp on the duty cycle. When duty <= lower limit, the duty cycle is 0, and when duty >= upper limit, the duty cycle is 100%, which can be used for dead zone protection.

    • Support round function, that is, SPWM in the same group will stop after generating a specific number of pulses.

    • Support stop function, that is, SPWM in the same group will stop urgently.

    3.1. Modulation Mode and Modulation Index

    • Full-wave mode

      The maximum value of a sine cycle is 64 carrier cycles (the modulation index can be set to 64 at most), and each carrier cycle is effective for duty, and the duty cycle is output according to the setting order of the duty table.

    • Half-wave mode

      The maximum value of a sine cycle is 128 carrier cycles (the modulation index can be set to 128 at most), the first 64 carrier cycles are effective for duty, and the duty cycle is output according to the setting order of the duty table, and the duty of the last 64 carrier cycles is 0.

    • Symmetric half-wave mode

      The maximum value of a sine cycle is 256 carrier cycles (the modulation index can be set to 256 at most). The 1st to 64th carrier cycles are all effective for duty, and the duty cycle is output according to the setting order of the duty table. The 65th to 128th carrier cycles are all effective for duty, and the duty cycle is output in the opposite order of the duty table setting, which is symmetrical with the first 64 carrier cycles. The duty of the 128th to 256th carrier cycle is 0.

    • Duty Table

      Each group of spwm shares a duty table, which can be abstractly understood as an array, which can store up to 64 duty values. When spwm is enabled, it will output the corresponding duty in each carrier cycle sequentially in the order of the duty table;

      Taking Full-wave mode as an example, if the modulation index is set to 10 and the initial phase is 0, then spwm will output waveforms according to duty0~duty9 in the duty table; if the modulation index is set to 64, then spwm will output waveforms according to duty0~duty63 in the duty table; the modulation index of Full-wave mode does not support setting values ​​greater than 64;

      Taking Half-wave mode as an example, if the modulation index is set to 10 and the initial phase is 0, then spwm will output waveforms according to duty0~duty9 in the duty table for the 1st to 10th carrier cycles, and the duty of the 11th to 20th carrier cycles is 0; if the modulation index is set to 128, then spwm will output waveforms according to duty0~duty63 in the duty table for the 1st to 64th carrier cycles, and the duty of the 65th to 128th carrier cycles is 0; the modulation index of Half-wave mode does not support setting values greater than 128.

    3.2. Scale Function

    The duty cycle scaling function can quickly adjust the amplitude of the modulation wave.

    Assuming OSCCLK is 12MHz, carrier period is 50KHz, and the scaling ratio set by scale is 50% of the original, the change of duty is as follows:

    Duty index Original duty cycle Duty cycle reduced by 50%
    0 250 ns 83 ns
    1 500 ns 250 ns
    2 750 ns 335 ns
    3 1000 ns 500 ns
    4 1250 ns 585 ns
    5 1500 ns 750 ns
    6 1750 ns 835 ns
    7 2000 ns 1000 ns
    8 2250 ns 1085 ns
    9 2500 ns 1250 ns

    Please note that the duty cycle is an integer multiple of 12MHz, so after the scale conversion, the duty cycle that is not an integer multiple will be rounded down.

    3.3. Clamp Function

    Duty cycle clamp mode, when duty <= lower limit, the duty cycle is 0, when duty >= upper limit, the duty cycle is 100%.

    With OSCCLK of 12MHz, carrier period of 50KHz, duty cycle range set by duty table of 250ns~16000ns, and duty cycle clamp upper and lower limits set to 10000~12000ns, the output waveform is as follows:

    3.4.1 Sync mode

    Sync mode can add each spwm channel to its own group to complete the purpose of controlling multiple spwm at the same time. A group has 4 or 6 spwm channels, and the group and channel correspondence is as follows:

    Group Group Member
    Group0 SPWM0, SPWM1, SPWM2, SPWM3
    Group1 SPWM4, SPWM5, SPWM6, SPWM7
    Group2 SPWM8, SPWM9, SPWM10, SPWM11
    Group3 SPWM12, SPWM13, SPWM14, SPWM15, SPWM16, SPWM17

    You can choose whether to add spwm to the Group through SYSDESC configuration:

    <pwm0>
        [reg_u32_u16] 0x2203200 0x40;
        ......
        [group_u32] 0xFFFF;
        [spwm_group_u32] 0;
        ......
    
    <pwm1>
        [reg_u32_u16] 0x2203240 0x40;
        ......
        [group_u32] 0xFFFF;
        [spwm_group_u32] 0;
        ......
    
    <pwm2>
        [reg_u32_u16] 0x2203280 0x40;
        ......
        [group_u32] 0xFFFF;
        [spwm_group_u32] 0;
        ......
    
    <pwm3>
        [reg_u32_u16] 0x22032C0 0x40;
        ......
        [group_u32] 0xFFFF;
        [spwm_group_u32] 0;
        ......
    
    <pwm4>
        [reg_u32_u16] 0x2203400 0x40;
        ......
        [group_u32] 1;
        [spwm_group_u32] 0xFFFF;
        ......
    
    <pwm5>
        [reg_u32_u16] 0x2203440 0x40;
        ......
        [group_u32] 1;
        [spwm_group_u32] 0xFFFF;
        ......
    
    <pwm6>
        [reg_u32_u16] 0x2203480 0x40;
        ......
        [group_u32] 1;
        [spwm_group_u32] 0xFFFF;
        ......
    
    <pwm7>
        [reg_u32_u16] 0x22034C0 0x40;
        ......
        [group_u32] 1;
        [spwm_group_u32] 0xFFFF;
        ......
    
    <pwm8>
        [reg_u32_u16] 0x2203800 0x40;
        ......
        [group_u32] 0xFFFF;
        [spwm_group_u32] 0xFFFF;
        ......
    
    <pwm9>
        [reg_u32_u16] 0x2203840 0x40;
        ......
        [group_u32] 0xFFFF;
        [spwm_group_u32] 0xFFFF;
        ......
    

    SYSDESC PWM nodes are configured with spwm_group_u32 to enable the spwm function and join the spwm group. For example, if pwm0~pwm3 are all configured with [spwm_group_u32] 0 and [group_u32] 0xFFFF, then pwm0~pwm3 will be given the spwm function and join spwm group0. It is necessary to follow the characteristics and settings of spwm, so spwm_group_u32 can be understood as the function switch of spwm;

    SYSDESC PWM nodes are configured with group_u32 to enable the pwm function and join the pwm group. For example, if pwm4~pwm7 are all configured with [group_u32] 1 and [spwm_group_u32] 0xFFFF, then pwm4~pwm7 will be given the pwm function and join pwm group1. At this time, the spwm function cannot be used;

    SYSDESC PWM nodes are configured with [group_u32] 0xFFFF and [spwm_group_u32] 0xFFFF, such as pwm8 and pwm9, then pwm8 and pwm9 can only be used as the ordinary pwm.

    3.4.2 Round mode

    The round function will stop after all spwm channels in the same spwm group complete a certain number of pulses. Each spwm group has its own independent round function. As shown in the figure below, spwm group0 uses full wave mode and round is set to 64, so the waveform stops after 64 pulses are actually output.

    3.4.3 Stop mode

    The stop function can stop all spwm channels in the current spwm group immediately (without waiting for the current cycle to complete) and maintain the level at the end. Each spwm group has its own independent stop function.

    Note: It is not recommended to set the stop time to be too long, especially when the level is maintained at a high level after stopping.


    4. Hardware connection instructions

    After the PIN pin is multiplexed to PWM MODE, it is already in output state. To protect the circuit, please do not inject external voltage; at the same time, the hardware will output PWM waveform or SPWM waveform according to the register setting, and the load can be connected as needed

    5. RISCV USAGE INTRODUCTION

    5.1. DRIVER PATH

    sc/driver/sysdriver/pwm/drv/pub/drv_pwm.h
    sc/driver/sysdriver/pwm/drv/src/drv_pwm.c
    sc/driver/sysdriver/pwm/drv/src/drv_spwm_test.c
    sc/driver/sysdriver/pwm/hal/chipname/src/hal_pwm.c
    sc/driver/sysdriver/pwm/hal/chipname/inc/hal_pwm.h
    sc/driver/sysdriver/pwm/hal/chipname/inc/hal_pwm_cfg.h
    

    5.2. CONFIG Configuration

    The config file is located in mak/options_chipname_riscv_isw.mak. Enable CONFIG_PWM_SUPPORT, CONFIG_SSTAR_SPWM and CONFIG_SSTAR_PWM_EXTEND.

    # Feature_Name = [DRV] PWM driver support
    # Description = PWM driver support
    # Option_Selection = TRUE, FALSE
    CONFIG_PWM_SUPPORT = TRUE       //Enable the PWM driver
    CONFIG_SSTAR_SPWM  = TRUE       //Enable the SPWM function
    CONFIG_SSTAR_PWM_EXTEND = TRUE  //SPWM only supports the high-precision mode
    

    5.3. SYSDESC Configuration

    The file chipname_xxx.sys is used to describe the hardware attributes of peripherals. The attribute values contained in the peripheral node can be used to configure the peripherals, similar to the Linux device tree. The file is located in sc/driver/sysdriver/sysdesc/hal/chipname/pub. The following takes pwm0 as an example:

    <pwm0>
        [reg_u32_u16] 0x2203200 0x40;
        [interrupts_u32] INT_IRQ_PWM_GROUP0;
        [camclk_u16] CAMCLK_pwm;
        [group_u32] 0xFFFF;
        [spwm_group_u32] 0;
        [clk_level_u8] 0;
        [status_u8] 0;
    

    The attributes supported for configuration in the pwm driver are as follows:

    Attribute Description Setting value Remark
    reg_u32_u16 Specify the bank address 0x2203200 Modification prohibited
    interrupts_u32 Specify the hardware interrupt number INT_IRQ_PWM_GROUP0 Modification prohibited
    camclk_u16 Specify the clock source CAMCLK_pwm Modification prohibited
    group_u32 Select whether to join the pwm group To enable spwm, this attribute must be set to 0xFFFF You can only choose to join group or spwm group
    spwm_group_u32 Select whether to join the pwm group According to Group and channel correspondence, the corresponding group index is assigned. 0xFFFF means not to join You can only choose to join group or spwm group
    clk_level_u8 Select the clock source Pwm0~17 can be selected from 0~6 corresponding to 12M/6M/3M/1.5M/750K/86M/24M Pwm0~17 selections must be consistent
    status_u8 Select whether to enable the driver 1: enable; 0: disable Can be modified as needed

    5.4. PADMUX Configuration

    CONFIG Configuration: CONFIG_PADMUX_SUPPORT=TRUE

    If the chipname_xxx.sys file is configured with the attribute <padmux>, then the PADMUX setting is directly configured here:

    <padmux>
        [schematic_u32_u32_u32]
                  PAD_GPIOC_00   PINMUX_FOR_PWM0_MODE_1    MDRV_PUSE_PWM0,
                  PAD_GPIOC_01   PINMUX_FOR_PWM1_MODE_1    MDRV_PUSE_PWM1,
                  PAD_GPIOC_02   PINMUX_FOR_PWM2_MODE_1    MDRV_PUSE_PWM2,
                  PAD_GPIOC_03   PINMUX_FOR_PWM3_MODE_1    MDRV_PUSE_PWM3,
                  PAD_GPIOC_04   PINMUX_FOR_PWM4_MODE_1    MDRV_PUSE_PWM4,
                  PAD_GPIOC_05   PINMUX_FOR_PWM5_MODE_1    MDRV_PUSE_PWM5,
                  PAD_GPIOC_06   PINMUX_FOR_PWM6_MODE_1    MDRV_PUSE_PWM6,
                  PAD_GPIOC_07   PINMUX_FOR_PWM7_MODE_1    MDRV_PUSE_PWM7,
                  PAD_GPIOC_08   PINMUX_FOR_PWM8_MODE_1    MDRV_PUSE_PWM8,
                  PAD_OUTP_CH0   PINMUX_FOR_PWM9_MODE_1    MDRV_PUSE_PWM9,
                  PAD_GPIOA_00   PINMUX_FOR_PWM10_MODE_2   MDRV_PUSE_PWM10,
                  PAD_GPIOA_01   PINMUX_FOR_PWM11_MODE_2   MDRV_PUSE_PWM11,
                  PAD_GPIOA_02   PINMUX_FOR_PWM12_MODE_2   MDRV_PUSE_PWM12,
                  PAD_GPIOA_03   PINMUX_FOR_PWM13_MODE_2   MDRV_PUSE_PWM13,
                  PAD_GPIOA_04   PINMUX_FOR_PWM14_MODE_2   MDRV_PUSE_PWM14,
                  PAD_GPIOA_05   PINMUX_FOR_PWM15_MODE_2   MDRV_PUSE_PWM15,
                  PAD_GPIOA_06   PINMUX_FOR_PWM16_MODE_2   MDRV_PUSE_PWM16,
                  PAD_GPIOA_07   PINMUX_FOR_PWM17_MODE_2   MDRV_PUSE_PWM17,
                  ......
        [status_u8] 1;
    

    Otherwise, enable the PADMUX driver and configure the pin multiplexing function in the chipname-xxx-padmux.c file, which is located in sc/driver/sysdriver/padmux/hal/chipname/src. You only need to add the following content to the corresponding schematic attribute:

    pad_info_t schematic[] =
    {
          {PAD_GPIOC_00   PINMUX_FOR_PWM0_MODE_1    MDRV_PUSE_PWM0},
          {PAD_GPIOC_01   PINMUX_FOR_PWM1_MODE_1    MDRV_PUSE_PWM1},
          {PAD_GPIOC_02   PINMUX_FOR_PWM2_MODE_1    MDRV_PUSE_PWM2},
          {PAD_GPIOC_03   PINMUX_FOR_PWM3_MODE_1    MDRV_PUSE_PWM3},
          {PAD_GPIOC_04   PINMUX_FOR_PWM4_MODE_1    MDRV_PUSE_PWM4},
          {PAD_GPIOC_05   PINMUX_FOR_PWM5_MODE_1    MDRV_PUSE_PWM5},
          {PAD_GPIOC_06   PINMUX_FOR_PWM6_MODE_1    MDRV_PUSE_PWM6},
          {PAD_GPIOC_07   PINMUX_FOR_PWM7_MODE_1    MDRV_PUSE_PWM7},
          {PAD_GPIOC_08   PINMUX_FOR_PWM8_MODE_1    MDRV_PUSE_PWM8},
          {PAD_OUTP_CH0   PINMUX_FOR_PWM9_MODE_1    MDRV_PUSE_PWM9},
          {PAD_GPIOA_00   PINMUX_FOR_PWM10_MODE_2   MDRV_PUSE_PWM10},
          {PAD_GPIOA_01   PINMUX_FOR_PWM11_MODE_2   MDRV_PUSE_PWM11},
          {PAD_GPIOA_02   PINMUX_FOR_PWM12_MODE_2   MDRV_PUSE_PWM12},
          {PAD_GPIOA_03   PINMUX_FOR_PWM13_MODE_2   MDRV_PUSE_PWM13},
          {PAD_GPIOA_04   PINMUX_FOR_PWM14_MODE_2   MDRV_PUSE_PWM14},
          {PAD_GPIOA_05   PINMUX_FOR_PWM15_MODE_2   MDRV_PUSE_PWM15},
          {PAD_GPIOA_06   PINMUX_FOR_PWM16_MODE_2   MDRV_PUSE_PWM16},
          {PAD_GPIOA_07   PINMUX_FOR_PWM17_MODE_2   MDRV_PUSE_PWM17},
          ......
    };
    

    The first column is the pin index number, which can be queried in sc/drivers/sysdriver/gpio/hal/chipname/pub/gpio.h;

    The second column is the mode definition, which can be queried in sc/drivers/sysdriver/gpio/hal/chipname/pub/padmux.h;

    The third column is the index name of the pin and matching mode, which can be queried in sc/drivers/sysdriver/padmux/drv/pub/drv_puse.h.

    5.5. Sample Code

    The demo source code is located in sc/driver/sysdriver/pwm/drv/src/drv_spwm_test.c.

    6. API Reference

    The header file is located in sc/driver/sysdriver/pwm/drv/pub/drv_pwm.h.

    struct spwm_gp_cfg
    {
        u8  mode;       //Modulation mode
        u8  step;       //Initial phase
        u8  scale;      //Duty scaling ratio n, calculated as n/8
        u32 group;      //SPWM group id
        u8  enable;     //1: enable
        u64 period;     //SPWM carrier period, in ns
        u8  clamp_en;   //Enable duty clamp function
        u8  duty_len;   //Duty table length
        u64 duty[64];   //Duty table setting, up to 64
        u32 round_num;  //Set the number of round pulses
        u64 clamp_max;  //Clamp upper limit
        u64 clamp_min;  //Clamp lower limit
    };
    
    extern int drv_spwm_update_period(u32 group, u64 period);
    extern int drv_spwm_set_sram_duty(u32 group, u8 index, u64 duty_ns);
    extern int drv_spwm_update_duty(u32 group, u8 index, u8 len, u64 *duty_ns);
    extern int drv_spwm_set_group_config(struct spwm_gp_cfg *gp_cfg);
    extern int drv_spwm_get_group_config(struct spwm_gp_cfg *gp_cfg);
    extern int drv_spwm_stop_enable(u32 group, u8 stop_en);
    extern int drv_spwm_round_enable(u32 group, u32 round_num);
    

    6.1 drv_spwm_set_group_config

    • Purpose

      Configure spwm group attributes.

    • Syntax

      int drv_spwm_set_group_config(struct spwm_gp_cfg *gp_cfg)
      
    • Parameter

      Parameter name Description
      gp_cfg Used to configure the spwm group's modulation mode, initial phase, duty table, carrier period and other attributes
    • Return value

      Result Description
      Success Return 0
      Failure Return negative numbers

    6.2 drv_spwm_get_group_config

    • Purpose

      Get the attribute configuration of the current spwm group.

    • Syntax

      int drv_spwm_get_group_config(struct spwm_gp_cfg *gp_cfg)
      
    • Parameter

      Parameter name Description
      gp_cfg Used to get the spwm group's modulation mode, initial phase, duty table, carrier period and other attributes
    • Return value

      Result Description
      Success Return 0
      Failure Return negative numbers

    6.3 drv_spwm_update_period

    • Purpose

      Update the carrier period of the spwm group.

    • Syntax

      int drv_spwm_update_period(u32 group, u64 period)
      
    • Parameter

      Parameter name Description
      group Select the group to enable the spwm waveform
      period Carrier period, in ns
    • Return value

      Result Description
      Success Return 0
      Failure Return negative numbers

    6.4 drv_spwm_set_sram_duty

    • Purpose

      Update the single duty value of the specified subscript in the spwm duty table.

    • Syntax

      int drv_spwm_set_sram_duty(u32 group, u8 index, u64 duty_ns)
      
    • Parameter

      Parameter name Description
      group Select the group to enable the spwm waveform
      index Select the subscript of the duty table
      duty_ns Set the duty cycle in ns
    • Return value

      Result Description
      Success Return 0
      Failure Return negative numbers

    6.5 drv_spwm_update_duty

    • Purpose

      Update the length duty values of the specified subscript in the spwm duty table.

    • Syntax

      int drv_spwm_update_duty(u32 group, u8 index, u8 len, u64 *duty_ns);
      
    • Parameter

      Parameter name Description
      group Select the group to enable the spwm waveform
      index Select the subscript of the duty table as the starting update point
      len Set the number of duties to be updated this time
      duty_ns Address of the duty cycle array
    • Return value

      Result Description
      Success Return 0
      Failure Return negative numbers

    6.6 drv_spwm_stop_enable

    • Purpose

      Enable the stop function.

    • Syntax

      int drv_spwm_stop_enable(u32 group, u8 stop_en)
      
    • Parameter

      Parameter name Description
      group Select the group to enable the stop function
      stop_en 1: enable, waveform stops; 0: disable, waveform resumes
    • Return value

      Result Description
      Success Return 0
      Failure Return negative numbers

    6.7 drv_spwm_round_enable

    • Purpose

      Set the number of pwm cycles for round mode operation.

    • Syntax

      int drv_spwm_round_enable(u32 group, u32 round_num)
      
    • Parameter

      Parameter name Description
      group Select the group to enable round mode
      round_num Specify the number of pwm cycles
    • Return value

      Result Description
      Success Return 0
      Failure Return negative numbers

    7. FAQ

    Q1:SPWM Device Does Not Exist

    1. Check if the status of the SYSDESC PWM node is 1.

    2. Check the spwm-group attribute of the SYSDESC PWM node, which should be configured as 0/½/3.

    3. Check the group attribute of the SYSDESC PWM node, which should be configured as 0xFFFF.

    4. Check if config is configured, see [5.2. CONFIG Configuration].

    Q2:No SPWM Waveform is Generated After Configuration

    1. First confirm whether the measured pin is correct: open the corresponding schematic to confirm.

    2. Confirm whether the corresponding PWM mode is effective. There are two main reasons for pin multiplexing failure:

      Reason 1: The pin is not set to PWM mode. See [PADMUX Configuration] for setting methods.

      Reason 2: There is a padmux mode with a higher priority than PWM mode is turned on.

    3. Check whether the relevant parameters are set successfully.

      Call drv_spwm_get_group_config to get whether the current configuration is correct.