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. 关键字

    dts/dtsi:

    Linux设备树文件,通常用于描述CPU所支持的外设,外设节点中包含的属性值可用于外设的配置。

    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. Kernel用法介绍

    驱动路径:kernel/drivers/sstar/capture

    4.1. Kernel Config配置

    在编译kernel时需要选择的配置如下:

    Device Drivers-->
        [*] SStar SoC platform drivers-->
            [*] Sigmastar Capture driver
    

    4.2. 配置DTS

    Capture的DTS配置只需要在对应的chipname.dtsi中配置如下信息:

    capture0: capture@1f2ce000 {
        compatible = "sstar,capture";
        reg = <0x0 0x1F2CE000 0x0 0x80>;
        interrupts=<GIC_SPI INT_IRQ_CAPTURE IRQ_TYPE_LEVEL_HIGH>;
        group = <0>;
        channel = <0 1>;
        //0: normal mode,  1: quad mode, 2: dir mode
        pulse-cal-mode = <0>;
        pulse-cal-chan = <0>;
        deglitch = <0>;
        clocks = <&CLK_pwm_capture>;
        status = "ok";
    };
    
    .......
    
    capture4: capture@1f2cf800 {
        compatible = "sstar,capture";
        reg = <0x0 0x1F2CF800 0x0 0x80>;
        interrupts=<GIC_SPI INT_IRQ_CAPTURE IRQ_TYPE_LEVEL_HIGH>;
        group = <4>;
        channel = <8>;
        //only support 0: normal mode
        pulse-cal-mode = <0>;
        pulse-cal-chan = <8>;
        deglitch = <0>;
        clocks = <&CLK_pwm_capture>;
        status = "ok";
    };
    

    Capture DTS配置说明:

    属性 描述 设定值 备注
    compatible 匹配驱动进行注册,需与代码中一致 "sstar,capture" 禁止修改
    reg 设定寄存器bank的地址 / 禁止修改
    interrupts 指定使用的硬件中断号及属性 INT_IRQ_CAPTURE 禁止修改
    group 每个channel所属的group id / 禁止修改
    channel 每个group下拥有的channel id / 禁止修改
    pulse-cal-mode 选择不同的脉冲计数模式,可参考脉冲计数模式说明 Capture03支持02,Capture4~7仅支持0 可根据需要修改
    pulse-cal-chan 选择捕获脉冲数量的channel Capture03支持二选1,Capture47仅支持1个channel 可根据需要修改
    deglitch 设定滤除的脉冲 以ns为单位,比如设定值为7,那么高电平时长低于24M * 7 = 291.67ns以下的脉冲无法被捕获 可根据需要修改
    clocks 指定使用的时钟源 CLK_pwm_capture 禁止修改
    status 选择是否使能Capture驱动 "ok" or "disable" 可根据需要修改

    4.3. PADMUX配置

    Capture的padmux配置需要根据选择的引脚在对应的arch/arm64/boot/dts/sstar/chipname-xxx-padmux.dtsi中加入如下所示的代码:

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

    第一列为引脚索引号,可以在/drivers/sstar/inlcude/{chipname}/gpio.h中查到;

    第二列为模式定义,在/drivers/sstar/gpio/{chipname}/hal_pinmux.c中hal_gpio_st_padmux_info数组里罗列了所有引脚的复用关系,可用于查询该引脚支持哪些复用功能;

    第三列为引脚及搭配模式的索引名称,可在/drivers/sstar/include/drv_puse.h里查询。

    4.4. 模块使用介绍

    4.4.1. sys/class/sstar/capture

    sys/class/sstar/capture目录结构如下:

    • 一级目录

      根据DTS Capture status的状态创建不同的group

    • 二级目录

      每组Capture的各项属性设定

    各文件接口的使用介绍

    名称 描述 参数 备注
    capture 获取捕获到的频率和占空比 echo [channel id] > capture;cat capture
    cap_edge 设定捕获周期和占空比时的边沿采样模式 echo [channel id] [edge mode] > cap_edge edge mode:0->上升沿 1->下降沿 2->双边沿
    cap_enable 捕获使能 echo [enable] > cap_enable 0->disable 1->enable
    pulse 获取捕获到的脉冲数量 cat pulse 捕获的channel由DTS决定
    pulse_edge 设定捕获脉冲数量时的边沿采样模式 echo [edge mode] > pulse_edge edge mode:0->上升沿 1->下降沿 2->双边沿,注意单边沿捕获的脉冲数量是双边沿的倍数关系
    pulse_enable 捕获使能 echo [enable] > pulse_enable 0->disable 1->enable
    pulse_bound quad mode下捕获的上下限设定 echo [max] [min]> pulse_bound 仅支持quad mode使用,当方向为正时,达到max会触发中断并将捕获的pulse数值清0,当方向为负时,达到min会触发中断并将捕获的pulse数值清0
    direction 获取捕获脉冲时的方向 cat direction 0->负向 1->正向
    timeout 设定捕获的超时时间 echo [channel id] [time ns] > time_out 在规定时间内捕获的结果不变,软件判定为输入源已断开,捕获失败,可用于较小频率的捕获

    举例:使用Capture0的channel0捕获频率、占空比和脉冲数量

    1.    #跳转到Capture0路径
    2.    cd sys/class/sstar/capture0/
    3.
    4.     #设置Capture相关属性
    5.     echo 0 2 > cap_edge
    6.     echo 1   > cap_enable
    7.     echo 1   > pulse_edge
    8.     echo 1   > pulse_enable
    9.
    10.    #获取捕获结果
    11.    echo 0 > capture;
    12.    cat capture;
    13.    cat pulse;
    14.    cat direction;
    

    4.5 Demo code

    除sysfs外,capture还提供了ioctl的用户层接口, 用法如下

    #include <stdio.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <signal.h>
    #include <string.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <sys/ioctl.h>
    #include <drv_capture.h>
    
    void capture_warn(int num)
    {
        printf("capture pulse exceeding the threshold\n");
    }
    
    int main(int argc, char **argv)
    {
        u8                    id;
        char                  cmd;
        int                   flags;
        int                   fd = -1;
        char                  path_name[24];
        struct capture_info   info;
        struct capture_config cap_cfg;
    
        if (argc != 5)
        {
            printf("format: ut_capture [channel] [cap_edge] [pul_edge] [enable]\n");
            return -1;
        }
    
        info.channel        = atoi(argv[1]);
        cap_cfg.channel     = atoi(argv[1]);
        cap_cfg.cap_edge    = atoi(argv[2]);
        cap_cfg.pul_edge    = atoi(argv[3]);
        cap_cfg.cap_enable  = atoi(argv[4]);
        cap_cfg.pul_enable  = atoi(argv[4]);
        cap_cfg.quad_pul_up = 20000;
        cap_cfg.quad_pul_dn = 20000;
        cap_cfg.timeout     = 10000000000;
    
        if (cap_cfg.channel >= 0 && cap_cfg.channel <= 1)
        {
            id = 0;
        }
        else if (cap_cfg.channel >= 2 && cap_cfg.channel <= 3)
        {
            id = 1;
        }
        else if (cap_cfg.channel >= 4 && cap_cfg.channel <= 5)
        {
            id = 2;
        }
        else if (cap_cfg.channel >= 6 && cap_cfg.channel <= 7)
        {
            id = 3;
        }
        else if (cap_cfg.channel == 8)
        {
            id = 4;
        }
        else if (cap_cfg.channel == 9)
        {
            id = 5;
        }
        else if (cap_cfg.channel == 10)
        {
            id = 6;
        }
        else if (cap_cfg.channel == 11)
        {
            id = 7;
        }
        else
        {
            printf("unsupport channel\n");
            return -1;
        }
    
        snprintf(path_name, sizeof(path_name), "/dev/capture%hhu", id);
        fd = open((const char *)(char *)path_name, O_RDWR);
        if (fd < 0)
        {
            printf("open /dev/capture%hhu fail errno:[%d]\n", id, fd);
            return -1;
        }
    
        if (ioctl(fd, IOCTL_CAPTURE_SET_CONFIG, &cap_cfg))
        {
            printf("capture[%hhu] config fail\n", cap_cfg.channel);
            close(fd);
            return -1;
        }
    
        signal(SIGIO, capture_warn); //quad mode达到上下限时触发
    
        fcntl(fd, F_SETOWN, getpid());
        flags = fcntl(fd, F_GETFL);
        fcntl(fd, F_SETFL, flags | FASYNC);
    
        while (1)
        {
            cmd = getchar();
            if (cmd == 'q' || cmd == 'Q')
            {
                break;
            }
    
            if (ioctl(fd, IOCTL_CAPTURE_RD_PERIOD, &info))
            {
                printf("capture[%hhu] read period fail\n", info.channel);
                close(fd);
                return -1;
            }
            printf("capture period [%llu]ns , duty [%llu.%02llu]%% \n", info.period, info.duty_i, info.duty_d);
    
            if (ioctl(fd, IOCTL_CAPTURE_RD_PULSE, &info))
            {
                printf("capture[%hhu] read pulse fail\n", info.channel);
            }
            else
            {
                printf("capture pulse [%u] dir[%hhu]\n", info.pulse, info.dir);
            }
        }
    
        close(fd);
    
        return 0;
    }
    

    5. API 参考

    capture的ioctl方法提供以下魔数接口:

    Cmd 功能
    IOCTL_CAPTURE_SET_CONFIG 设定指定channel的捕获属性
    IOCTL_CAPTURE_GET_CONFIG 获取当前channel的捕获属性
    IOCTL_CAPTURE_RD_PERIOD 获取当前周期
    IOCTL_CAPTURE_RD_PULSE 获取当前脉冲计数

    使用前需包含头文件/driver/sstar/capture/drv_capture.h,其中定义的数据结构如下:

    struct capture_config
    {
        u8  channel;     //指定捕获channel
        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;      //捕获脉冲时的方向
        u32 pulse;    //捕获的脉冲数量
        u64 period;   //捕获的周期
        u64 duty_i;   //捕获占空比的整数数值
        u64 duty_d;   //捕获占空比的小数数值
        u8  channel;
    };
    

    5.1. IOCTL_CAPTURE_SET_CONFIG

    • 功能

      从 cfg 设定file 对应设备的捕获属性。

    • 声明

      ioctl(struct file *file, IOCTL_CAPTURE_SET_CONFIG,struct capture_config *cfg);
      
    • 形参

      参数名称 描述
      file 设备节点
      IOCTL_CAPTURE_SET_CONFIG 命令
      cfg 存储配置的结构体
    • 返回值

      返回值 描述
      0 成功
      other 失败

    5.2. IOCTL_CAPTURE_GET_CONFIG

    • 功能

      获取 file 对应设备的捕获属性,并返回到 cfg。

    • 声明

      ioctl(struct file *file, IOCTL_CAPTURE_GET_CONFIG,struct capture_config *cfg);
      
    • 形参

      参数名称 描述
      file 设备节点
      IOCTL_CAPTURE_GET_CONFIG 命令
      cfg 存储配置的结构体
    • 返回值

      返回值 描述
      0 成功
      other 失败

    5.3. IOCTL_CAPTURE_RD_PERIOD

    • 功能

      获取 file 对应设备的当前周期并返回到 info 。

    • 声明

      ioctl(struct file *file, IOCTL_CAPTURE_RD_PERIOD,struct capture_info *info);
      
    • 形参

      参数名称 描述
      file 设备节点
      IOCTL_CAPTURE_RD_PERIOD 命令
      info 存储捕获信息的结构体
    • 返回值

      返回值 描述
      0 成功
      other 失败

    5.4. IOCTL_CAPTURE_RD_PULSE

    • 功能

      获取 file 对应设备的当前脉冲计数并返回到 info 。

    • 声明

      ioctl(struct file *file, IOCTL_CAPTURE_RD_PULSE, struct capture_info *info);
      
    • 形参

      参数名称 描述
      file 设备节点
      IOCTL_CAPTURE_RD_PULSE 命令
      info 存储捕获信息的结构体
    • 返回值

      返回值 描述
      0 成功
      other 失败

    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接口使用说明规范使用