RISCV_Capture使用参考
REVISION HISTORY¶
Revision No. | Description |
Date |
---|---|---|
1.0 | 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接口使用说明规范使用