AD7606双通道数据采集实战:基于STM32 HAL库的SPI DMA方案与数据对齐处理
在工业数据采集和实验室测量场景中,AD7606作为一款高精度、多通道同步采样ADC芯片,配合STM32的SPI DMA功能,能够实现高效稳定的数据采集系统。本文将深入探讨如何利用STM32 HAL库的SPI DMA功能优化AD7606的数据采集流程,解决双通道模式下的数据对齐问题,并提供可直接复用的工程实践方案。
1. AD7606硬件配置与初始化
AD7606的硬件配置直接影响采样性能和精度。与传统的查询式SPI通信不同,DMA方案需要特别注意以下几个硬件参数:
- OS[2:0]引脚:配置过采样率,直接影响转换时间和数据吞吐量
- RANGE引脚:决定输入电压范围(±5V或±10V)
- CONVST引脚:启动转换的触发信号,在多通道同步时尤为关键
典型初始化代码如下:
void AD7606_Init(void) { // 配置过采样率为0(无过采样) HAL_GPIO_WritePin(OS0_GPIO_Port, OS0_Pin, GPIO_PIN_RESET); HAL_GPIO_WritePin(OS1_GPIO_Port, OS1_Pin, GPIO_PIN_RESET); HAL_GPIO_WritePin(OS2_GPIO_Port, OS2_Pin, GPIO_PIN_RESET); // 设置输入范围为±5V HAL_GPIO_WritePin(RANGE_GPIO_Port, RANGE_Pin, GPIO_PIN_RESET); // 复位芯片 HAL_GPIO_WritePin(RESET_GPIO_Port, RESET_Pin, GPIO_PIN_RESET); HAL_Delay(1); HAL_GPIO_WritePin(RESET_GPIO_Port, RESET_Pin, GPIO_PIN_SET); // 初始状态保持CONVST高电平 HAL_GPIO_WritePin(CONVST_GPIO_Port, CONVST_Pin, GPIO_PIN_SET); }注意:RESET脉冲宽度需至少50ns,在高主频STM32上可能需要插入NOP指令或使用硬件定时器确保时序。
2. SPI DMA配置与双通道数据采集
2.1 SPI外设配置
AD7606的SPI接口需要特定配置才能正常工作:
| 参数 | 配置值 | 说明 |
|---|---|---|
| 时钟极性(CPOL) | 1 | 空闲时SCK保持高电平 |
| 时钟相位(CPHA) | 1 | 数据在第二个边沿采样 |
| 数据大小 | 16位 | 匹配AD7606输出数据格式 |
| 片选管理 | 软件控制 | 确保转换完成后再读取数据 |
HAL库配置示例:
hspi2.Instance = SPI2; hspi2.Init.Mode = SPI_MODE_MASTER; hspi2.Init.Direction = SPI_DIRECTION_2LINES_RXONLY; hspi2.Init.DataSize = SPI_DATASIZE_16BIT; hspi2.Init.CLKPolarity = SPI_POLARITY_HIGH; hspi2.Init.CLKPhase = SPI_PHASE_2EDGE; hspi2.Init.NSS = SPI_NSS_SOFT; hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; HAL_SPI_Init(&hspi2);2.2 DMA双通道数据接收
双通道模式下,AD7606通过DOUTA和DOUTB同时输出两路数据。DMA配置需要考虑以下关键点:
- 内存地址递增:每个通道数据需要存储到不同内存位置
- 数据对齐:16位数据在内存中的排列方式
- 循环模式:适用于连续采集场景
DMA配置代码示例:
// DMA接收缓冲区定义 __ALIGN_BEGIN uint16_t adcData[2][8] __ALIGN_END; // 双通道,每通道8个样本 void AD7606_DMA_Config(void) { hdma_spi2_rx.Instance = DMA1_Stream0; hdma_spi2_rx.Init.Channel = DMA_CHANNEL_0; hdma_spi2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_spi2_rx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_spi2_rx.Init.MemInc = DMA_MINC_ENABLE; hdma_spi2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; hdma_spi2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; hdma_spi2_rx.Init.Mode = DMA_CIRCULAR; hdma_spi2_rx.Init.Priority = DMA_PRIORITY_HIGH; HAL_DMA_Init(&hdma_spi2_rx); __HAL_LINKDMA(&hspi2, hdmarx, hdma_spi2_rx); HAL_SPI_Receive_DMA(&hspi2, (uint8_t*)adcData, 16); // 16个16位数据 }3. 数据转换与校准处理
3.1 有符号补码转换
AD7606输出的是16位有符号补码数据,需要转换为实际电压值。转换步骤如下:
- 检查符号位(bit15)
- 负数时取反加1得到原码
- 根据RANGE设置计算实际电压
float AD7606_ConvertToVoltage(uint16_t rawData, uint8_t range) { int16_t signedValue = (int16_t)rawData; float voltage; if(range == AD7606_RANGE_5V) { voltage = signedValue * 5.0f / 32768.0f; } else { voltage = signedValue * 10.0f / 32768.0f; } return voltage; }3.2 双通道数据对齐
在DMA接收的双通道数据中,DOUTA和DOUTB的数据可能交错存储。典型的数据排列方式为:
缓冲区索引: 0 1 2 3 4 5 6 7 通道A数据: A0 A1 A2 A3 A4 A5 A6 A7 通道B数据: B0 B1 B2 B3 B4 B5 B6 B7处理代码示例:
void Process_DualChannel_Data(void) { float chA_voltage[8], chB_voltage[8]; for(int i=0; i<8; i++) { chA_voltage[i] = AD7606_ConvertToVoltage(adcData[0][i], currentRange); chB_voltage[i] = AD7606_ConvertToVoltage(adcData[1][i], currentRange); // 可在此处添加数据滤波或校准处理 } }4. 系统优化与异常处理
4.1 时序优化技巧
- CONVST信号触发:使用定时器输出比较模式产生精确的转换脉冲
- BUSY信号利用:配置为外部中断触发DMA传输开始
- SPI时钟优化:根据采样率选择最高可行的SPI时钟
定时器触发配置示例:
// 配置TIM2 CH1输出1kHz的CONVST脉冲 htim2.Instance = TIM2; htim2.Init.Prescaler = 84-1; // 1MHz计数频率 htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 1000-1; // 1kHz HAL_TIM_OC_Init(&htim2); TIM_OC_InitTypeDef sConfigOC; sConfigOC.OCMode = TIM_OCMODE_TOGGLE; sConfigOC.Pulse = 500; // 50%占空比 sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; HAL_TIM_OC_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1);4.2 常见问题排查
- 数据全为0x7FFF:检查参考电压和模拟输入连接
- 数据跳动大:确保电源去耦电容足够(推荐10μF钽电容+0.1μF陶瓷电容)
- DMA传输不完整:检查内存对齐和缓冲区大小设置
- 双通道数据错位:确认CONVST信号同步性,必要时增加微小延迟
提示:使用逻辑分析仪捕获SPI总线信号是调试时序问题的最有效方法,重点关注CS下降沿到第一个SCK边沿的时序关系。
5. 实际工程应用案例
在电机控制系统中的应用示例:
- 电流采样:通过分流电阻+运放接入AD7606
- 电压采样:直接测量直流母线电压(需分压)
- 同步采样:利用PWM定时器触发AD7606转换
关键配置代码:
void MX_ADC_Trigger_Config(void) { // 配置PWM定时器在周期中点触发AD7606 htim1.Instance = TIM1; htim1.Init.Prescaler = 0; htim1.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1; htim1.Init.Period = 1680-1; // 50kHz PWM, 中心对齐模式 HAL_TIM_PWM_Init(&htim1); TIM_MasterConfigTypeDef sMasterConfig; sMasterConfig.MasterOutputTrigger = TIM_TRGO_OC1REF; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig); // 连接TIM1_TRGO到CONVST引脚 HAL_GPIO_WritePin(CONVST_GPIO_Port, CONVST_Pin, GPIO_PIN_SET); }这种配置实现了PWM周期中点的精确电流采样,有效减少了开关噪声对采样结果的影响。