DMA(直接内存访问)允许外设(如 ADC)直接与内存进行数据传输,无需 CPU 干预。在 WiFi 与 ADC 同时运行的场景中,DMA 的核心优势是:
减少 CPU 中断开销:ADC 采样完成后无需触发 CPU 中断,数据直接写入内存。
实现并行操作:WiFi 通信与 ADC 采样可同时进行,互不干扰。
避免数据丢失:DMA 支持循环缓冲区,确保高频采样时数据不丢失。
2. 关键 DMA 配置参数
以 STM32 系列 MCU 为例,DMA 配置需关注以下参数:
c
运行
// 示例:STM32的ADC+DMA配置
void ADC_DMA_Configuration(void) {
// 1. 启用ADC和DMA时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
// 2. 配置ADC为连续转换模式
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
ADC_Init(ADC1, &ADC_InitStructure);
// 3. 配置DMA通道(ADC1对应DMA1通道1)
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADC_Buffer;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = ADC_BUFFER_SIZE;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // 循环模式
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
// 4. 启用DMA和ADC
DMA_Cmd(DMA1_Channel1, ENABLE);
ADC_DMACmd(ADC1, ENABLE);
ADC_Cmd(ADC1, ENABLE);
}
关键参数说明:
循环模式(Circular Mode):DMA 完成缓冲区填充后自动从头开始,适合连续采样。
数据宽度匹配:确保DMA_PeripheralDataSize与 ADC 分辨率(如 12 位对应 HalfWord)一致。
高优先级:WiFi 通信可能使用 DMA,需合理分配优先级避免冲突。
3. 优化方法与实践建议
3.1 双缓冲区机制
使用双缓冲区交替存储 ADC 数据,避免 WiFi 与 DMA 访问冲突:
c
运行
#define ADC_BUFFER_SIZE 1024
uint16_t ADC_Buffer[2][ADC_BUFFER_SIZE]; // 双缓冲区
// 配置DMA使用双缓冲区
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_Buffer;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
3.2 中断优化
仅在缓冲区半满 / 全满时触发中断,减少 CPU 干预:
c
运行
// 启用DMA半传输和传输完成中断
DMA_ITConfig(DMA1_Channel1, DMA_IT_TC | DMA_IT_HT, ENABLE);
// 中断处理函数
void DMA1_Channel1_IRQHandler(void) {
if (DMA_GetITStatus(DMA1_IT_HT1)) {
// 处理前半部分缓冲区数据(可触发WiFi发送)
process_adc_data(ADC_Buffer[0], ADC_BUFFER_SIZE/2);
DMA_ClearITPendingBit(DMA1_IT_HT1);
}
if (DMA_GetITStatus(DMA1_IT_TC1)) {
// 处理后半部分缓冲区数据
process_adc_data(ADC_Buffer[0] + ADC_BUFFER_SIZE/2, ADC_BUFFER_SIZE/2);
DMA_ClearITPendingBit(DMA1_IT_TC1);
}
}
3.3 采样率与缓冲区大小平衡
高采样率(如 100kHz 以上):增大缓冲区(如 4096 字节),减少中断频率。
低采样率:使用较小缓冲区(如 512 字节),降低内存占用。
3.4 电源管理优化
在 STM32 中,可配置 ADC 为低功耗模式:
c
运行
// 配置ADC为低功耗模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // 单次转换后休眠
ADC_InitStructure.ADC_Prescaler = ADC_Prescaler_Div8; // 降低ADC时钟
4. 常见问题排查
数据丢失:
检查 DMA 缓冲区是否足够大,避免采样数据覆盖。
确保 WiFi 发送速度快于 ADC 采样速度。
CPU 占用率仍高:
检查中断处理函数是否执行耗时操作,可将数据处理移至后台任务。
调整 DMA 优先级,避免与 WiFi 冲突。
采样异常:
确认 ADC 与 DMA 时钟配置正确,避免时钟抖动。
使用示波器监测 ADC 输入信号是否稳定。
|