RISCV_Capture使用参考


REVISION HISTORY

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

    1. 概述

    1.1. Capture

    Capture可以捕获PWM波形信息,包括周期、占空比及脉冲个数,Capture原理是通过捕获PWM波形的上升沿和下降沿及其时间间隔,从而得到PWM波形的信息,需要注意的是,捕获的波形占空比范围应该在0% < duty < 100%,因为占空比为0%或者100%的时候,不存在上升沿和下降沿,无法捕捉到跳变来获取输入的PWM波形信息。

    Capture的时钟频率为24Mhz,不支持切换。

    1.2. channel

    capture共有8组,其中前4组每组有2个channel支持捕获,后四组每组有1个channel支持捕获,总计12个channel支持捕获

    Capture最高支持12个channel同时捕获PWM周期及占空比,但每组仅有1个channel捕获脉冲数量,因此最高支持8个channel同时捕获脉冲数量

    2. 关键字

    sysdesc:

    RTOS用于描述外设硬件属性的文件,外设节点中包含的属性值可用于外设的配置,类似Linux的设备树文件

    padmux:

    引脚复用,用于将模块功能引脚连接到具体的外部引脚上面,打通信号连接。

    deglitch:

    滤波,长度小于deglitch值的波形会被忽略(单位ns),deglitch的设定会影响捕获的PWM频率上限

    3. 功能描述

    capture 支持三种模式的脉冲数量捕获:normal mode、direction mode、quad mode,捕获的频率范围为1Hz~6MHz

    3.1. 脉冲计数模式--normal mode

    8组Capture都支持normal mode,每捕获到两个上升沿后计数加1,最大值为0xFFFF,溢出清0

    3.2. 脉冲计数模式--direction mode

    仅前4组Capture0-Capture3支持direction mode,每组的两个channel,一个作为脉冲计数,另一个作为方向判断,

    当作为方向的channel捕获到高电平时,脉冲计数开始递增,最大值为0xFFFF,溢出清0,

    当作为方向的channel捕获到低电平时,脉冲计数开始递减,最大值为0xFFFF,逐渐减小至0后再跳变为0xFFFF,循环往复

    3.3. 脉冲计数模式--quad mode

    quad mode也称为正交编码计数模式,仅前4组Capture0-Capture3支持,每组的两个channel,

    通过捕获信号完全一样,相位差90度的PWM信号(即正交信号),以此计算出脉冲数量及方向,

    如图所示,quad mode就是4倍计数的意思,满足图中4个时刻的计数才会让脉冲数量加1,因此拥有更高的计数精度

    如图所示,脉冲在TI1和TI2边沿都计数,其中

    1 时刻:TI2为低电平,TI1上升沿跳变,计数器向上计数

    2 时刻:TI1为高电平,TI2上升沿跳变,计数器仍然向上计数

    3 时刻:TI2为高电平,TI1下降沿跳变,计数器仍然向上计数

    4 时刻:TI1为低电平,TI2下降沿跳变,计数器仍然向上计数

    4. RISCV用法介绍

    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配置

    config文件位于mak/options_chipname_riscv_isw.mak,使能CONFIG_CAPTURE_SUPPORT

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

    4.3 SYSDESC配置

    chipname-default.sys文件位于sc/driver/sysdriver/sysdesc/hal/chipname/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;
    

    驱动中支持配置的属性如下表:

    属性 描述 设定值 备注
    reg_u32 设定寄存器bank的地址 / 禁止修改
    interrupts_u32 指定使用的硬件中断号 INT_IRQ_CAPTURE 禁止修改
    camclk_u16 指定使用的时钟源 CAMCLK_pwm_capture 禁止修改
    channel_u8 每个group下拥有的channel id / 禁止修改
    pulse_cal_mode_u8 选择不同的脉冲计数模式,可参考脉冲计数模式说明 Capture03支持0->normal、1->quad、2->dir,Capture47仅支持0:normal 可根据需要修改
    pulse_cal_chan_u8 选择捕获脉冲数量的channel Capture03支持二选1,Capture47仅支持1个channel 可根据需要修改
    deglitch_u32 设定滤除的脉冲 以ns为单位,比如设定值为7,那么高电平时长低于24M * 7 = 291.67ns以下的脉冲无法被捕获 可根据需要修改
    status 选择是否使能Capture驱动 1:enable;0:disable 可根据需要修改

    4.4 PADMUX配置

    CONFIG配置:CONFIG_PADMUX_SUPPORT=TRUE

    如果chipname_xxx.sys文件配置了属性<padmux>,那么PADMUX的设定直接在此配置:

    <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;
    

    否则通过使能PADMUX驱动,在chipname-xxx-padmux.c文件配置引脚复用功能,该文件位于sc/driver/sysdriver/padmux/hal/chipname/src,只需要在对应的schematic属性添加如下内容中设定:

    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},
    };
    

    第一列为引脚索引号,可以在sc/drivers/sysdriver/gpio/hal/chipname/pub/gpio.h中查询;

    第二列为模式定义,可以在sc/drivers/sysdriver/gpio/hal/chipname/pub/padmux.h中查询;

    第三列为引脚及搭配模式的索引名称,可以在sc/drivers/sysdriver/padmux/drv/pub/drv_puse.h中查询;

    4.5 Demo code

    demo源码位于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 参考

    该功能模块提供以下接口:

    API名 功能
    drv_capture_set_config 配置capture属性
    drv_capture_get_config 获取capture属性
    drv_capture_period 获取捕获到的周期及占空比
    drv_capture_pulse 获取捕获到的脉冲数量及方向
    drv_capture_register_callback 注册回调函数
    drv_capture_unregister_callback 注销回调函数

    头文件位于sc/driver/sysdriver/capture/drv/pub/drv_capture.h

    struct capture_config
    {
        u8  group;        //指定捕获的group
        u8  channel;      //指定捕获的通道,需要在group的支持范围内
        u64 timeout;      //设定超时时间,以ns为单位
        u8  cap_edge;     //设定捕获周期和占空比时的边沿模式
        u8  pul_edge;     //设定捕获脉冲数量时的边沿模式
        u8  cap_enable;   //使能周期捕获
        u8  pul_enable;   //使能脉冲数量捕获
        u16 quad_pul_up;  //设定quad mode下的脉冲捕获上限
        u16 quad_pul_dn;  //设定quad mode下的脉冲捕获下限
    };
    
    struct capture_info
    {
        u8  dir;       //捕获脉冲时的方向
        u8  group;     //指定捕获的group
        u32 pulse;     //捕获的脉冲数量
        u64 period;    //捕获的周期
        u64 duty_i;    //捕获占空比的整数数值
        u64 duty_d;    //捕获占空比的小数数值
        u8  channel;   //指定捕获的通道,需要在group的支持范围内
    };
    
    typedef int (*capture_cb_t)(void *);
    
    struct capture_cb
    {
        capture_cb_t           cb_t;     //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

    • 功能

      配置capture属性

    • 声明

      int drv_capture_set_config(struct capture_config *cap_cfg)
      
    • 形参

      参数名称 描述
      cap_cfg 用于配置capture的通道、使能状态、边沿采样模式等属性
    • 返回值

      返回值 描述
      0 成功
      负数 失败

    5.2. drv_capture_get_config

    • 功能

      获取capture属性,防止更新参数时其他属性被改变

    • 声明

      drv_capture_get_config(struct capture_config *cap_cfg)
      
    • 形参

      参数名称 描述
      cap_cfg 用于获取capture的通道、使能状态、边沿采样模式等属性
    • 返回值

      返回值 描述
      0 成功
      负数 失败

    5.3. drv_capture_period

    • 功能

      获取捕获到的周期及占空比

    • 声明

      int drv_capture_period(struct capture_info *cap_info)
      
    • 形参

      参数名称 描述
      cap_info 用于获取捕获到的周期及占空比
    • 返回值

      返回值 描述
      0 成功
      负数 失败

    5.4. drv_capture_pulse

    • 功能

      获取捕获到的脉冲数量及方向

    • 声明

      int drv_capture_pulse(struct capture_info *cap_info)
      
    • 形参

      参数名称 描述
      cap_info 用于获取捕获到的脉冲数量及方向
    • 返回值

      返回值 描述
      0 成功
      负数 失败

    5.5. drv_capture_register_callback

    • 功能

      注册回调函数,用于quad mode捕获脉冲时达到阈值上下限的处理

    • 声明

      int drv_capture_register_callback(struct capture_cb *para)
      
    • 形参

      参数名称 描述
      para 配置回调函数
    • 返回值

      返回值 描述
      0 成功
      负数 失败

    5.6. drv_capture_unregister_callback

    • 功能

      注销回调函数

    • 声明

      int drv_capture_unregister_callback(struct capture_cb *para)
      
    • 形参

      参数名称 描述
      para 回调函数的配置信息
    • 返回值

      返回值 描述
      0 成功
      负数 失败

    6. FAQ

    6.1. Capture各接口不存在

    • 检查DTS Capture节点的status是否为ok

    • 检查kernel config是否配置,详见Kernel Config配置

    6.2. 配置后Cature捕获结果异常或超时

    Step1: 首先确认测量的引脚是否正确:打开对应的原理图确认即可,如果没有错误的话,则进行下一步。

    Step2: 确认对应的Capture pad mode是否生效,引脚复用失败主要有两个原因:

    原因一:该引脚没有设置为Capture mode,设置方法详见PADMUX配置

    原因二:有优先级比Capture mode更高级别的padmux mode被开启,可以在编译的时候打开padmux回读机制的CONFIG:CONFIG_MSYS_PADMUX,它的功能是用于确认使用到的padmux是否有被成功设定,开启后在在user space输入如下命令查看:

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

    Step3:检查相关参数是否设置成功

    请参考sysfs接口使用说明规范使用