ADCMP使用参考


REVISION HISTORY

Revision No.
Description
Date
1.0
  • Initial release
  • 09/06/2024
    1.1
  • 完善功能说明和FAQ描述
  • 04/10/2025
    1.2
  • 增加直接读取ADC数据及序列采样后的线性映射接口
  • 05/15/2025

    1. 概述

    逐次逼近型模数转换器(Successive Approximation ADC)采用的是一种反馈比较型电路结构。实现方式简要概述为:取一个数字量加到DAC上,可得到一个对应的输出模拟电压,将这个模拟电压和输入的模拟电压信号相比较,如果两者不相等,则调整所取的数字量,直到两个模拟电压相等为止,最后所取的这个数字量就是所求的转换结果。

    2. 关键字说明

    • ADCLP

      Analog-to-digital converter Low Precision,低精度(10bit)模数转换器

    • ADCMP

      Analog-to-digital converter Medium Precision,中精度(12bit)模数转换器

    • regular/inject

      不同的adc通道可以选择按不同的采样顺序加入regular序列或者inject序列,inject序列采样优先级高于regular序列

    • 基准电压

      用于模数转换计算时使用的参考电压,也是最大量程,若基准电压设定为1.8v,当外部输入电压>=1.8v时,数字量达到最大值4095

    3. 功能描述

    SAR ADCMP采样精度为12bit,硬件设计为2组,下文使用group0和group1区分,其中group0属于pm domain,group1属于nonpm domain

    3.1. group0功能描述

    • 支持22个adc通道采样,可同时使用regular序列及inject序列

    • regular序列最多配置23个adc通道(group0共计22个通道,富余的1个通道可以选择不配置,也可以选择配置为重复的通道),inject序列最多配置12个adc通道(采样优先级大于regular序列,但非dma模式下不建议与regular序列的通道重合)

    • regular序列支持15种采样触发方式,inject序列支持14种采样触发方式

    • 采样频率 = 时钟源 / 16,可选时钟源为24M和12M(采样频率的倒数为硬件上采集一个数据点的时间)

    • 支持1.5V、1.8V共计2个档位基准电压

    3.2. group1功能描述

    • 支持2个adc通道采样,且不可同时使用regular序列及inject序列,只能二选一

    • regular序列最多配置23个adc通道(group1共计2个通道,富余的21个通道可以选择不配置,也可以选择配置为重复的通道),inject序列最多配置12个adc通道(富余的10个通道可以选择不配置,也可以选择配置为重复的通道,但不支持与regular序列同时使用)

    • regular序列支持3种采样触发方式,inject序列支持2种采样触发方式

    • 采样频率 = 时钟源 / N,可选时钟源为80M、24M、12M、6M;当采样模式为conversion时, N=15;当采样模式为sequence时, N=16(采样频率的倒数为硬件上采集一个数据点的时间)

    • 支持1.8V的基准电压

    3.3. 触发方式说明

    adcmp支持的触发方式汇总

    NO. 触发方式 group0-regular group0-inject group1-regular group1-inject
    0 pwm12_out_p
    ×
    ×
    1 pwm12_out_n
    ×
    ×
    2 pwm13_out_p
    ×
    ×
    3 pwm13_out_n
    ×
    ×
    4 pwm14_out_p
    ×
    ×
    5 pwm14_out_n
    ×
    ×
    6 pwm15_out_p
    ×
    ×
    7 pwm15_out_n
    ×
    ×
    8 pwm16_out_p
    ×
    ×
    9 pwm16_out_n
    ×
    ×
    10 pwm17_out_p
    ×
    ×
    11 pwm17_out_n
    ×
    ×
    12 sw trigger
    13 external trigger
    14 freerun
    ×
    ×

    pwm_out_p:基于dead time设定后生成的正向PWM波,regular序列的采样时机是pwm_out_p波形的上升沿,inject序列的采样时机是pwm周期的起点,如图所示:

    pwm_out_n:基于dead time设定后生成的反向PWM波,regular序列的采样时机是pwm_out_n波形的上升沿,inject序列的采样时机是pwm周期的起点,如图所示:

    sw trigger:通知指令下达至寄存器,一次指令trigger后硬件执行一次采样

    external trigger:指定PIN脚,拉低拉高后触发上升沿脉冲后硬件执行一次采样

    freerun:不间断采样,采样方法如果是conversion,那么支持采样多个数据并输出平均值,同时可设定采样间隔

    3.4. 采样方法说明

    adcmp采样可选择conversion和sequence两种不同的方法

    conversion:每次触发源会触发硬件采样一个通道

    • conversion + pwm_out_p触发源:每个pwm周期的上升沿触发一次采样并采集一个通道的数据
    • conversion + sw trigger触发源:每执行一次sw trigger,触发一次采样并采集一个通道的数据
    • conversion + external trigger触发源:每执行一次external trigger,触发一次采样并采集一个通道的数据
    • conversion + freerun触发源:触发一次后进行不间断采样,支持平均采样和设定每个通道的硬件采样间隔

    sequence:每次触发源会触发硬件采样一整个序列的所有通道

    • sequence + pwm_out_p触发源:每个pwm周期的上升沿触发一次采样并采集一整个序列所有通道的数据
    • sequence + sw trigger触发源:每执行一次sw trigger,触发一次采样并采集一整个序列所有通道的数据
    • sequence + external trigger触发源:每执行一次external trigger,触发一次采样并采集一整个序列所有通道的数据
    • sequence + freerun触发源:触发一次后进行不间断采样,不支持平均采样,也不支持设定每个通道的硬件采样间隔

    3.5. 计算说明

    SAR ADCMP的主要功能是将模拟信号转换为相应的数字信号,即可以将输入电压转换为数字量存储于寄存器中,通过公式计算出输入电压,

    计算公式:电压 = ( 寄存器数值 / 采样精度12bit )* 基准电压

    即如果读到的数值是0x4B0,可得电压为0x4B0/0xFFF *1.8=0.53v左右

    4. 硬件连接介绍

    SAR ADCMP不同group下的不同通道与PAD的对应关系:

    Group0 Channel Index Pad Name
    0 PAD_SAR_ADC0_00
    1 PAD_SAR_ADC0_01
    2 PAD_SAR_ADC0_02
    3 PAD_SAR_ADC0_03
    4 PAD_SAR_ADC0_04
    5 PAD_SAR_ADC0_05
    6 PAD_SAR_ADC0_06
    7 PAD_SAR_ADC0_07
    8 PAD_SAR_ADC0_08
    9 PAD_SAR_ADC0_09
    10 PAD_SAR_ADC0_10
    11 PAD_SAR_ADC0_11
    12 PAD_SAR_ADC0_12
    13 PAD_SAR_ADC0_13
    14 PAD_SAR_ADC0_14
    15 PAD_SAR_ADC0_11
    16 PAD_PM_GPIO0
    17 PAD_PM_GPIO1
    18 PAD_PM_GPIO3
    19 PAD_PM_GPIO6
    20 PAD_PM_ADC00_IN
    21 PAD_PM_GPIO7
    Group1 Channel Index Pad Name
    0 PAD_PWM_OUT00
    1 PAD_PWM_OUT01

    以PAD_SAR_ADC0_00为例,硬件连接时,查看原理图定位引脚位置,将外部电压接入引脚PAD_SAR_ADC0_00,如下图所示:

    5. Uboot用法介绍

    5.1. Uboot Config配置

    查看Kconfig可以看到支持ADCMP需要配置CONFIG_SSTAR_ADCMLP、CONFIG_ADC、CONFIG_CMD_ADC,其中开启CONFIG_CMD_ADC需要先配置DM_REGULATOR

    1. 配置CONFIG_SSTAR_ADCMP

    2. 配置CONFIG_ADC

    3. 配置DM_REGULATOR

    4. 配置CONFIG_CMD_ADC

    5.2. DTS配置

    SAR ADCMP的DTS配置只需要在chipname.dtsi中配置如下信息:

    adcmp0: adcmp0 {
        compatible = "sstar,adcmp";
        reg = <0x1F00AC00 0x200>, <0x1F00AE00 0x200>, <0x1F003C00 0x200>,<0x1F204600 0x200>, <0x1F203E00 0x200>;
        group = <0>;
        //1500mv 1800mv
        ref-voltage = <1800>;
        //24M 12M
        clock-freq = <24000000>;
        regular-method = <0>;
        inject-method = <0>;
        trigger-source = <12 12>; //sw trigger
        regular-ch = <0 1 2 3 4 5 6 7 8 9 10 11>;
        inject-ch = <12 13 14 15 16 17 18 19 20 21>;
        status = "okay";
    };
    
    adcmp1: adcmp1 {
        compatible = "sstar,adcmp";
        reg = <0x1F203600 0x200>, <0x1F203A00 0x200>, <0x1F200E00 0x200>, <0x1F204600 0x200>, <0x1F203E00 0x200>;
        group = <1>;
        //1800mv
        ref-voltage = <1800>;
        //24M 12M 6M 80M
        clock-freq = <80000000>;
        regular-method = <0>;
        inject-method = <0>;
        trigger-source = <12>; //sw trigger
        regular-ch = <0 1>;
        status = "okay";
    };
    

    SAR ADCMP DTS配置说明:

    属性 描述 设定值 备注
    compatible 匹配驱动进行注册 "sstar,adcmp" 禁止修改
    reg 设定寄存器bank地址 禁止修改
    group 设定group 0、1 禁止修改
    ref-voltage 设定基准电压挡位 以mv为单位,group0可选1500、1800,group1只能设定1800 可根据需要修改
    clock-freq 设定时钟频率 可切换时钟频率变更采样时间,group0可选24M、12M,group1可选024M、12M、6M、80M 可根据需要修改
    regular-method 设定regular序列的采样模式 0:conversion, 1:sequence 可根据需要修改
    inject-method 设定inject序列的采样模式 0:conversion, 1:sequence 可根据需要修改
    trigger-source 设定regular序列和inject序列的采样触发源 参数可参考触发方式说明 禁止修改
    regular-ch 设定regular序列的adc采样通道 最多设定23个adc通道,按照采样顺序从左至右排列 可根据需要修改
    inject-ch 设定inject序列的adc采样通道 最多设定12个adc通道,按照采样顺序从左至右排列 可根据需要修改
    status 选择是否使能驱动 "okay" or "disable" 可根据需要修改

    5.3. Uboot cmd参数说明及使用实例

    • 命令行输入adc

    • adc list → 可查看sar adcmp是否有绑定

    • adc info adcmp0 → 可查看adcmp0支持的channel数量及data精度

      如下图,adcmp0支持的channel数量为22(注意区分mask为0x3fffff),最大data值为0xfff

    • adc single adcmp0 [channel] → 可查看adcmp0具体某个channel的data

      如下图,channel 0的数值为1252

      根据公式:电压 = (data / 0xfff)* 基准电压

      此时电压为1252 / 4095 * 1.8 V = 0.550V

    • adc scan adcmp0 [channel mask] → 可查看多个channel的data

      adc scan adcmp0 :查看所有channel的data

      adc scan adcmp0 0x3:查看adcmp0 channel 0和channel 1的data

    6. Kernel用法介绍

    6.1. Kernel Config配置

    SAR ADCMP关联的驱动模块Config:

    • CONFIG_IIO

    • CONFIG_IRQ_WORK

    • CONFIG_IIO_BUFFER

    • CONFIG_IIO_TRIGGER

    • CONFIG_IIO_TRIGGERED_BUFFER

    SAR ADCMP驱动enable需要选择如下配置:

    Device Drivers --->
    
        [*] Sstar SoC platform drivers --->
    
            <*> Sstar ADCMP driver
    

    6.2. DTS配置

    SAR ADCMP的DTS配置只需要在chipname.dtsi中配置如下信息:

    adcmp0: adcmp@1f00ac00 {
        compatible = "sstar,adcmp";
        reg = <0x0 0x1F00AC00 0x0 0x200>, <0x0 0x1F00AE00 0x0 0x200>, <0x0 0x1F003C00 0x0 0x200>, <0x0 0x1F204600 0x0 0x200>, <0x0 0x1F203E00 0x0 0x200>;
        clocks = <&CLK_pm_pwm_adc>;
        interrupt-parent = <&sstar_pm_main_intc>;
        interrupts = <INT_PMSLEEP_FIQ_ADC>;
        interrupts-enable;
        group = <0>;
        //dma-enable;
        //dma-count = <50>;
        ref-voltage = <1800>;//1.5V 1.8V
        //0:24M 1:12M
        clk-select = <0>;
        regular-method = <0>;
        inject-method = <0>;
        regular-ch = <0 1 2 3 4 5 6 7 8 9 10 11>;
        inject-ch = <12 13 14 15 16 17 18 19 20 21>;
        upper-bound = <0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF
                        0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF>;
        lower-bound = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
        status = "okay";
    };
    
    adcmp1: adcmp@1f203600 {
        compatible = "sstar,adcmp";
        reg = <0x0 0x1F203600 0x0 0x200>, <0x0 0x1F203A00 0x0 0x200>, <0x0 0x1F200E00 0x0 0x200>, <0x0 0x1F204600 0x0 0x200>, <0x0 0x1F203E00 0x0 0x200>;
        clocks = <&CLK_pwm_adc>;
        interrupts = <GIC_SPI INT_FIQ_ADCMP IRQ_TYPE_LEVEL_HIGH>;
        interrupts-enable;
        group = <1>;
        //dma-enable;
        //dma-count = <50>;
        ref-voltage = <1800>; //only support 1.8V
        //0->24M, 1->12M, 2->6M, 3->80M
        clk-select = <3>;
        regular-method = <0>;
        inject-method = <0>;
        regular-ch = <0 1>;
        upper-bound = <0xFFFF 0xFFFF>;
        lower-bound = <0 0>;
        status = "okay";
    };
    
    属性 描述 设定值 备注
    compatible 匹配驱动进行注册 "sstar,adcmp" 禁止修改
    interrupt-parent 绑定中断控制器 &sstar_pm_main_intc 禁止修改
    interrupts 绑定中断号 INT_PMSLEEP_FIQ_ADC & INT_FIQ_ADCMP 禁止修改
    interrupts-enable 使能中断 bool,不配置即disable 可根据需要修改
    reg 设定寄存器bank地址 禁止修改
    clocks 设定时钟源 CLK_pm_pwm_adc & CLK_pwm_adc 禁止修改
    group 设定group 0、1 禁止修改
    dma-enable 使能dma bool,不配置即disable,使用dma需要先使能中断 可根据需要修改
    dma-count dma采样数量 必须是偶数 可根据需要修改
    ref-voltage 设定基准电压挡位 以mv为单位,group0可选1500、1800,group1只能设定1800 可根据需要修改
    clk-select 设定时钟源 可切换时钟源变更采样时间,group0可选0->24M、1->12M,group1可选0->24M、1->12M、2->6M、3->80M 可根据需要修改
    regular-method 设定regular序列的采样模式 0:conversion, 1:sequence 可根据需要修改
    inject-method 设定inject序列的采样模式 0:conversion, 1:sequence 可根据需要修改
    regular-ch 设定regular序列的adc采样通道 最多设定23个adc通道,按照采样顺序从左至右排列 可根据需要修改
    inject-ch 设定inject序列的adc采样通道 最多设定12个adc通道,按照采样顺序从左至右排列 可根据需要修改
    upper-bound 设定阈值上限电压 0~0xFFFF 可根据需要修改
    lower-bound 设定阈值下限电压 0~0xFFFF 可根据需要修改
    status 是否使能驱动 "ok" or "disable" 可根据需要修改

    以DMA采样功能举例,若按照如下DTS配置:

    adcmp0: adcmp@1f00ac00 {
        ......
        interrupt-parent = <&sstar_pm_main_intc>;
        interrupts = <INT_PMSLEEP_FIQ_ADC>;
        interrupts-enable;  //DMA功能必须使能中断
        group = <0>;
        dma-enable;         //使能DMA
        dma-count = <200>;  //每次触发采样,会连续采集200个ADC数据
        ref-voltage = <1800>;//1.5V 1.8V
        //0:24M 1:12M
        clk-select = <0>;
        regular-method = <0>;
        inject-method = <0>;
        regular-ch = <0 1 2 3 4 5>;
        inject-ch = <12 13 14 15>;
        ......
    };
    

    影响DMA采样结果的配置如下:

    clk-select = <0>:采样频率 = 24M / 16 = 1.5M hz,因此每个ADC数据的采样间隔 = 1000000000 / 1.5M = 667ns

    dma-count = <200>:每次DMA触发后采集200个ADC数据,因此每次DMA触发后硬件采样的总时间为667ns * 200 = 133400ns

    regular-ch = <0 1 2 3 4 5>, inject-ch = <12 13 14 15>:采集的200个数据中包含了channel0、1、2、3、4、5、12、13、14、15的ADC数据, 由于inject序列优先级更高,因此采样结果按照channel 12 -> channel 13 -> channel 14 -> channel 15 -> channel 0 -> channel 1 -> channel 2 -> channel 3 -> channel 4 -> channel 5....顺序排列

    adcmp1: adcmp@1f203600 {
        ......
        interrupts = <GIC_SPI INT_FIQ_ADCMP IRQ_TYPE_LEVEL_HIGH>;
        interrupts-enable; //DMA功能必须使能中断
        group = <1>;
        dma-enable;        //使能DMA
        dma-count = <400>; //每次触发采样,会连续采集400个ADC数据
        ref-voltage = <1800>; //only support 1.8V
        //0->24M, 1->12M, 2->6M, 3->80M
        clk-select = <3>;
        regular-method = <1>;
        inject-method = <1>;
        regular-ch = <0 1>;
        ......
    };
    

    影响DMA采样结果的配置如下:

    clk-select = <3>,regular-method = <1>:采样频率 = 80M / 16 = 5M hz (如果regular-method = <0>, 那么采样频率 = 80M / 15 = 5.33M hz) ,因此每个ADC数据的采样间隔 = 1000000000 / 5M = 200ns

    dma-count = <400>:每次DMA触发后采集400个ADC数据,因此每次DMA触发后硬件采样的总时间为200ns * 400 = 80000ns

    regular-ch = <0 1>:采集的400个数据中包含了channel0和channle1的ADC数值,按照channel 0 -> channel 1 -> channel 0 -> channel 1 -> ....顺序排列

    6.3. Padmux配置

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

    //pm adc 22ch
    <PAD_SAR_ADC0_00  PINMUX_FOR_PMADC0_MODE_1 MDRV_PUSE_PWMADC0>,
    <PAD_SAR_ADC0_01 PINMUX_FOR_PMADC1_MODE_1 MDRV_PUSE_PWMADC1>,
    <PAD_SAR_ADC0_02 PINMUX_FOR_PMADC2_MODE_1 MDRV_PUSE_PWMADC2>,
    <PAD_SAR_ADC0_03  PINMUX_FOR_PMADC3_MODE_1 MDRV_PUSE_PWMADC3>,
    <PAD_SAR_ADC0_04 PINMUX_FOR_PMADC4_MODE_1 MDRV_PUSE_PWMADC4>,
    <PAD_SAR_ADC0_05  PINMUX_FOR_PMADC5_MODE_1 MDRV_PUSE_PWMADC5>,
    <PAD_SAR_ADC0_06  PINMUX_FOR_PMADC6_MODE_1 MDRV_PUSE_PWMADC6>,
    <PAD_SAR_ADC0_07  PINMUX_FOR_PMADC7_MODE_1 MDRV_PUSE_PWMADC7>,
    <PAD_SAR_ADC0_08 PINMUX_FOR_PMADC8_MODE_1 MDRV_PUSE_PWMADC8>,
    <PAD_SAR_ADC0_09  PINMUX_FOR_PMADC9_MODE_1 MDRV_PUSE_PWMADC9>,
    <PAD_SAR_ADC0_10 PINMUX_FOR_PMADC10_MODE_1 MDRV_PUSE_PWMADC10>,
    <PAD_SAR_ADC0_11  PINMUX_FOR_PMADC11_MODE_1 MDRV_PUSE_PWMADC11>,
    <PAD_SAR_ADC0_12 PINMUX_FOR_PMADC12_MODE_1 MDRV_PUSE_PWMADC12>,
    <PAD_SAR_ADC0_13  PINMUX_FOR_PMADC13_MODE_1 MDRV_PUSE_PWMADC13>,
    <PAD_SAR_ADC0_14  PINMUX_FOR_PMADC14_MODE_1 MDRV_PUSE_PWMADC14>,
    <PAD_PM_GPIO0   PINMUX_FOR_PMADC15_MODE_1 MDRV_PUSE_PWMADC15>,
    <PAD_PM_GPIO1     PINMUX_FOR_PMADC16_MODE_1 MDRV_PUSE_PWMADC16>,
    <PAD_PM_GPIO2     PINMUX_FOR_PMADC17_MODE_1 MDRV_PUSE_PWMADC17>,
    <PAD_PM_GPIO3     PINMUX_FOR_PMADC18_MODE_1 MDRV_PUSE_PWMADC18>,
    <PAD_PM_GPIO6      PINMUX_FOR_PMADC19_MODE_1 MDRV_PUSE_PWMADC19>,
    <PAD_PM_ADC00_IN PINMUX_FOR_PMADC20_MODE_1 MDRV_PUSE_PWMADC20>,
    <PAD_PM_GPIO7     PINMUX_FOR_PMADC21_MODE_1 MDRV_PUSE_PWMADC21>,
    <PAD_PM_PWM0_OUT    PINMUX_FOR_PM_ADC_INT_MODE_2 MDRV_PUSE_PMPWMADC_INT>,
    
    //non pm adc 2ch
    <PAD_PWM_OUT00     PINMUX_FOR_ADC0_MODE_1 MDRV_PUSE_PWMADC22>,
    <PAD_PWM_OUT01     PINMUX_FOR_ADC1_MODE_1 MDRV_PUSE_PWMADC23>,
    <PAD_GPIOA_12 PINMUX_FOR_PWM_INT_MODE_1 MDRV_PUSE_PWMADC_INT>,
    <PAD_GPIOA_13 PINMUX_FOR_PWM_INT_MODE_1 MDRV_PUSE_PWMOUT_INT>,
    

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

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

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

    6.4. 模块使用介绍

    6.4.1. SYSFS接口

    各文件接口的使用介绍

    名称 描述 参数 备注
    regular 设定regular序列的采样触发方式及使能 echo [trigger mode] [enable]> regular trigger mode的参数可参考触发方式说明
    inject 设定inject序列的采样触发方式及使能 echo [trigger mode] [enable]> inject trigger mode的参数可参考触发方式说明
    threshold 电压的上下限设定 echo [adc channel] [upper] [lower]> threshold 采样的结果超出阈值范围会触发中断,但需要主动执行cat data
    trig_delay inject序列采样时可设置delay时间 echo [p_delay] [n_delay]> trig_delay 以count传参,delay时长为pwm source clock * count
    freerun 使能freerun触发模式并设定单通道的平均采样次数和延长采样间隔时间 echo [average count] [sample time] > freerun average count->单通道的平均采样次数,sample time->延长采样间隔(仅支持conversion下使用),若sample time = N,最终的采样间隔时间 = 基础采样时间 + 延长采样时间 = (1 / (时钟源 / 16)) + ( N / (时钟源 / 4))
    data 获取adc采样值 echo [adc channel] > data;cat data 不支持dma使能后获取data
    data_list 获取adc所有通道的采样值 cat data 先按照DTS里inject-ch定义的通道顺序显示,再按照DTS里regular-ch定义的通道顺序显示,不支持dma使能后获取data

    请注意:采样的触发方式如果使用0~11,需要先设置对应的pwm dead time,以0:pwm12_out_p为例

    1.     #设定pwm dead time,跳转到pwm12路径
    2.     cd sys/class/sstar/pwm/group3/pwm12
    3.
    4.     #设置参数输出1000HZ,50%占空比,极性normal的波形,dead time生效前必须先设定pwm波形
    5.     echo 1000000  > period
    6.     echo 500000   > duty
    7.     echo normal   > polarity
    8.     echo 1        > enable
    9.
    10.    #设定pwm12的dead time,最终产生1000HZ,占空比分别为45%的正向波形和46%的反向波形
    11.    echo 50000 40000 > ddt
    12.    echo 1           > ddt_en
    13.
    14.    #跳转到adcmp0路径
    15.    cd sys/class/sstar/adcmp0/
    16.
    17.    #设置regular及inject采样触发方式
    18.    echo 0 1 > regular
    19.    echo 0 1 > inject
    20.    echo 0   > data
    21.    cat data
    22.    ......
    

    6.4.2. IOCTL使用方法

    头文件<drv_adcmp.h>位于kernel/driver/sstar/sar目录下,

    • IOCTL_ADCMP_SET_BOUND

      设定adcmp的阈值范围

    • IOCTL_ADCMP_SET_CONFIG

      设定adcmp的采样属性

    • IOCTL_ADCMP_GET_CONFIG

      获取当前adcmp的采样属性

    • IOCTL_ADCMP_CHANNEL_READ

      获取当前adcmp中某个通道的采样结果

    • IOCTL_ADCMP_SEQUENCE_READ

      获取DTS定义的所有通道的采样结果,先获取inject-ch指定通道的采样值,后获取regular-ch指定通道的采样值

    struct adcmp_bound
    {
        u8  channel;     //指定adc通道
        u8  bound_en;    //使能阈值监测功能
        u16 lower_bd;    //阈值下限
        u16 upper_bd;    //阈值上限
    };
    
    struct adcmp_config
    {
        u8  inje_en;     //使能inject序列采样功能
        u8  inje_mod;    //inject序列采样触发方式
        u8  regu_en;     //使能regular序列采样功能
        u8  regu_mod;    //regular序列采样触发方式
        u8  avg_cnt;     //freerun时获取平均值的采样数量
        u32 p_delay;     //inject采样时pwm out p trigger的delay时间
        u32 n_delay;     //inject采样时pwm out n trigger的delay时间
        u16 sample_time; //freerun延长的采样间隔(仅支持coversion下使用),若sample time = N,最终的采样间隔时间 =  基础采样时间 + 延长采样时间 = (1 / (时钟源 / 16)) + ( N / (时钟源 / 4))
    };
    
    struct adcmp_info
    {
        u16  ch_data;    //变量channel指定通道的采样数值
        u8   channel;    //指定adc通道
        u16 *seq_data;   //承载DTS指定所有通道的采样数值
    };
    
    
    #define ADCMP_IOC_MAXNR 5
    
    #define ADCMP_IOC_MAGIC           'a'
    #define IOCTL_ADCMP_SET_BOUND     _IO(ADCMP_IOC_MAGIC, 0)
    #define IOCTL_ADCMP_SET_CONFIG    _IO(ADCMP_IOC_MAGIC, 1)
    #define IOCTL_ADCMP_GET_CONFIG    _IO(ADCMP_IOC_MAGIC, 2)
    #define IOCTL_ADCMP_CHANNEL_READ  _IO(ADCMP_IOC_MAGIC, 3)
    #define IOCTL_ADCMP_SEQUENCE_READ _IO(ADCMP_IOC_MAGIC, 4)
    

    6.5. Sample Code

    6.5.1. Ioctl

    源码位于kernel/driver/sstar/sar/ut/ut_adcmp.c

    #include <fcntl.h>
    #include <stdio.h>
    #include <errno.h>
    #include <signal.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #include <sys/stat.h>
    #include <sys/ioctl.h>
    #include <sys/types.h>
    #include <drv_adcmp.h>
    
    #define ADCMP_DMA_COUNT  50
    #define ADCMP_CHAN_COUNT 24
    
    void sample_warn(int num)
    {
        printf("adcmp data exceeding the threshold\n");
    }
    
    int main(int argc, char **argv)
    {
        int                 i;
        int                 fd;
        int                 ret;
        char                cmd;
        int                 flags;
        u8                  group;
        u32                 count;
        u8                  dma_en;
        u8                  channel;
        u8                  regu_mod;
        u8                  inje_mod;
        char                path[64];
        struct adcmp_info   info;
        struct adcmp_bound  adcmp_bd;
        struct adcmp_config adcmp_cfg;
    
        if ((argc != 5) && (argc != 6))
        {
            printf("format: ut_adcmp <once> [group] [channel] [regu_mode] [inje_mode]\n");
            printf("format: ut_adcmp <scan> [group] [dma_en] [regu_mode] [inje_mode]\n");
            return -1;
        }
    
        if (!strcmp(argv[1], "once"))
        {
            if (argc != 6)
            {
                printf("format: ut_adcmp <once> [group] [channel] [regu_mode] [inje_mode]\n");
                return -1;
            }
    
            group    = atoi(argv[2]);
            channel  = atoi(argv[3]);
            regu_mod = atoi(argv[4]);
            inje_mod = atoi(argv[5]);
            snprintf(path, sizeof(path), "/dev/adcmp%hhu", group);
            fd = open((const char *)(char *)path, O_RDWR);
            if (fd < 0)
            {
                printf("open device fail\n");
                return -1;
            }
    
            signal(SIGIO, sample_warn);
            fcntl(fd, F_SETOWN, getpid());
            flags = fcntl(fd, F_GETFL);
            fcntl(fd, F_SETFL, flags | FASYNC);
    
            adcmp_bd.channel  = channel;
            adcmp_bd.bound_en = 1;
            adcmp_bd.upper_bd = 2000;
            adcmp_bd.lower_bd = 1000;
            ret               = ioctl(fd, IOCTL_ADCMP_SET_BOUND, &adcmp_bd);
            if (ret)
            {
                printf("adcmp set bound fail\n");
                return ret;
            }
    
            adcmp_cfg.inje_en  = 1;
            adcmp_cfg.inje_mod = inje_mod;
            adcmp_cfg.p_delay  = 1000;
            adcmp_cfg.n_delay  = 1000;
    
            adcmp_cfg.regu_en     = 1;
            adcmp_cfg.regu_mod    = regu_mod;
            adcmp_cfg.avg_cnt     = 3;
            adcmp_cfg.sample_time = 15;
            ret                   = ioctl(fd, IOCTL_ADCMP_SET_CONFIG, &adcmp_cfg);
            if (ret)
            {
                printf("adcmp set config fail\n");
                return ret;
            }
    
            info.channel = channel;
            while (1)
            {
                cmd = getchar();
                if (cmd == 'q' || cmd == 'Q')
                {
                    break;
                }
    
                ret = ioctl(fd, IOCTL_ADCMP_CHANNEL_READ, &info);
                if (ret)
                {
                    printf("adcmp channel read fail\n");
                    return ret;
                }
                printf("adcmp%hhu channel[%hhu] data[%hu]\n", group, info.channel, info.ch_data);
            }
        }
        else if (!strcmp(argv[1], "scan"))
        {
            if (argc != 6)
            {
                printf("format: ut_adcmp <scan> [group] [dma_en] [regu_mode] [inje_mode]\n");
                return -1;
            }
    
            group    = atoi(argv[2]);
            dma_en   = atoi(argv[3]);
            regu_mod = atoi(argv[4]);
            inje_mod = atoi(argv[5]);
            snprintf(path, sizeof(path), "/dev/adcmp%hhu", group);
            fd = open((const char *)(char *)path, O_RDWR);
            if (fd < 0)
            {
                printf("open device fail\n");
                return -1;
            }
    
            adcmp_cfg.inje_en  = 1;
            adcmp_cfg.inje_mod = inje_mod;
            adcmp_cfg.p_delay  = 0;
            adcmp_cfg.n_delay  = 0;
    
            adcmp_cfg.regu_en     = 1;
            adcmp_cfg.regu_mod    = regu_mod;
            adcmp_cfg.avg_cnt     = 0;
            adcmp_cfg.sample_time = 0;
            ret                   = ioctl(fd, IOCTL_ADCMP_SET_CONFIG, &adcmp_cfg);
            if (ret)
            {
                printf("adcmp set config fail\n");
                return ret;
            }
    
            info.dma_en = dma_en;
            if (info.dma_en)
                count = ADCMP_DMA_COUNT;
            else
                count = ADCMP_CHAN_COUNT;
    
            info.seq_data = (unsigned short *)malloc(count * sizeof(unsigned short));
            while (1)
            {
                cmd = getchar();
                if (cmd == 'q' || cmd == 'Q')
                {
                    free(info.seq_data);
                    break;
                }
    
                ret = ioctl(fd, IOCTL_ADCMP_SEQUENCE_READ, &info);
                if (ret)
                {
                    printf("adcmp scan read fail\n");
                    return ret;
                }
    
                for (i = 0; i < count; i++)
                {
                    printf("adcmp%hhu sequence data[%hu]\n", group, info.seq_data[i]);
                }
            }
        }
        else
        {
            printf("format: ut_adcmp <once>\n");
            printf("format: ut_adcmp <scan>\n");
            return -1;
        }
    
        close(fd);
    
        return 0;
    }
    

    6.5.2. Kernel Mode

    #include <linux/kernel.h>
    #include <linux/module.h>
    #include <linux/moduleparam.h>
    #include <linux/platform_device.h>
    #include <linux/of.h>
    #include <linux/list.h>
    #include <drv_adcmp.h>
    #include <linux/slab.h>
    
    #define ADCMP_DMA_ENABLE 1
    #define ADCMP_DMA_TRIG   10
    #define ADCMP_DMA_COUNT  24
    
    ushort adcmp_bus = 0;
    module_param(adcmp_bus, ushort, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
    MODULE_PARM_DESC(adcmp_bus, "adcmp bus");
    ushort adcmp_ch = 0;
    module_param(adcmp_ch, ushort, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
    MODULE_PARM_DESC(adcmp_ch, "adcmp channel");
    
    static adcmp_cb_t cb_t;
    static u8 adcmp_dma_trig = 0;
    
    int adcmp_get_data(u8 group)
    {
        u8    i;
        int   ret       = 0;
        u16   count     = 0;
        u16  *seq_data  = NULL;
    
        count    = ADCMP_DMA_COUNT;
        seq_data = CamOsMemAlloc(count * sizeof(u16));
    
        printk("sample dma data count%hhu\n", adcmp_dma_trig);
        ret = sstar_adcmp_dma_sample_data(group, seq_data);
        if (ret)
            return ret;
    
        for (i = 0; i < count; i++)
        {
            printk("index[%hhu] data is[%hu]\n", i, seq_data[i]);
        }
    
        CamOsMemRelease(seq_data);
        adcmp_dma_trig++;
    
        if (adcmp_dma_trig != ADCMP_DMA_TRIG)
        {
            ret = sstar_adcmp_dma_sample_trigger(group);
            if (ret)
                return ret;
        }
        else
        {
            ret = sstar_adcmp_dma_sample_stop(group);
            if (ret)
                return ret;
    
            adcmp_dma_trig = 0;
        }
    
        return 0;
    }
    
    
    static int __init adcmp_test_init(void)
    {
        u8   i        = 0;
        int  ret      = 0;
        u8   dma      = 0;
        u16  value    = 0;
        u16 *seq_data = NULL;
        struct adcmp_config adcmp_cfg= {0};
    
    
        adcmp_cfg.inje_en  = 1;
        adcmp_cfg.inje_mod = 12;
        adcmp_cfg.p_delay  = 0;
        adcmp_cfg.n_delay  = 0;
    
        adcmp_cfg.regu_en     = 1;
        adcmp_cfg.regu_mod    = 14;
        adcmp_cfg.avg_cnt     = 0;
        adcmp_cfg.sample_time = 0;
    
        printk("adcmp%hu set config\n", adcmp_bus);
        ret = sstar_adcmp_set_config(&adcmp_cfg, adcmp_bus);
        if (ret)
        {
            printk("adcmp%hu config fail\n", adcmp_bus);
            return ret;
        }
    
        dma = ADCMP_DMA_ENABLE;
        if (!dma)
        {
            printk("adcmp%hu sample channel\n", adcmp_bus);
            ret = sstar_adcmp_sample_channel(adcmp_bus, adcmp_ch, &value);
            if (ret)
            {
                printk("adcmp%hu ch%hu sample fail\n", adcmp_bus, adcmp_ch);
                return ret;
            }
            printk("ch%hu value[%hu]\n", adcmp_ch, value);
    
            seq_data = (unsigned short *)kmalloc(ADCMP_DMA_COUNT * sizeof(unsigned short), GFP_KERNEL);
            ret = sstar_adcmp_sample_sequence(adcmp_bus, seq_data);
            if (ret)
            {
                printk("adcmp%hu sequence sample fail\n", adcmp_bus);
                return ret;
            }
    
            for (i = 0; i < ADCMP_DMA_COUNT; i++)
            {
                printk("index%hhu sequence data[%hu]\n", i, seq_data[i]);
            }
    
            kfree(seq_data);
        }
        else
        {
            cb_t = adcmp_get_data;
            ret = sstar_adcmp_register_callback(adcmp_bus, cb_t);
            if (ret)
            {
                printk("adcmp%hu register callback fail\n", adcmp_bus);
                return ret;
            }
    
            ret = sstar_adcmp_dma_sample_trigger(adcmp_bus);
            if (ret)
            {
                printk("adcmp%hu register callback fail\n", adcmp_bus);
                return ret;
            }
        }
    
    
        return 0;
    }
    
    static void __exit adcmp_test_exit(void)
    {
        u8 dma;
    
        dma = ADCMP_DMA_ENABLE;
        if (dma)
        {
            sstar_adcmp_dma_sample_stop(adcmp_bus);
            sstar_adcmp_unregister_callback(adcmp_bus, cb_t);
        }
    }
    
    module_init(adcmp_test_init);
    module_exit(adcmp_test_exit);
    

    7. API参考

    头文件<drv_adcmp.h>位于kernel/driver/sstar/sar目录下,

    #ifdef __KERNEL__
    typedef s32 (*adcmp_cb_t)(u8 group);
    
    int sstar_adcmp_get_ref_vol(u8 group, u32 *voltage);
    int sstar_adcmp_direct_read_ch(u8 group, u8 channel, u16 *value);
    int sstar_adcmp_direct_read_seq(u8 group, u8 linear_map, u16 *value);
    int sstar_adcmp_sample_channel(u8 group, u8 channel, u16 *value);
    int sstar_adcmp_sample_sequence(u8 group, u16 *value);
    int sstar_adcmp_sample_seq_linear_map(u8 group, u16 *value);
    int sstar_adcmp_set_bound(struct adcmp_bound *adcmp_bd, u8 group);
    int sstar_adcmp_set_config(struct adcmp_config *adcmp_cfg, u8 group);
    int sstar_adcmp_get_config(struct adcmp_config *adcmp_cfg, u8 group);
    int sstar_adcmp_dma_sample_trigger(u8 group);
    int sstar_adcmp_dma_sample_stop(u8 group);
    int sstar_adcmp_dma_sample_data(u8 group, u16 *value);
    int sstar_adcmp_register_callback(u8 group, adcmp_cb_t cb_t);
    int sstar_adcmp_unregister_callback(u8 group, adcmp_cb_t cb_t);
    #endif
    
    API名称 功能
    sstar_adcmp_get_ref_vol 获取当前使用的基准电压
    sstar_adcmp_direct_read_ch 直接获取指定单个通道的外部输入电压数字量,不保证实时性
    sstar_adcmp_direct_read_seq 在不使能dma时,直接获取regular序列所有通道的外部输入电压数字量,不保证实时性
    sstar_adcmp_sample_channel 获取指定单个通道的外部输入电压数字量
    sstar_adcmp_sample_sequence 在不使能dma时,获取DTS指定所有通道的外部输入电压数字量
    sstar_adcmp_sample_seq_linear_map 在不使能dma时,实时获取sysdesc指定所有通道的外部输入电压数字量,并将通道和数据做线性映射
    sstar_adcmp_set_bound 设定指定通道的阈值
    sstar_adcmp_set_config 设定采样属性
    sstar_adcmp_get_config 获取采样属性
    sstar_adcmp_dma_sample_trigger 触发dma模式下的采样功能
    sstar_adcmp_dma_sample_stop 停止dma模式下的采样功能
    sstar_adcmp_dma_sample_data 获取dma模式下的采样结果
    sstar_adcmp_register_callback 注册指定group的回调函数
    sstar_adcmp_unregister_callback 释放指定group的回调函数和注册时申请的内存

    API详细说明:

    sstar_adcmp_sample_channel

    • 目的

      获取指定单个通道的外部输入电压数字量

    • 语法

      int sstar_adcmp_sample_channel(u8 group, u8 channel, u16 *value)
      
    • 参数

      参数名称 描述
      group 0或1
      channel 指定通道,注意需要是DTS中属性regular-chinject-ch的成员
      value 获取采样结果的指针地址
    • 返回值

      返回值 描述
      0 成功
      EINVAL 失败

    sstar_adcmp_sample_sequence

    • 目的

      在不使能dma时,获取DTS指定所有通道的外部输入电压数字量

    • 语法

      int sstar_adcmp_sample_sequence(u8 group, u16 *value)
      
    • 参数

      参数名称 描述
      group 0或1
      value 获取采样结果的指针地址,先获取inject-ch指定通道的采样值,后获取regular-ch指定通道的采样值
    • 返回值

      返回值 描述
      0 成功
      EINVAL 失败

    sstar_adcmp_set_bound

    • 目的

      设定指定通道的阈值

    • 语法

      int sstar_adcmp_set_bound(struct adcmp_bound *adcmp_bd, u8 group)
      
    • 参数

      参数名称 描述
      adcmp_bd 阈值配置
      group 0或1
    • 返回值

      返回值 描述
      0 成功
      EINVAL 失败

    sstar_adcmp_set_config

    • 目的

      设定采样属性

    • 语法

      int sstar_adcmp_set_config(struct adcmp_config *adcmp_cfg, u8 group)
      
    • 参数

      参数名称 描述
      adcmp_cfg 属性配置
      group 0或1
    • 返回值

      返回值 描述
      0 成功
      非0 失败

    sstar_adcmp_get_config

    • 目的

      获取采样属性

    • 语法

      int sstar_adcmp_get_config(struct adcmp_config *adcmp_cfg, u8 group)
      
    • 参数

      参数名称 描述
      adcmp_config 属性配置
      group 0或1
    • 返回值

      返回值 描述
      0 成功
      EINVAL 失败

    sstar_adcmp_dma_sample_trigger

    • 目的

      触发dma模式下的采样功能

    • 语法

      int sstar_adcmp_dma_sample_trigger(u8 group)
      
    • 参数

      参数名称 描述
      group 0或1
    • 返回值

      返回值 描述
      0 成功
      EINVAL 失败

    sstar_adcmp_dma_sample_stop

    • 目的

      停止dma模式下的采样功能

    • 语法

      int sstar_adcmp_dma_sample_stop(u8 group)
      
    • 参数

      参数名称 描述
      group 0或1
    • 返回值

      返回值 描述
      0 成功
      EINVAL 失败

    sstar_adcmp_dma_sample_data

    • 目的

      获取dma模式下的采样结果,注意每次刷新采样结果都需要先调用sstar_adcmp_dma_sample_trigger

    • 语法

      int sstar_adcmp_dma_sample_data(u8 group, u16 *value)
      
    • 参数

      参数名称 描述
      group 0或1
      value 获取dma采样结果的指针地址,先获取inject-ch指定通道的采样值,后获取regular-ch指定通道的采样值
    • 返回值

      返回值 描述
      0 成功
      EINVAL 失败

    sstar_adcmp_register_callback

    • 目的

      注册指定group的回调函数,当dma采样完成后可在回调函数里调用sstar_adcmp_dma_sample_data获取采样结果

    • 语法

      int sstar_adcmp_register_callback(u8 group, adcmp_cb_t cb_t)
      
    • 参数

      参数名称 描述
      group 0或1
      cb_t 函数指针
    • 返回值

      返回值 描述
      0 注册成功
      EINVAL 注册失败

    sstar_adcmp_unregister_callback

    • 目的

      释放指定group的回调函数和注册时申请的内存

    • 语法

      int sstar_adcmp_unregister_callback(u8 group, adcmp_cb_t cb_t)
      
    • 参数

      参数名称 描述
      group 0或1
      cb_t 函数指针
    • 返回值

      返回值 描述
      0 取消注册成功
      EINVAL 取消注册失败

    注意dma采样时的调用顺序:sstar_adcmp_set_config()->sstar_adcmp_register_callback()->sstar_adcmp_dma_sample_trigger()->回调函数中调用sstar_adcmp_dma_sample_data()

    sstar_adcmp_get_ref_vol

    • 目的

      获取当前使用的基准电压

    • 语法

      int sstar_adcmp_get_ref_vol(u8 group, u32 *voltage)
      
    • 参数

      参数名称 描述
      group 指定adcmp group
      voltage 基准电压,以mv为单位
    • 返回值

      返回值 描述
      0 成功
      EINVAL 失败

    sstar_adcmp_direct_read_ch

    • 目的

      直接获取指定单个通道的外部输入电压数字量,与sstar_adcmp_sample_channel区别在于direct read获取的结果不保证实时性,仅支持对regular序列的通道使用,且触发源不支持sw trigger和external trigger;

      硬件方面,regular序列的通道会按照既定顺序轮询采样,使用sstar_adcmp_sample_channel会确保是当前周期的采样结果,sstar_adcmp_direct_read_ch可能是上一个周期,当前周期,或者下一周期的采样结果(一个采样周期=regular序列通道数量*(1 / 采样频率),不包括inject序列抢占所需的采样时间)

      常用场景一般为使用DMA采集大量数据时,可在DMA采样结束前先获取某个通道的数据

    • 语法

      int sstar_adcmp_direct_read_ch(u8 group, u8 channel, u16 *value)
      
    • 参数

      参数名称 描述
      group 指定adcmp group
      channel 指定通道,必须是sysdesc中属性regular_ch_u8的成员
      value 获取采样结果的指针
    • 返回值

      返回值 描述
      0 成功
      EINVAL 失败
    • 注意事项

      第一次使用之前或者每次调用sstar_adcmp_set_config之后,都需要先调用一次sstar_adcmp_sample_channel or sstar_adcmp_dma_sample_trigger触发采样;

      如果使用了sstar_adcmp_dma_sample_triggersstar_adcmp_direct_read_ch只能获取DMA采样过程中的通道数据,当DMA采样结束后,sstar_adcmp_direct_read_ch拿到的数据不会更新,此时再调用sstar_adcmp_sample_channel即可恢复

    sstar_adcmp_direct_read_seq

    • 目的

      在不使能dma时,直接获取regular序列所有通道的外部输入电压数字量,与sstar_adcmp_sample_sequence区别在于direct read获取的结果不保证实时性,仅支持对regular序列的通道使用,且触发源不支持sw trigger和external trigger;

      硬件方面,regular序列的通道会按照既定顺序轮询采样,使用sstar_adcmp_sample_sequence会确保是当前周期的采样结果,sstar_adcmp_direct_read_seq可能是上一个周期,当前周期,或者下一周期的采样结果(一个采样周期=regular序列通道数量*(1 / 采样频率),不包括inject序列抢占所需的采样时间)

      常用场景一般为使用DMA采集大量数据时,可在DMA采样结束前先获取整个序列所有通道的数据

    • 语法

      int sstar_adcmp_direct_read_seq(u8 group, u8 linear_map, u16 *value)
      
    • 参数

      参数名称 描述
      group 指定adcmp group
      linear_map 0:value的数据排序根据sysdesc中regular_ch_u8定义的顺序,1:value的数据按照通道index从小到大排序,比如value[0]=channel 0 adc data
      value 获取采样结果的指针, 获取regular_ch_u8中所有通道的采样值
    • 返回值

      返回值 描述
      0 成功
      EINVAL 失败
    • 注意事项

      第一次使用之前或者每次调用sstar_adcmp_set_config之后,都需要先调用一次sstar_adcmp_sample_sequence or sstar_adcmp_dma_sample_trigger触发采样;

      如果使用了sstar_adcmp_dma_sample_triggersstar_adcmp_direct_read_seq只能获取DMA采样过程中的通道数据,当DMA采样结束后,sstar_adcmp_direct_read_seq拿到的数据不会更新,此时再调用sstar_adcmp_sample_sequence即可恢复

    sstar_adcmp_sample_seq_linear_map

    • 目的

      在不使能dma时,实时获取sysdesc指定所有通道的外部输入电压数字量,并将通道和数据做线性映射

    • 语法

      int sstar_adcmp_sample_seq_linear_map(u8 group, u16 *value)
      
    • 参数

      参数名称 描述
      group 指定adcmp group
      value 获取采样结果的指针, value的数据按照通道index从小到大排序,比如value[0] = channel 0 adc data, value[1] = channel 1 adc data
    • 返回值

      返回值 描述
      0 成功
      EINVAL 失败

    8. FAQ

    Q1:SAR ADCMP接口不存在

    1. 检查DTS ADCMP节点的status是否为ok

    2. 检查kernel config是否配置,详见[6.1. Kernel Config配置]

    Q2:SAR ADCMP采样结果没有与外部电压同步变化

    1. 引脚设为GPIO mode进行output high/low的试验,如果无法拉高拉低则有可能是硬件问题

    2. 检查采样触发方式是否ready,比如pwm out p需要配置pwm dead time并使能,external trigger需要电平产生变化触发上升沿,尤其是inject序列的触发方式未启动,那么regular序列也无法采样

    Q3:SAR ADCMP采样结果以256的倍数变化

    当某一ADC通道对应的PIN脚输入电压大于参考电压时,前一个通道的采样会受到干扰,采样结果只能是256的倍数

    adcmp0: adcmp@1f00ac00 {
        compatible = "sstar,adcmp";
        reg = <0x0 0x1F00AC00 0x0 0x200>, <0x0 0x1F00AE00 0x0 0x200>, <0x0 0x1F003C00 0x0 0x200>, <0x0 0x1F204600 0x0 0x200>, <0x0 0x1F203E00 0x0 0x200>;
        clocks = <&CLK_pm_pwm_adc>;
        interrupt-parent = <&sstar_pm_main_intc>;
        interrupts = <INT_PMSLEEP_FIQ_ADC>;
        interrupts-enable;
        group = <0>;
        //dma-enable;
        //dma-count = <50>;
        ref-voltage = <1800>;//1.5V 1.8V
        //0:24M 1:12M
        clk-select = <0>;
        regular-method = <0>;
        inject-method = <0>;
        regular-ch = <0 1 2 8 3 9 4 5 6 7 10 11 12 13 14 15 16 17 18 19 20 21>;
        upper-bound = <0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF 0xFFFF>;
        lower-bound = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
        status = "okay";
    };
    

    例如上述配置中,ref-voltage为1.8V,若通道8、通道9的输入电压大于1.8V,则通道2、通道3的采样结果会受到干扰,且只能是256的倍数。

    Q4:SAR ADCMP 在超声波场景下DMA采样时获取不到有效数据

    此场景需求输出PWM波形(蓝色)后,电压(黄色)才产生变化;

    如果没有报错,仅是采样数据不符合预期,需要查看DMA采样时机与电压变化时机是否匹配;

    如果此时使用adcmp0,可以选择pwm_out的触发方式(0~11),采样起点在第一个PWM波形的上升沿,可以保证同步采完所有ADC数据;

    如果此时使用adcmp1,由于没有pwm_out的触发方式,可以选择先trigger采样,然后在控制输出PWM波形,根据采样count控制采样总时长,也可采完所有ADC数据