Continuous Mode
该示例通过使用 ADC 连续采样模式进行电压检测。
该示例还可配置宏 ADC_CONFIG_GDMA_MODE_EN
用于控制是否使用 DMA 进行数据搬运。
若未开启DMA搬运,则ADC采样完成之后触发 ADC_INT_FIFO_THD
中断,在中断函数内读取raw data并进行电压转换计算。
若开启DAM搬运,DMA将数据从ADC FIFO搬运至数组中,传输完成后触发 GDMA_INT_Transfer
中断。
环境需求
该示例支持以下开发套件:
Hardware Platforms |
Board Name |
---|---|
RTL87x2G HDK |
RTL87x2G EVB |
更多信息请参考快速入门。
硬件连线
连接P2_4和外部输入电压。
配置选项
该示例可配置的宏如下:
ADC_CONFIG_GDMA_MODE_EN
:配置该宏可选择是否使用DMA进行ADC采样数据搬运,1
表示使用DMA搬运,0
表示不使用DMA搬运。ADC_MODE_DIVIDE_OR_BYPASS
:配置该宏可选择ADC的电压采样范围,可选择的值如下。ADC_DIVIDE_MODE
:在Divide Mode下,ADC的采样电压值范围为0~3.3V。ADC_BYPASS_MODE
:在Bypass Mode下,ADC的采样电压值范围为0~0.9V。
编译和下载
该示例的工程路径如下:
Project file: samples\peripheral\adc\continuous_gdma\proj\rtl87x2g\mdk
Project file: samples\peripheral\adc\continuous_gdma\proj\rtl87x2g\gcc
请按照以下步骤操作构建并运行该示例:
打开工程文件。
按照 快速入门 中 编译APP Image 给出的步骤构建目标文件。
编译成功后,在路径
mdk\bin
或gcc\bin
下会生成 app binapp_MP_xxx.bin
文件。按下复位按键,开始运行。
测试验证
EVB启动后,在Debug Analyzer工具内观察log。
Start ADC Continuous Mode test !
ADC初始化配置:
若配置为
ADC_DIVIDE_MODE
,则会打印如下log。[ADC]ADC sample mode is divide mode !
若配置为
ADC_BYPASS_MODE
,则会打印如下log。[ADC]ADC sample mode is bypass mode !
ADC采样结束后,会在Debug Analyzer工具内打印采集得到的raw data和转换后的电压值。若开启宏
ADC_CONFIG_GDMA_MODE_EN
,则会打印DMA中断信息;若未开启宏ADC_CONFIG_GDMA_MODE_EN
,则会打印ADC中断信息。[io_adc]io_adc_voltage_calculate: ADC rawdata_0 = xxx, voltage_0 = xxxmV [io_adc]io_adc_voltage_calculate: ADC rawdata_1 = xxx, voltage_1 = xxxmV ...
代码介绍
该章节分为以下几个部分:
源码路径
工程路径:
sdk\samples\peripheral\adc\continuous_gdma\proj
源码路径:
sdk\samples\peripheral\adc\continuous_gdma\src
该工程的工程文件代码结构如下:
└── Project: continuous_gdma
└── secure_only_app
└── Device includes startup code
├── startup_rtl.c
└── system_rtl.c
├── CMSIS includes CMSIS header files
├── CMSE Library Non-secure callable lib
├── Lib includes all binary symbol files that user application is built on
└── rtl87x2g_io.lib
├── Peripheral includes all peripheral drivers and module code used by the application
├── rtl_rcc.c
├── rtl_pinmux.c
├── rtl_gdma.c
└── rtl_adc.c
└── APP includes the ble_peripheral user application implementation
├── main_ns.c
└── io_adc.c
初始化
初始化流程包括了 global_adc_init
board_adc_init
和 driver_adc_init
。
若开启宏 ADC_CONFIG_GDMA_MODE_EN
,则初始化中仍包含 driver_gdma_adc_init
。
global_adc_init
中包含了全局初始化。
执行
ADC_CalibrationInit()
函数进行ADC校准。初始化DMA接收数组
ADC_Recv_Buffer
。
board_adc_init
中包含了PAD设置。
配置PAD:设置引脚、SW模式、PowerOn、无内部上拉、输出失能。
driver_adc_init
包含了对ADC外设的初始化。
使能PCC时钟。
配置ADC的采样通道,配置通道0为P2_4单端模式,设置Bitmap为0x01。
若开启宏
ADC_CONFIG_GDMA_MODE_EN
,设置ADC_WaterLevel
。设置
ADC_DataWriteToFifo
为 ENABLE,将ADC采样数据存入FIFO,设置ADC_FifoThdLevel
。若开启Bypass Mode,执行函数
ADC_BypassCmd()
开启对应引脚的Bypass模式。配置ADC中断。
若开启宏
ADC_CONFIG_GDMA_MODE_EN
,配置ADC_INT_FIFO_RD_ERR
中断和ADC_INT_FIFO_OVERFLOW
中断。若未开启宏
ADC_CONFIG_GDMA_MODE_EN
,配置ADC_INT_FIFO_THD
中断。
RCC_PeriphClockCmd(APBPeriph_ADC, APBPeriph_ADC_CLOCK, ENABLE);
...
#if ADC_CONFIG_GDMA_MODE_EN
ADC_InitStruct.ADC_WaterLevel = 4;
#endif
ADC_InitStruct.ADC_DataWriteToFifo = ENABLE;
...
#if ADC_CONFIG_GDMA_MODE_EN
ADC_INTConfig(ADC, ADC_INT_FIFO_RD_ERR, ENABLE);
ADC_INTConfig(ADC, ADC_INT_FIFO_OVERFLOW, ENABLE);
#else
ADC_INTConfig(ADC, ADC_INT_FIFO_THD, ENABLE);
#endif
备注
ADC的Continuous模式下,数据默认存放至ADC FIFO中。
driver_gdma_adc_init
包含了对DMA搬运的初始化。
指定GDMA传输方向为外设到内存传输。
设置源地址为ADC FIFO,目的地址为
ADC_Recv_Buffer
。设置源端地址固定,目的端地址自增。
配置GDMA总传输完成中断
GDMA_INT_Transfer
。
GDMA_InitStruct.GDMA_DIR = GDMA_DIR_PeripheralToMemory;
GDMA_InitStruct.GDMA_SourceInc = DMA_SourceInc_Fix;
GDMA_InitStruct.GDMA_DestinationInc = DMA_DestinationInc_Inc;
GDMA_InitStruct.GDMA_SourceAddr = (uint32_t)(&(ADC->ADC_FIFO_READ));
GDMA_InitStruct.GDMA_DestinationAddr = (uint32_t)ADC_Recv_Buffer;
...
GDMA_INTConfig(ADC_GDMA_CHANNEL_NUM, GDMA_INT_Transfer, ENABLE);
...
功能实现
若开启宏
ADC_CONFIG_GDMA_MODE_EN
,在初始化完DMA后,执行GDMA_Cmd()
,开启DMA搬运。在ADC采样前执行
ADC_ClearFIFO()
清空ADC FIFO内数据。执行
ADC_Cmd()
,开始ADC采样。若开启宏
ADC_CONFIG_GDMA_MODE_EN
,DMA搬运结束后,进入GDMA中断函数。失能ADC连续采样模式。
对采样数据进行数据处理(详见第5点)。
重新设置GDMA搬运信息,包括源地址,目的地址,搬运长度。
重新使能GDMA搬运,清空ADC FIFO数据,重新使能ADC采样。
void ADC_GDMA_Channel_Handler(void)
{
ADC_Cmd(ADC, ADC_CONTINUOUS_MODE, DISABLE);
for (uint32_t i = 0; i < GDMA_TRANSFER_SIZE; i++)
{
...
}
GDMA_SetSourceAddress(ADC_GDMA_Channel, (uint32_t)(&(ADC->ADC_FIFO_READ)));
GDMA_SetDestinationAddress(ADC_GDMA_Channel, (uint32_t)(ADC_Recv_Buffer));
GDMA_SetBufferSize(ADC_GDMA_Channel, GDMA_TRANSFER_SIZE);
GDMA_ClearINTPendingBit(ADC_GDMA_CHANNEL_NUM, GDMA_INT_Transfer);
GDMA_Cmd(ADC_GDMA_CHANNEL_NUM, ENABLE);
ADC_ClearFIFO(ADC);
ADC_Cmd(ADC, ADC_CONTINUOUS_MODE, ENABLE);
}
若未开启宏
ADC_CONFIG_GDMA_MODE_EN
,ADC FIFO内的值达到Threshold时,触发ADC_INT_FIFO_THD
中断,进入ADC中断函数。执行
ADC_GetFIFODataLen()
读取FIFO中数据长度,执行ADC_ReadFIFOData()
函数读取FIFO内数据。执行
ADC_ClearFIFO()
清空ADC FIFO内数据。执行
ADC_GetVoltage()
函数,将采样数据转换为电压值。
if (ADC_GetINTStatus(ADC, ADC_INT_FIFO_THD) == SET)
{
ADC_Cmd(ADC, ADC_CONTINUOUS_MODE, DISABLE);
data_len = ADC_GetFIFODataLen(ADC);
ADC_ReadFIFOData(ADC, sample_data, data_len);
ADC_ClearFIFO(ADC);
...
ADC_Cmd(ADC, ADC_CONTINUOUS_MODE, ENABLE);
}
备注
当ADC FIFO溢出时触发 ADC_INT_FIFO_OVERFLOW
中断,进入中断处理函数 SAR_ADC_Handler
,清空ADC FIFO数据。
常见问题
若拿到的IC未经过FT校验,ADC则无法转换为正确的电压值。在log工具内会打印如下信息。
[ADC]ADC_CalibrationInit fail!
若ADC采样值不正确,则会打印错误状态信息。
[ADC]adc_sample_demo: ADC parameter or efuse data error! i = xxx, error_status = xxx