RISCV_CAPTURE USER GUIDE


REVISION HISTORY

Revision No.
Description
Date
1.0
  • Initial release
  • 04/09/2025

    1. OVERVIEW

    1.1. Capture

    Capture can capture PWM waveform information, including period, duty cycle and number of pulses. The principle of Capture is to obtain the PWM waveform information by capturing the rising and falling edges of the PWM waveform and their time intervals. It should be noted that the captured waveform duty cycle range should be 0% < duty < 100%, because when the duty cycle is 0% or 100%, there is no rising and falling edge, and the jump cannot be captured to obtain the input PWM waveform information.

    The clock frequency of Capture is 24Mhz, and switching is not supported.

    1.2. channel

    Capture has 8 groups, of which the first 4 groups have 2 channels each, and the last 4 groups have 1 channel each, there are 12 channels to support capture in total.

    Capture supports up to 12 channels to capture PWM period and duty cycle at the same time, but each group has only 1 channel to capture the number of pulses, so it supports up to 8 channels to capture the number of pulses at the same time.

    2. Key Words

    sysdesc:

    RTOS files 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 device tree file of Linux.

    padmux:

    Pin Multiplexing, used to connect the functional pins of a module to specific external pins, thereby establishing signal connections.

    deglitch:

    Glitch filtering: waveforms shorter than the deglitch value (in ns) will be ignored. The setting of deglitch affects the upper limit of the captured PWM frequency

    3. Function Description

    Support three modes of pulse number capture: normal mode, direction mode, quad mode.the captured frequency range is 1Hz ~ 6MHz.

    3.1. Pulse Counting Mode--Normal Mode

    All 8 capture groups support normal mode. After capturing two rising edges, the count increases by 1. The maximum value is 0xFFFF, and overflow is cleared to 0.

    3.2. Pulse Counting Mode--Direction Mode

    Only the first 4 groups Capture0-Capture3 support direction mode. Each group has two channels, one for pulse counting and the other for direction judgment.

    When the channel as the direction captures a high level, the pulse count starts to increase, the maximum value is 0xFFFF, and overflow is cleared to 0.

    When the channel as the direction captures a low level, the pulse count starts to decrease, the maximum value is 0xFFFF, gradually decreases to 0 and then jumps to 0xFFFF, repeating the cycle.

    3.3. Pulse Counting Mode--Quad Mode

    The quad mode is also called orthogonal encoding counting mode. It is only supported by the first 4 groups Capture0-Capture3, with two channels in each group.

    By capturing PWM signals with the same signal and a phase difference of 90 degrees (i.e. orthogonal signals), the number and direction of pulses are calculated.

    As shown in the figure, quad mode means 4 times counting. The number of pulses will be increased by 1 only when the counting at the 4 moments in the figure is met, so it has a higher counting accuracy.

    As shown in the figure, pulses count on both edges of TI1 and TI2, among which,

    Moment 1: TI2 is at a low level, TI1 has an upward edge transition, the counter counts up

    Moment 2: TI1 is at a high level, TI2 has an upward edge transition, the counter continues to count up

    Moment 3: TI2 is at a high level, TI1 has a downward edge transition, the counter continues to count up

    Moment 4: TI1 is at a low level, TI2 has a downward edge transition, the counter continues to count up

    4. RISCV USAGE INTRODUCTION

    4.1. Driver Path

    sc/driver/sysdriver/capture/os/capture_os.h
    sc/driver/sysdriver/capture/drv/pub/drv_capture.h
    sc/driver/sysdriver/capture/drv/src/drv_capture.c
    sc/driver/sysdriver/capture/drv/src/drv_capture_test.c
    sc/driver/sysdriver/capture/hal/chipname/src/hal_capture.c
    sc/driver/sysdriver/capture/hal/chipname/inc/hal_capture.h
    sc/driver/sysdriver/capture/hal/chipname/inc/hal_capture_cfg.h
    

    4.2. CONFIG Configuration

    The config file is located at mak/options_chipname_riscv_isw.mak, enable CONFIG_CAPTURE_SUPPORT.

    # Feature_Name = [DRV] CAPTURE driver support
    # Description = CAPTURE driver support
    # Option_Selection = TRUE, FALSE
    CONFIG_CAPTURE_SUPPORT = TRUE
    

    4.3. SYSDESC Configuration

    The chipname-default.sys file is located in sc\driver\sysdriver\sysdesc\hal\pcupid\pub\.

    <capture0>
        [reg_u32] 0x22CE000;
        [interrupts_u32] INT_IRQ_CAPTURE;
        [camclk_u16] CAMCLK_pwm_capture;
        [channel_u8] 0, 1;
        [pulse_cal_mode_u8] 0;
        [pulse_cal_chan_u8] 0;
        [deglitch_u32] 0;
        [status_u8] 0;
    
    ......
    
    <capture7>
        [reg_u32] 0x22CF980;
        [interrupts_u32] INT_IRQ_CAPTURE;
        [camclk_u16] CAMCLK_pwm_capture;
        [channel_u8] 11;
        [pulse_cal_mode_u8] 0;
        [pulse_cal_chan_u8] 11;
        [deglitch_u32] 0;
        [padmux_u16] PINMUX_FOR_UNKNOWN_MODE;
        [status_u8] 0;
    

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

    Attribute Description Setting Value Remark
    reg_u32 Set the address of the register bank / Modification prohibited
    interrupts_u32 Specify the hardware interrupt number to be used INT_IRQ_CAPTURE Modification prohibited
    camclk_u16 Specify the clock source to be used CAMCLK_pwm_capture Modification prohibited
    channel_u8 Channel ID owned by each group / Modification prohibited
    pulse_cal_mode_u8 Select different pulse counting modes, please refer to Pulse Counting Mode Description Capture0~3 supports 0->normal, 1->quad, 2->dir, Capture4~7 only supports 0: normal Can be modified as needed
    pulse_cal_chan_u8 Select the channel for capturing the number of pulses Capture0~3 supports 2-choose-1, Capture4~7 only supports 1 channel Can be modified as needed
    deglitch_u32 Set the pulse to be filtered In ns, for example, if the setting value is 7, then pulses with a high level duration shorter than 24M * 7 = 291.67ns cannot be captured Can be modified as needed
    status Select whether to enable the Capture driver 1: enable; 0: disable Can be modified as needed

    4.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_OUTP_CH0   PINMUX_FOR_PWMIN0_MODE_1 MDRV_PUSE_PWMIN0,
                PAD_OUTN_CH0   PINMUX_FOR_PWMIN1_MODE_1 MDRV_PUSE_PWMIN1,
                PAD_OUTP_CH1   PINMUX_FOR_PWMIN2_MODE_1 MDRV_PUSE_PWMIN2,
                PAD_OUTN_CH1   PINMUX_FOR_PWMIN3_MODE_1 MDRV_PUSE_PWMIN3,
                PAD_OUTP_CH2   PINMUX_FOR_PWMIN4_MODE_1 MDRV_PUSE_PWMIN4,
                PAD_OUTN_CH2   PINMUX_FOR_PWMIN5_MODE_1 MDRV_PUSE_PWMIN5,
                PAD_OUTP_CH3   PINMUX_FOR_PWMIN6_MODE_1 MDRV_PUSE_PWMIN6,
                PAD_OUTN_CH3   PINMUX_FOR_PWMIN7_MODE_1 MDRV_PUSE_PWMIN7,
                PAD_GPIOE_10   PINMUX_FOR_PWMIN8_MODE_3 MDRV_PUSE_PWMIN8,
                PAD_GPIOD_00   PINMUX_FOR_PWMIN9_MODE_2 MDRV_PUSE_PWMIN9,
                PAD_GPIOE_14   PINMUX_FOR_PWMIN10_MODE_3 MDRV_PUSE_PWMIN10,
                PAD_GPIOE_16   PINMUX_FOR_PWMIN11_MODE_3 MDRV_PUSE_PWMIN11;
        [status_u8] 1;
    

    Otherwise, by enabling the PADMUX driver, 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_OUTP_CH0   PINMUX_FOR_PWMIN0_MODE_1 MDRV_PUSE_PWMIN0},
        {PAD_OUTN_CH0   PINMUX_FOR_PWMIN1_MODE_1 MDRV_PUSE_PWMIN1},
        {PAD_OUTP_CH1   PINMUX_FOR_PWMIN2_MODE_1 MDRV_PUSE_PWMIN2},
        {PAD_OUTN_CH1   PINMUX_FOR_PWMIN3_MODE_1 MDRV_PUSE_PWMIN3},
        {PAD_OUTP_CH2   PINMUX_FOR_PWMIN4_MODE_1 MDRV_PUSE_PWMIN4},
        {PAD_OUTN_CH2   PINMUX_FOR_PWMIN5_MODE_1 MDRV_PUSE_PWMIN5},
        {PAD_OUTP_CH3   PINMUX_FOR_PWMIN6_MODE_1 MDRV_PUSE_PWMIN6},
        {PAD_OUTN_CH3   PINMUX_FOR_PWMIN7_MODE_1 MDRV_PUSE_PWMIN7},
        {PAD_GPIOE_10   PINMUX_FOR_PWMIN8_MODE_3 MDRV_PUSE_PWMIN8},
        {PAD_GPIOD_00   PINMUX_FOR_PWMIN9_MODE_2 MDRV_PUSE_PWMIN9},
        {PAD_GPIOE_14   PINMUX_FOR_PWMIN10_MODE_3 MDRV_PUSE_PWMIN10},
        {PAD_GPIOE_16   PINMUX_FOR_PWMIN11_MODE_3 MDRV_PUSE_PWMIN11},
    };
    

    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;

    4.5 Demo code

    The demo code is located in sc/driver/sysdriver/capture/drv/src/drv_capture_test.c.

    #include <drv_capture.h>
    #include <sys_sys_isw_cli.h>
    
    #if defined(__VER_CAPTURE__)
    
    static capture_cb_t cb_t[12] = {0};
    
    int capture_bound(void *para)
    {
        u8 group;
    
        group = *((u8 *)para);
    
        cliPrintf("capture%hhu pulse exceeding bound\n", group);
    
        return 0;
    }
    
    static int capture_ut_test(CLI_t *cli, char *p)
    {
        int                   ret;
        char *                cmd;
        u32                   edge;
        u32                   group;
        u32                   enable;
        u32                   channel;
        u64                   time_ns;
        struct capture_info   info    = {0};
        struct capture_config cap_cfg = {0};
    
        cmd = CliTokenPop(cli);
        if (!cmd)
            return -eCLI_PARSE_INPUT_ERROR;
    
        if (strcmp(cmd, "config") == 0)
        {
            if (CliTokenCount(cli) == 4)
            {
                if (CliTokenPopNum(cli, &group, 0) != eCLI_PARSE_OK)
                    goto cap_config_msg;
                if (CliTokenPopNum(cli, &channel, 0) != eCLI_PARSE_OK)
                    goto cap_config_msg;
                if (CliTokenPopNum(cli, &edge, 0) != eCLI_PARSE_OK)
                    goto cap_config_msg;
                if (CliTokenPopNum(cli, &enable, 0) != eCLI_PARSE_OK)
                    goto cap_config_msg;
    
                cb_t[channel] = capture_bound;
                if (enable)
                    drv_capture_register_callback((u8)group, cb_t[channel]);
                else
                    drv_capture_unregister_callback((u8)group, cb_t[channel]);
    
                cap_cfg.group       = (u8)group;
                cap_cfg.channel     = (u8)channel;
                cap_cfg.cap_edge    = (u8)edge;
                cap_cfg.pul_edge    = (u8)edge;
                cap_cfg.cap_enable  = (u8)enable;
                cap_cfg.pul_enable  = (u8)enable;
                cap_cfg.quad_pul_up = 20000;
                cap_cfg.quad_pul_dn = 20000;
                cap_cfg.timeout     = 0;
    
                ret = drv_capture_set_config(&cap_cfg);
                if (ret)
                    return -eCLI_PARSE_INVALID_PARAMETER;
            }
            else
            {
            cap_config_msg:
                cliPrintf("command format : capture <config> [group] [channel] [edge] [enable]\n");
                return -eCLI_PARSE_INVALID_PARAMETER;
            }
    
            return eCLI_PARSE_OK;
        }
        else if (strcmp(cmd, "period") == 0)
        {
            if (CliTokenCount(cli) == 2)
            {
                if (CliTokenPopNum(cli, &group, 0) != eCLI_PARSE_OK)
                    goto cap_period_msg;
                if (CliTokenPopNum(cli, &channel, 0) != eCLI_PARSE_OK)
                    goto cap_period_msg;
    
                info.group   = (u8)group;
                info.channel = (u8)channel;
    
                ret = drv_capture_period(&info);
                if (ret)
                    return -eCLI_PARSE_INVALID_PARAMETER;
    
                CamOsPrintf("capture period [%llu]ns , duty [%llu.%02llu]%% \n", info.period, info.duty_i, info.duty_d);
            }
            else
            {
            cap_period_msg:
                cliPrintf("command format : capture <period> [group] [channel]\n");
                return -eCLI_PARSE_INVALID_PARAMETER;
            }
    
            return eCLI_PARSE_OK;
        }
        else if (strcmp(cmd, "pulse") == 0)
        {
            if (CliTokenCount(cli) == 3)
            {
                if (CliTokenPopNum(cli, &group, 0) != eCLI_PARSE_OK)
                    goto cap_pulse_msg;
                if (CliTokenPopNum(cli, &channel, 0) != eCLI_PARSE_OK)
                    goto cap_pulse_msg;
                if (CliTokenPopNum(cli, &enable, 0) != eCLI_PARSE_OK)
                    goto cap_pulse_msg;
    
                info.group   = (u8)group;
                info.channel = (u8)channel;
    
                ret = drv_capture_pulse_enable(group, channel, (u8)enable);
                if (ret)
                    return -eCLI_PARSE_INVALID_PARAMETER;
    
                if (enable)
                {
                    ret = drv_capture_pulse(&info);
                    if (ret)
                        return -eCLI_PARSE_INVALID_PARAMETER;
    
                    CamOsPrintf("capture pulse [%u], direction [%hhu]\n", info.pulse, info.dir);
                }
            }
            else
            {
            cap_pulse_msg:
                cliPrintf("command format : capture <pulse> [group] [channel] [enable]\n");
                return -eCLI_PARSE_INVALID_PARAMETER;
            }
    
            return eCLI_PARSE_OK;
        }
        else if (strcmp(cmd, "time") == 0)
        {
            if (CliTokenCount(cli) == 3)
            {
                if (CliTokenPopNum(cli, &group, 0) != eCLI_PARSE_OK)
                    goto cap_time_msg;
                if (CliTokenPopNum(cli, &channel, 0) != eCLI_PARSE_OK)
                    goto cap_time_msg;
                if (CliTokenPopNumU64(cli, &time_ns, 0) != eCLI_PARSE_OK)
                    goto cap_time_msg;
    
                cap_cfg.group   = (u8)group;
                cap_cfg.channel = (u8)channel;
                ret             = drv_capture_get_config(&cap_cfg);
                if (ret)
                    return -eCLI_PARSE_INVALID_PARAMETER;
    
                cap_cfg.timeout = time_ns;
                ret             = drv_capture_set_config(&cap_cfg);
                if (ret)
                    return -eCLI_PARSE_INVALID_PARAMETER;
            }
            else
            {
            cap_time_msg:
                cliPrintf("command format : capture <time> [group] [channel] [time_ns]\n");
                return -eCLI_PARSE_INVALID_PARAMETER;
            }
    
            return eCLI_PARSE_OK;
        }
        else
        {
            return -eCLI_PARSE_INVALID_PARAMETER;
        }
    }
    

    5. API Reference

    This functional module provides the following interfaces:

    API Function
    drv_capture_set_config Configure capture attributes
    drv_capture_get_config Get the capture attribute
    drv_capture_period Get the captured period and duty cycle
    drv_capture_pulse Get the number and direction of captured pulses
    drv_capture_register_callback Register the callback function
    drv_capture_unregister_callback Unregister the callback function

    The header file is located at sc/driver/sysdriver/capture/drv/pub/drv_capture.h.

    struct capture_config
    {
        u8  group;        //Specify the capture group
        u8  channel;      //Specify the capture channel, which needs to be within the supported range of the group
        u64 timeout;      //Set the timeout in ns
        u8  cap_edge;     //Set the edge mode when capturing the period and duty cycle
        u8  pul_edge;     //Set the edge mode when capturing the number of pulses
        u8  cap_enable;   //Enable period capture
        u8  pul_enable;   //Enable pulse number capture
        u16 quad_pul_up;  //Set the upper limit of pulse capture in quad mode
        u16 quad_pul_dn;  //Set the lower limit of pulse capture in quad mode
    };
    
    struct capture_info
    {
        u8  dir;          //Direction when capturing pulses
        u8  group;        //Specify the capture group
        u32 pulse;        //The number of pulses captured
        u64 period;       //The period of capture
        u64 duty_i;       //The integer value of the Capture duty cycle
        u64 duty_d;       //The decimal value of the Capture duty cycle
        u8  channel;      //Specify the capture channel, which needs to be within the supported range of the group
    };
    
    typedef int (*capture_cb_t)(void *);
    
    struct capture_cb
    {
        capture_cb_t           cb_t;     //Processing function after capturing pulses exceeds the threshold in quad mode
        u8                     group;
        u8                     channel;
        struct CamOsListHead_t cb_node;
    };
    
    extern int drv_capture_set_config(struct capture_config *cap_cfg);
    extern int drv_capture_get_config(struct capture_config *cap_cfg);
    extern int drv_capture_period(struct capture_info *cap_info);
    extern int drv_capture_pulse(struct capture_info *cap_info);
    extern int drv_capture_register_callback(struct capture_cb *para);
    extern int drv_capture_unregister_callback(struct capture_cb *para);
    

    5.1 drv_capture_set_config

    • Purpose

      Configure capture attributes.

    • Syntax

      int drv_capture_set_config(struct capture_config *cap_cfg)
      
    • Parameter

      Parameter Name Description
      cap_cfg Used to configure capture channels, enabling status, edge sampling modes and other attributes
    • Return value

      Return Value Description
      0 Success
      negative Failure

    5.2 drv_capture_get_config

    • Purpose

      Get the capture attribute to prevent other attributes from being changed when updating parameters.

    • Syntax

      drv_capture_get_config(struct capture_config *cap_cfg)
      
    • Parameter

      Parameter Name Description
      cap_cfg Used to obtain capture channels, enabling status, edge sampling modes and other attributes
    • Return value

      Return Value Description
      0 Success
      negative Failure

    5.3 drv_capture_period

    • Purpose

      Get the captured period and duty cycle.

    • Syntax

      int drv_capture_period(struct capture_info *cap_info)
      
    • Parameter

      Parameter Name Description
      cap_info Used to get the captured period and duty cycle
    • Return value

      Return Value Description
      0 Success
      negative Failure

    5.4 drv_capture_pulse

    • Purpose

      Get the number and direction of captured pulses.

    • Syntax

      int drv_capture_pulse(struct capture_info *cap_info)
      
    • Parameter

      Parameter Name Description
      cap_info Used to get the number and direction of captured pulses
    • Return value

      Return Value Description
      0 Success
      negative Failure

    5.5 drv_capture_register_callback

    • Purpose

      Register the callback function for processing when the upper and lower thresholds are reached when capturing pulses in quad mode.

    • Syntax

      int drv_capture_register_callback(struct capture_cb *para)
      
    • Parameter

      Parameter Name Description
      para Configure the callback function
    • Return value

      Return Value Description
      0 Success
      negative Failure

    5.6 drv_capture_unregister_callback

    • Purpose

      Unregister the callback function.

    • Syntax

      int drv_capture_unregister_callback(struct capture_cb *para)
      
    • Parameter

      Parameter Name Description
      para The configuration information of the callback function
    • Return value

      Return Value Description
      0 Success
      negative Failure

    6. FAQ

    6.1. Each Capture Interface Does Not Exist

    • Check whether the status of the DTS Capture node is ok.

    • Check whether the kernel config is configured, see Kernel Config Configuration.

    6.2. Capture Results Are Abnormal or Timed out After Configuration

    Step 1: First confirm whether the measured pin is correct: open the corresponding schematic to confirm, if there is no error, proceed to the next step.

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

    Reason 1: The pin is not set to Capture mode. For details on the setting method, see PADMUX Configuration.

    Reason 2: A padmux mode with a higher priority than Capture mode is enabled. You can turn on the padmux readback mechanism CONFIG: CONFIG_MSYS_PADMUX during compilation. Its function is to confirm whether the padmux used has been successfully set. After turning it on, enter the following command in user space to check:

    echo [pad index] [pinmux index] > /sys/class/sstar/msys/mux_verify
    
    cat /sys/class/sstar/msys/mux_verify
    

    Step 3: Check whether the relevant parameters are set successfully.

    Please refer to Sysfs Interface Usage Instructions for standard usage.