ADCMP使用参考
REVISION HISTORY¶
Revision No. | Description |
Date |
---|---|---|
1.0 | 09/06/2024 | |
1.1 | 04/10/2025 | |
1.2 | 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
-
配置CONFIG_SSTAR_ADCMP
-
配置CONFIG_ADC
-
配置DM_REGULATOR
-
配置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.c
中hal_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-ch
和inject-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
orsstar_adcmp_dma_sample_trigger
触发采样;如果使用了
sstar_adcmp_dma_sample_trigger
,sstar_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 datavalue 获取采样结果的指针, 获取 regular_ch_u8
中所有通道的采样值 -
返回值
返回值 描述 0 成功 EINVAL 失败 -
注意事项
第一次使用之前或者每次调用
sstar_adcmp_set_config
之后,都需要先调用一次sstar_adcmp_sample_sequence
orsstar_adcmp_dma_sample_trigger
触发采样;如果使用了
sstar_adcmp_dma_sample_trigger
,sstar_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接口不存在
-
检查DTS ADCMP节点的
status
是否为ok
-
检查kernel config是否配置,详见[6.1. Kernel Config配置]
Q2:SAR ADCMP采样结果没有与外部电压同步变化
-
引脚设为GPIO mode进行output high/low的试验,如果无法拉高拉低则有可能是硬件问题
-
检查采样触发方式是否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数据