ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

ADS1278 24位同步采样ADC驱动开发:SPI时序与寄存器配置实战

ADS1278 24位同步采样ADC驱动开发:SPI时序与寄存器配置实战 简介针对德州仪器ADS1278这款高性能24位模数转换器的驱动开发资源以单文件C语言驱动代码为核心面向需要快速完成高精度多通道数据采集系统搭建的嵌入式软硬件工程师。ADS1278具备二十四位分辨率、低噪声与多通道同步采样等特性相应驱动程序覆盖芯片初始化、工作模式与采样速率配置、串行外设接口通信读写、转换结果读取、错误处理以及低功耗管理等关键环节并尽量抽象底层硬件细节可适应常见单片机平台方便直接移植或二次修改。资源压缩包共一个文件类型为C语言源文件包体仅三KB轻量易读便于开发者逐行理解寄存器操作与数据流逻辑。已有1304人学习下载适合正在设计工业自动化、电力监测或医疗监护设备的开发者参考也可作为后续扩展多通道同步采集系统的裸机驱动编写范本帮助缩短产品验证周期。1. ADS1278 这颗 24 位 ADC 值不值得折腾先看你要不要同步采样8 通道同时采样、24 位分辨率、内置数字滤波器的 ADC 在市面上选择并不多ADS1278 是其中存在感最强的一颗。它的每个通道都有一套完整的 delta-sigma 调制器和可编程抽取滤波器所以多通道之间没有轮询时间差振动监测、电力录波、多轴压力采集这类任务会优先考虑它。但第一次上手的人往往会在第一个晚上就遇到问题SPI 读回来的波形要么满幅跳变要么八通道数据串位示波器上 DRDY 和 SCLK 的时序看起来总是不对。这里有一个反直觉的点ADS1278 难的不是 24 位数据怎么读而是读之前你有没有把时钟、参考电压和滤波器模式想清楚。这颗芯片的接口看起来就是一个普通 SPI 从机但它的数据速率、输出格式和寄存器配置是耦合在一起的改一个抽取率SCLK 频率上限和 DRDY 间隔都会变。这篇文章适合用 STM32、ESP32 或者 ZYNQ 这类平台去接 ADS1278 的工程师我会从硬件引脚、SPI 时序、寄存器写到驱动代码骨架最后落到 ENOB 验证和几个最影响采集质量的坑上。2. 先解决 ADS1278 的电源、参考电压和时钟再谈驱动代码2.1 最小系统引脚分配与布局要点ADS1278 的引脚看起来多真正关系信号链的只有几组AINP/AINN 八个模拟输入对、AVDD/DVDD/IOVDD 三个电源域、SPI 接口的 SCLK/DIN/DOUT/CS以及两个状态和控制脚 DRDY、SYNC。MODE 引脚决定芯片使用 SPI 还是帧同步接口通常接固定电平不参与运行时切换。驱动开发的第一步不在代码里而在引脚映射。我一般会在原理图阶段就把 SCLK 和 AINx 分开布置模拟输入附近不走数字时钟线SCLK 与 DOUT 这两根线也不要贴着模拟输入走长距离平行线。理由不复杂delta-sigma 调制器工作在远高于输出速率的内部频率上任何数字边沿通过寄生电容耦合到输入引脚都会直接变成带内噪声而且是数字滤波器无法去除的那一种。对 24 位分辨率的系统来说PCB 布局造成的性能损失远比寄存器配错更难排查。SYNC 引脚要接到 MCU 的普通 GPIO不要在硬件上直接绑高电平。SYNC 用于复位内部数字滤波器和同步多片 ADC 的采样起点哪怕只接一颗芯片上电后也应该由 MCU 主动给一个低脉冲完成一次确定性的复位否则首次上电后第一个 DRDY 间隔可能不满足你期望的采样率。DRDY 必须接到 MCU 的 EXTI 引脚不建议用轮询方式等待数据就绪后面写驱动时会解释为什么。2.2 电源域与参考电压选取ADS1278 的电源分为 AVDD、DVDD 和 IOVDD三者的区别在于模拟调制器供电、数字核心供电和 IO 输出电平域。IOVDD 是驱动 DOUT/DRDY 信号电平的电源需要和 MCU 的 IO 电平匹配3.3V 单片机就接 3.3V1.8V 的 FPGA 银行就接 1.8V。AVDD 和 DVDD 建议用两个独立的 LDO 供电至少在 PCB 上要保证模拟电源平面和数字电源平面不重叠。电源域供电对象去耦电容建议关键注意点AVDD模拟调制器10uF 钽电容 0.1uF 瓷片电容并联远离开关电源噪声走线单独从 LDO 输出引出DVDD数字核心逻辑1uF 0.1uF与 AVDD 之间加磁珠隔离IOVDDSPI/DRDY 输出缓冲0.1uF电压必须覆盖 MCU 高电平阈值参考电压是 24 位系统最容易低估的一环。ADS1278 的差分输入范围是 ±VREFVREF 的噪声会直接叠加到转换结果里。常见做法是用 2.5V 或 4.096V 的精密基准源后端加一个低噪声缓冲器再接到 VREFP/VREFN而不是用电阻分压从电源取。REF 引脚附近需要放一个 1uF 到 10uF 的低 ESR 电容电容位置距离 VREFP 引脚越近越好。如果参考电压纹波超过 1mVpp测量结果的有效位数基本不可能超过 20 位后面做多少软件滤波都补不回来。2.3 时钟频率、抽取率与采样率的换算关系ADS1278 需要一颗外部时钟 CLKCLK 经过分频后作为调制器时钟再经过数字滤波器抽取得到最终输出数据率。数据率的大致换算关系是DataRate fCLK / (CLKDIV × OS)CLKDIV 是 MODE 寄存器里的分频位置 1 时 CLK 内部除以 2OS 是抽取率由 MODE 寄存器的 OS[2:0] 位决定。这个公式决定的不仅是采样率还直接影响 SCLK 的最小时间预算每帧要读出 8 通道 × 24 位 192 位数据如果 DRDY 周期是 T那么 192 位数据必须全部在 T 时间内由主机读走否则下一帧数据到来时当前帧会被覆盖。所以计算 SCLK 频率时要预留余量。例如你要做到 50kSPS帧周期是 20us那么读取 192 位需要的时间必须小于 20usSCLK 至少需要 192 / 20us 9.6MHz实际建议留出至少 30% 余量也就是 SCLK 要跑到 12MHz 以上。如果 MCU 的 SPI 外设最高只能跑 10MHz就得把采样率降下来或者考虑使用 TDM 模式减少 DOUT 引脚数量但 SCLK 压力并不会降低。另外外部 CLK 信号的抖动直接影响 SNR。CLK 作为调制器采样时钟抖动会表现为采样时刻的不确定性。用 MCU 的 PWM 输出做 CLK 只能用于功能验证追求性能时必须用晶振或者低抖动时钟芯片。3. ADS1278 的 SPI 时序、关键寄存器与四种模式选择3.1 DRDY 时序与 SPI 帧格式的关系ADS1278 的 DRDY 是数据就绪指示下降沿表示当前所有通道的转换结果已经锁存到输出移位寄存器主机可以从这时开始读数据。DRDY 会周期性产生周期就是当前配置下的数据转换周期。第一个 DRDY 出现之前内部滤波器还在建立过程中数据不可用。SPI 读取的帧结构是固定的每个通道 24 位数据从通道 1 开始到通道 8 结束MSB 在前。CS 可以保持低电平连续读完八个通道也可以每通道单独拉高 CS 读三字节。连续读的效率更高因为可以减少 GPIO 翻转次数。SCLK 空闲电平为低数据在下降沿输出、上升沿被主机锁存对应 SPI Mode 1。一个容易踩的细节是ADS1278 的 DOUT 在 CS 拉高时必须处于高阻态CS 拉低后经过一小段延迟才会输出第一位。如果 SPI 主机在 CS 下降沿之后立刻采样第一位数据可能还没稳定。处理办法是降低 SPI 时钟或者使用 MCU 的 SPI 从模式使能延迟功能。3.2 MODE 寄存器与配置寄存器的位定义MODE 寄存器是 ADS1278 最重要的控制寄存器它通过 SPI 写入一个字节控制抽取率、数据格式和时钟分频。寄存器地址是 0x00。MODE 寄存器里关键的字段包括 OS[2:0] 位决定抽取率、FORMAT[1:0] 位决定串行数据格式、CLKDIV 位决定内部时钟是否二分之一分频。FORMAT 位决定 DOUT 的引脚行为。固定 SPI 模式每个通道有独立的 DOUT 引脚8 通道模数转换器对应 8 根 DOUT 线可以并行读取TDM 模式将八个通道的数据依次拼在单根 DOUT 上进行时分复用少引脚但需要更高的 SCLK。这两种模式各有用途固定 SPI 适合追求低 SCLK 的应用因为可以八根线并行读TDM 适合 FPGA 或 MCU 引脚资源紧张、但 SPI 时钟充足的设计。写入 MODE 寄存器的代码逻辑是典型的 SPI 写寄存器流程把 CS 拉低先发送寄存器地址字节再发送数据字节最后拉高 CS。传输过程中 DIN 引脚上的第一个字节是地址第二个字节是值ADS1278 在内部按位解析。寄存器映射结构不复杂但不同批次芯片对保留位的处理可能有差异写之前最好把 MODE 寄存器完整读回校验一遍。3.3 四种工作模式高速、高分辨率、低功耗、低延迟怎么选ADS1278 的四种工作模式本质上是同一硬件在不同抽取率和时钟分频组合下的表现。高速模式的 OS 较低数据速率可以推到最高适合对采样率要求高但噪声指标相对宽松的场景高分辨率模式使用更高的抽取率噪声更低ENOB 更高适合精密测量低功耗模式通过 CLKDIV 分频降低内部调制器频率功耗与噪声折中低延迟模式则针对控制环路和需要确定性延时的应用设计数字滤波器的群延迟最短。刚开始调板子时不要一上来就追求最高采样率。先用低抽取率的低速模式确认 SPI 帧格式对不上号的问题比如先设置到 1kSPS 左右把 DRDY、SCLK 和 DOUT 的波形抓到示波器上确认从 DOUT 读出的 24 位数据与输入电压的关系正确再逐步提高采样率。这样排查问题时的范围会小很多因为数据速率一旦上来片选时序和 SPI 时钟余量的问题会被噪音掩盖。MODE 寄存器的写入值通常是按表查询得来的。例如你想把芯片配置成高分辨率模式下的某个抽取率先在数据手册的 MODE 寄存器表格里找到对应的 OS 编码再加上 FORMAT 和 CLKDIV 的位拼成一个字节。关键点在于写入之前必须先让 SYNC 复位一次否则部分寄存器位的生效时间点不对。4. 用 C 代码实现 ADS1278 驱动初始化、DMA 读取与数据解析4.1 驱动初始化流程复位 SYNC 与 SPI 通信自检初始化穿插两层工作硬件 GPIO 的初始化以及通过 SPI 对 ADS1278 的寄存器配置。先用任意 GPIO 控制 SYNC拉低 1us 以上再拉高完成一次系统复位。然后配置 SPI 外设为 Mode 1、MSB 优先、8 位传输SCLK 的初始频率可以放低到 1MHz确保时序稳定。上电后的前几个 DRDY 周期内数字滤波器还在建立状态这段数据要丢弃。常见做法是上电后等待至少 10 个 DRDY 周期再开始处理数据或者在软件里设置一个跳过帧计数。初始化完成后回读 MODE 寄存器验证写入值是否一致这是排除通信问题的最高效手段。int ads1278_init(void) { /* 1. 复位内部数字滤波器 */ HAL_GPIO_WritePin(SYNC_GPIO_Port, SYNC_Pin, GPIO_PIN_RESET); delay_us(2); HAL_GPIO_WritePin(SYNC_GPIO_Port, SYNC_Pin, GPIO_PIN_SET); /* 2. 写入 MODE 寄存器值 0x06 只作为示例 FORMAT固定SPI模式, OS64倍抽取, CLKDIV1 */ uint8_t tx[2] {0x00, 0x06}; HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET); HAL_SPI_Transmit(hspi, tx, 2, 100); HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET); /* 3. 回读 MODE确认写入值与回读值一致 */ uint8_t rx[2] {0x00, 0x00}; /* 地址字节最高位置1表示读按手册时序填充 */ HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET); HAL_SPI_TransmitReceive(hspi, tx, rx, 2, 100); HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET); return (rx[1] 0x06) ? 0 : -1; }上面的代码把 SYNC 复位、寄存器写入和回读验证放在同一个函数里这是排查问题时最有效率的组织方式。回读机制的作用是排除 SPI 引脚接错、电平不匹配、时钟极性问题因为写入后马上读回是最短的验证反馈闭环。这里的寄存器值 0x06 不是所有应用的通用配置你应当根据实际需要的抽取率和接口格式去查手册算出具体的字节。4.2 用 DRDY 下降沿中断触发 DMA 传送读取 8 通道数据的核心思路是让 DRDY 下降沿触发 EXTI 中断在中断服务函数里启动 SPI DMA 读取等 DMA 完成后再做数据拼装。为什么不用阻塞式 SPI 读取阻塞读会占用 CPU 很长时间尤其是当 SCLK 只有 10MHz 时读 24 字节需要 19.2 微秒这期间 CPU 没法做其他事在高采样率下还会导致中断嵌套和帧丢失。#define ADS1278_CH_COUNT 8 #define ADS1278_FRAME_SIZE (ADS1278_CH_COUNT * 3) /* 8通道 × 3字节 24字节 */ static uint8_t g_rxbuf[ADS1278_FRAME_SIZE]; static int32_t g_raw[ADS1278_CH_COUNT]; static volatile uint8_t g_frame_ready 0; void EXTI_DRDY_IRQHandler(void) { /* 清除中断标志后立刻启动 DMA 读期间 DOUT 无数据需要等待 */ HAL_GPIO_EXTI_IRQHandler(DRDY_Pin); HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET); HAL_SPI_Receive_DMA(hspi, g_rxbuf, ADS1278_FRAME_SIZE); } void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) { if (hspi hspi1) { HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET); /* 在这里拼装 24 位补码数据转换到实际数值 */ for (int i 0; i ADS1278_CH_COUNT; i) { uint32_t v ((uint32_t)g_rxbuf[i * 3] 16) | ((uint32_t)g_rxbuf[i * 3 1] 8) | (uint32_t)g_rxbuf[i * 3 2]; if (v 0x800000u) { v | 0xFF000000u; /* 符号扩展成 32 位补码 */ } g_raw[i] (int32_t)v; } g_frame_ready 1; } }这里使用了 SPI DMA 的接收模式主循环里只需要轮询g_frame_ready标志位。DMA 传输的字节数是 24对应 8 通道每个通道 3 字节这段代码里 SPI 时钟频率可以适当调高到 10MHz 以上因为 DMA 模式下的时序开销比中断发送小很多。另一个细节是 CS 片的控制逻辑DMA 接收开始前拉低 CS接收完成回调里拉高 CS这保证了整个 24 字节帧读完后才释放总线。4.3 原始码值换算成物理电压的方法ADS1278 输出的是 24 位二进制补码满量程范围是 -2^23 到 2^23-1对应模拟输入的 -VREF 到 VREF-1LSB。所以换算成电压的公式是电压 原始码值 / 8388608 × VREF例如差分输入范围 ±2.5V 时1LSB 约等于 0.298VLSB也就是 596 纳伏这个精度级别下代码里任何不必要的浮点运算都会成为噪声源。如果 VREF 是 4.096V实际 LSB 只有 0.488VLSB反而更容易受参考源噪声影响。用整数先做除法再用浮点显示数据是更稳妥的做法。实际驱动里可以加一层软件校准。零输入时读到的码值即失调误差在系统初始化阶段读 100 帧取平均用这个平均值做预处理。ADS1278 内部虽然有偏移校准寄存器但对于单次标定软件校准的效果和寄存器校准几乎一样而且不影响内部数字滤波器的工作状态。4.4 帧错位的排查手段固定输入信号观察通道序列多通道数据串位是新手最容易遇到的问题现象是通道 1 的波形出现在通道 3 的位置。排查方法是给通道 1 输入一个直流电平其他通道接地或接共模电平然后观察读出的 8 个 24 位数据的排列顺序是否与 PCB 上的物理通道对应。这个测试在拿到开发板的第一个小时就应该做它同时验证了 PCB 焊线、SPI 帧格式和代码数组下标的关系。如果发现数据整体错开 N 个字节不要急着改代码先看示波器上 CS 拉低之后的第一位 DOUT 是否正好是通道 1 的 MSB。很多时候是因为 SPI 配置成了 16 位传输模式MCU 自动插入了字节对齐的额外时钟导致帧内数据位偏移。检查 SPI 外设的数据帧格式寄存器应该配置为 8 位数据传输。5. 验证 ADS1278 采集质量用 SINAD 和直方图快速定位问题拿到能出数的驱动之后下一件值得投入时间的事是验证有效位数而不是继续加功能。把信号源设置成标准的 1kHz 正弦波峰峰值放到满量程的 -1dBFS 左右采集 65536 个点做成 FFT观察频谱里的噪底和谐波分布。FFT 频谱的边框如果翘得很高大概率是加窗函数造成的频谱泄漏先用汉宁窗处理再测 SINAD。真正的 SINAD 测试不应该用信号源输出到 ADC 输入时观察而应该测量从 ADC 原始码值做 FFT 的结果这样才能排除示波器探头、信号线耦合等测试环境问题的影响。/* 伪代码以 -1dBFS 正弦输入收集 64k 样本后估算 SINAD */ double sinad_db compute_sinad_from_fft(fft_output, 65536); double enob (sinad_db - 1.76) / 6.02; printf(ENOB %.2f bits\n, enob);如果测得的 ENOB 比数据手册典型值低 3dB 以上优先检查参考电压的纹波和 CLK 抖动这两个因素直接影响 ADC 的理论性能上限。直方图测试针对直流输入的码值分布查看最坏情况下的码值离散程度如果分布呈现双锋状说明 PCB 上有周期性干扰往往是数字时钟耦合到参考电压回路。最后一个调试技巧值得记住不要用示波器探头直接量 VREF 引脚来判断参考是否干净示波器探头自身会引入噪声。应该量 VREF 芯片输出端经过缓冲器之后的位置如果那里干净而 VREFP 引脚不干净说明 ADS1278 内部的开关电容动态电流过大需要加大 VREFP 引脚本地去耦电容比如在原有 1uF 基础上并联 10uF X7R 电容规格书没有写死容值上限实际测试就能找到最优解。本文还有配套的精品资源点击获取
返回列表