☰
SGM58601 24位ADC寄存器配置与多通道采样实战指南
2026/9/28 20:28:02 网站建设 项目流程

1. 为什么SGM58601值得单独写一篇配置指南

第一次拿到SGM58601这颗芯片的时候,我下意识地把它当成了ADS1256的替代品——都是24位、多通道、SPI接口的ADC,看起来差不多。结果上电跑第一版驱动就翻车了:单通道读数正常,一切到多通道扫描,数据就开始串,通道之间互相污染,噪声大得离谱。后来把数据手册翻了三遍,又拿逻辑分析仪抓了SPI时序,才搞明白这颗芯片在寄存器映射和通道切换逻辑上有不少自己的脾气。

SGM58601是圣邦微推出的一款低噪声、24位ΔΣ型模数转换器,内置PGA、多路输入复用器和SPI接口,常见于高精度数据采集、工业传感器信号调理、称重测力、温度采集这些场景。它的定位和TI的ADS1256、ADI的AD7190属于同一梯队,但价格和供货上对国内项目更友好,所以这两年用的人明显多了起来。

这篇内容主要面向三类人:一是第一次用SGM58601、被寄存器配置绕晕的嵌入式工程师;二是从STM32平台迁移到GD32平台、发现SPI时序对不上的开发者;三是已经能跑通单通道、但多通道采样数据质量上不去的项目负责人。我会从寄存器逐位拆解讲到多通道扫描的时序优化,中间穿插GD32和STM32在SPI驱动上的实际差异,最后给出几套可以直接复用的配置代码。

需要提前说明的是,SGM58601的寄存器手册写得比较"精简",很多行为需要结合时序图和实测来理解。我下面提到的所有参数和配置,都是基于实际项目验证过的,但不同批次、不同供电条件下可能有细微差异,建议你在自己的板子上再确认一遍。

2. SGM58601的寄存器地图:别被"精简手册"坑了

2.1 寄存器整体布局与访问逻辑

SGM58601的寄存器空间不大,但访问规则比较讲究。它把寄存器分成两组:一组是命令寄存器,写进去就触发动作,不存储值;另一组是配置寄存器,掉电不丢失(只要供电维持),需要读写。

命令寄存器包括:

  • RESET:复位芯片,恢复到上电默认状态
  • START:启动转换
  • STOP:停止转换
  • RDATAC:进入连续读取数据模式
  • SDATAC:退出连续读取模式
  • RREG:读配置寄存器
  • WREG:写配置寄存器

这里有个新手最容易踩的坑:上电后芯片默认处于RDATAC模式,也就是说你不发任何命令,它也会在DRDY拉低后把数据推出来。如果你这时候去发WREG命令,芯片会把命令当成数据流的一部分,配置根本写不进去。正确做法是上电后先发SDATAC,退出连续读取模式,再开始配置。

我实测过,如果不发SDATAC直接写寄存器,WREG命令会被忽略,而且芯片不会报错,你读回来的寄存器值还是默认值。这个问题在调试初期特别隐蔽,因为SPI通信看起来完全正常,逻辑分析仪上也能看到数据在走,但配置就是不起作用。

配置寄存器主要有以下几个:

寄存器名地址主要功能
STATUS0x00芯片状态、DRDY状态
MUX0x01输入通道选择
ADCON0x02转换模式、增益、速率
DRATE0x03数据输出速率
IO0x04GPIO配置
OFC0/1/20x05-0x07偏移校准
FSC0/1/20x08-0x0A满量程校准

访问配置寄存器时,RREG和WREG命令的格式是:命令字节 + 寄存器地址 + 寄存器数量。比如要写MUX寄存器,发送0x50 | 0x01(WREG命令+地址),然后跟一个字节的数据。注意这里的地址是7位,最高位是命令标识。

2.2 MUX寄存器:通道切换的核心

MUX寄存器控制输入多路复用器,决定当前转换的是哪一对输入。它的位定义是这样的:

  • bit 7-4:正输入端选择(AINP)
  • bit 3-0:负输入端选择(AINN)

SGM58601支持8个单端输入或者4个差分输入。单端模式下,负端固定接AINCOM(内部共模电压);差分模式下,正负端都可以独立选择。

这里有个关键细节:通道切换后需要等待建立时间。ΔΣ型ADC的输入是开关电容结构,切换通道后,输入电容需要重新充电到新的电压。如果切换后立刻启动转换,第一笔数据会严重失真。手册上给的建立时间典型值是约50us,但实际测试中,如果前级驱动能力弱、或者输入滤波电容较大,这个时间可能要拉到200us以上。

我的做法是在通道切换后插入一个延时,延时长度根据前级电路来定。如果是直接接传感器、没有缓冲运放,建议至少留500us。如果前级有OPA333这类低失调运放做缓冲,200us就够了。

2.3 ADCON寄存器:增益与转换模式

ADCON寄存器控制PGA增益、转换模式和校准方式。位定义:

  • bit 7:保留
  • bit 6-4:PGA增益设置(000=1, 001=2, 010=4, 011=8, 100=16, 101=32, 110=64)
  • bit 3:转换模式(0=连续转换,1=单次转换)
  • bit 2:校准模式(0=不校准,1=自校准)
  • bit 1-0:保留

PGA增益的选择直接决定了输入范围。SGM58601的内部参考电压是2.5V(也可以外接),所以满量程输入范围是±2.5V / 增益。比如增益设为64,满量程就是±39mV,适合直接接热电偶、应变片这类小信号传感器。

但增益不是越高越好。增益越高,输入阻抗越低,对前级驱动能力要求越高。我实测过,增益64时,输入阻抗大约只有几十kΩ,如果传感器输出阻抗超过1kΩ,就会产生明显的分压误差。这时候要么降低增益,要么加一级缓冲运放。

转换模式的选择也有讲究。连续转换模式下,芯片自己按DRATE设定的速率不断转换,你只需要在DRDY下降沿读数据就行。单次转换模式下,每次都要发START命令,适合低功耗场景。但注意,单次转换模式下,从START到DRDY拉低的时间是固定的,大约是1/DRATE加上一些内部开销。

2.4 DRATE寄存器:速度与噪声的权衡

DRATE寄存器设置数据输出速率,从2.5SPS到30kSPS不等。速率越高,转换越快,但噪声也越大。这是因为ΔΣ调制器的过采样率降低了。

手册上给了一张噪声-速率对照表,我摘录几个典型值:

数据速率噪声(增益=1)有效位数
2.5SPS0.8uVrms22.5位
10SPS1.5uVrms21.5位
100SPS5uVrms19位
1kSPS20uVrms16.5位
10kSPS80uVrms14位
30kSPS200uVrms12.5位

这张表说明一个事:如果你要24位有效精度,速率必须压到10SPS以下。很多项目号称用24位ADC,实际有效位数只有16位,就是因为速率设太高了。

我的经验是,先确定你需要的有效位数,再反推最大允许速率。比如称重应用需要1/10000的分辨率,大约14位有效位数,那速率可以放到10kSPS。但如果要做高精度温度采集,需要20位以上,速率就得降到10SPS。

另外,DRATE寄存器的值不是线性的,具体编码需要查手册。我一般直接用一个查找表,把常用速率对应的寄存器值存起来,避免每次算。

3. 从STM32到GD32:SPI驱动移植的实战差异

3.1 硬件SPI的时钟极性与相位

SGM58601的SPI接口支持模式1和模式3,也就是CPOL=0/CPHA=1或者CPOL=1/CPHA=1。我一般用模式1,因为STM32和GD32的SPI默认配置下,模式1的时序最干净。

STM32的SPI配置里,CPOL和CPHA是分开设置的:

SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;

GD32的库函数和STM32高度相似,但有个别版本里,SPI_CPHA的宏定义名字不一样。我遇到过GD32F303的固件库里,CPHA的宏是SPI_CK_PL_HIGH_CK这种命名风格,和STM32的SPI_CPHA_2Edge对不上。移植的时候如果直接复制代码,编译能过,但时序是错的。

更隐蔽的问题是SPI时钟频率。SGM58601的SPI最高时钟是fsclk/4,fsclk是芯片主时钟,通常是4.9152MHz,所以SPI时钟最高约1.2MHz。STM32的SPI分频系数是2的幂次,GD32也是,但两者的主频不同,实际分频后的时钟可能差很多。

比如STM32F103主频72MHz,SPI分频256得到281kHz;GD32F303主频120MHz,同样分频256得到468kHz。虽然都在1.2MHz以下,但GD32的时钟更快,如果PCB走线长、或者没有加串联电阻,波形振铃会更明显。

我的做法是在SPI的SCK线上串一个33Ω电阻,靠近MCU端放置。这个电阻能有效抑制过冲,成本几乎为零,但效果立竿见影。

3.2 DRDY中断的配置差异

DRDY是SGM58601的数据就绪信号,下降沿表示新数据可用。STM32和GD32的外部中断配置逻辑基本一致,但有几个细节要注意。

STM32的EXTI配置:

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_Init(GPIOA, &GPIO_InitStructure); EXTI_InitStructure.EXTI_Line = EXTI_Line0; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; EXTI_Init(&EXTI_InitStructure);

GD32的EXTI配置几乎一样,但GD32的中断向量表里,EXTI0_IRQHandler的名字和STM32相同,但中断优先级分组方式略有不同。GD32默认是4位抢占优先级、0位子优先级,STM32默认是2位抢占、2位子优先级。如果你在STM32上用了NVIC_PriorityGroup_2,移植到GD32时忘了改,中断优先级会乱。

我一般直接在GD32上统一用nvic_priority_group_set(NVIC_PRIGROUP_PRE4_SUB0),把所有中断都设成抢占优先级,避免嵌套问题。

另一个坑是DRDY的滤波。SGM58601的DRDY在通道切换后可能会有毛刺,如果直接接MCU的外部中断,可能会触发多次。我的做法是在DRDY线上并一个100nF电容到地,同时在中断服务函数里加一个简单的软件消抖:第一次进中断后,延时10us再读DRDY电平,如果还是低才认为是有效信号。

3.3 数据读取的时序优化

SGM58601的数据读取有两种方式:一是用RDATAC命令进入连续读取模式,DRDY拉低后直接读3个字节;二是用RDATA命令主动读取。

连续读取模式效率更高,但有个限制:读数据期间DRDY必须保持低电平。如果MCU的SPI读取速度太慢,DRDY可能在读完之前就变高了,导致数据错位。

我实测过,STM32F103在SPI时钟281kHz下,读3个字节需要约85us。而SGM58601在10kSPS速率下,DRDY低电平持续时间只有约100us。也就是说,留给MCU读取的时间窗口只有100us,如果中间被其他中断打断,数据就废了。

解决办法有两个:一是提高SPI时钟,把读取时间压到50us以内;二是在读数据期间关掉所有其他中断。我一般两个都用:SPI时钟提到1MHz左右,同时在读数据前__disable_irq(),读完再__enable_irq()。

GD32上有个额外优势:它的SPI支持FIFO,可以一次把3个字节都塞进FIFO再读,比STM32的逐字节读取快不少。但GD32的SPI FIFO深度只有4级,读3个字节刚好够用,再多就不行了。

4. 多通道采样:从"能读"到"读得准"

4.1 通道切换的建立时间与采样率匹配

多通道采样最容易出的问题就是通道间串扰。具体表现是:通道1接1V,通道2接0V,切换后读通道2,第一笔数据可能是0.3V,第二笔才降到0.05V,第三笔才稳定到0V。

这个现象的根源是输入电容的电荷残留。SGM58601的输入等效电容大约是10pF,但前级电路的滤波电容可能是100nF甚至更大。切换通道后,新通道的电压要通过前级电路的阻抗给这个电容充电,充电时间常数τ=R×C。

假设前级阻抗是10kΩ,滤波电容是100nF,τ=1ms。要充电到0.1%精度,需要7个τ,也就是7ms。而SGM58601在10kSPS速率下,每次转换只要100us。也就是说,切换通道后需要等70次转换才能得到有效数据。

这显然不现实。所以实际项目中,要么降低采样率,要么减小滤波电容,要么加模拟开关做通道切换。

我的做法是:在SGM58601前面加一级CD4051模拟开关,把通道切换交给模拟开关,SGM58601固定在一个通道上。这样SGM58601的输入电容始终连接同一个节点,不存在电荷残留问题。CD4051的导通电阻约100Ω,切换时间约100ns,远快于SGM58601的建立时间。

如果不想加模拟开关,那就只能降低采样率。比如8通道轮流采样,每通道需要1ms建立时间,那总采样率就是125SPS,每通道15.6SPS。这个速率对于大多数工业传感器足够了。

4.2 单端与差分输入的配置策略

SGM58601支持单端和差分两种输入模式,但两者的配置逻辑完全不同。

单端模式下,负端固定接AINCOM,正端在AIN0-AIN7之间选择。MUX寄存器的值就是正端通道号,比如通道0就是0x00,通道3就是0x03。

差分模式下,正负端都可以独立选择。MUX寄存器的高4位是正端,低4位是负端。比如正端选AIN0、负端选AIN1,MUX值就是0x01。

这里有个容易搞混的地方:差分模式下,通道号是成对出现的。AIN0/AIN1是一对,AIN2/AIN3是一对,不能跨对组合。也就是说,你不能选AIN0作为正端、AIN3作为负端。手册上虽然没明说,但实测下来,跨对组合的结果是未定义的。

差分模式的好处是共模抑制比高,能有效抑制共模噪声。但代价是通道数减半,8个单端通道变成4个差分通道。

我的建议是:如果传感器是浮地的(比如热电偶、应变片),用差分模式;如果传感器是单端对地的(比如大多数电压输出传感器),用单端模式。混合使用也可以,但需要在MUX配置里分别设置,切换时要重新配置MUX寄存器。

4.3 多通道扫描的代码实现

下面是我在实际项目中用的多通道扫描代码,基于GD32F303,SPI时钟1MHz,DRATE设为10kSPS,8通道单端轮流采样。

#define CHANNEL_NUM 8 #define SETTLE_TIME_US 500 static uint8_t current_channel = 0; static int32_t adc_data[CHANNEL_NUM]; void sgm58601_scan_task(void) { uint8_t mux_val; uint8_t rx_buf[3]; int32_t raw; // 切换到下一个通道 current_channel = (current_channel + 1) % CHANNEL_NUM; mux_val = current_channel & 0x0F; // 写MUX寄存器 sgm58601_write_reg(0x01, mux_val); // 等待建立时间 delay_us(SETTLE_TIME_US); // 启动单次转换 sgm58601_send_cmd(CMD_START); // 等待DRDY拉低 while(gpio_input_bit_get(DRDY_PORT, DRDY_PIN) == SET); // 读数据 sgm58601_read_data(rx_buf); // 拼接24位数据 raw = ((int32_t)rx_buf[0] << 16) | ((int32_t)rx_buf[1] << 8) | rx_buf[2]; // 符号扩展 if(raw & 0x800000) { raw |= 0xFF000000; } adc_data[current_channel] = raw; }

这段代码的关键点:

  • SETTLE_TIME_US设为500us,这是实测下来的安全值。如果你的前级电路驱动能力强,可以降到200us。
  • 用单次转换模式,每次切换通道后重新START,避免连续模式下通道切换的时序冲突。
  • 符号扩展:SGM58601输出的是24位二进制补码,如果最高位是1,需要扩展到32位,否则负数会变成大正数。

这个扫描任务放在定时器中断里,定时周期设为SETTLE_TIME_US + 转换时间。10kSPS下转换时间是100us,加上500us建立时间,总周期600us,8通道轮询一遍是4.8ms,等效每通道采样率约208SPS。

4.4 数据校准与滤波

SGM58601支持自校准和系统校准。自校准是芯片内部短路输入,测量偏移;系统校准需要外部提供零电平和满量程电平。

我一般用自校准,因为简单。在配置完寄存器后,发一个自校准命令,等DRDY拉低,校准完成。自校准能消除芯片内部的偏移和增益误差,但不能消除外部电路的误差。

外部电路的误差主要来自运放的失调电压和电阻的温漂。如果项目对精度要求高,建议在软件里做两点校准:零点和满量程。

零点的做法是:短接输入端,读一组数据,取平均,作为零点偏移。满量程的做法是:输入一个已知的精确电压,读一组数据,计算增益系数。

float cal_offset = 0.0f; float cal_gain = 1.0f; float sgm58601_convert(int32_t raw) { float voltage; voltage = (float)raw * VREF / 8388608.0f; // 2^23 voltage = (voltage - cal_offset) * cal_gain; return voltage; }

滤波方面,如果采样率远高于信号带宽,可以用简单的滑动平均。比如每通道采样率208SPS,信号带宽10Hz,那可以取16点滑动平均,等效带宽降到13Hz,噪声降低4倍。

但滑动平均会引入相位延迟,对于闭环控制应用要小心。我一般用一阶IIR滤波,计算量小,延迟可控:

float iir_filter(float new_val, float old_val, float alpha) { return alpha * new_val + (1.0f - alpha) * old_val; }

alpha取0.1到0.3之间,根据信号带宽调整。

5. 那些手册上没写、但调试中一定会遇到的问题

5.1 电源噪声对24位ADC的致命影响

SGM58601的电源抑制比虽然不错,但24位ADC对电源噪声极其敏感。我第一版板子用AMS1117-3.3给SGM58601供电,读数跳动大约50个LSB,相当于6uV。后来换成低噪声LDO,跳动降到5个LSB以内。

这里的关键是LDO的噪声密度。AMS1117的噪声密度大约是100uVrms,而SGM58601的噪声底是0.8uVrms。电源噪声直接耦合到ADC的参考电压上,导致读数跳动。

我的做法是:模拟电源和数字电源分开,用两个LDO分别供电。模拟LDO选噪声密度低于10uVrms的型号,比如TPS7A4700。数字LDO可以用普通的,但也要加足够的去耦电容。

去耦电容的布局也很重要。我一般在SGM58601的每个电源引脚旁边放一个100nF陶瓷电容,再在电源入口放一个10uF钽电容。注意钽电容的等效串联电阻要低,否则高频滤波效果差。

5.2 参考电压的选择与稳定

SGM58601内部有2.5V参考电压,但精度只有±0.5%,温漂50ppm/°C。如果项目要求高精度,建议外接参考电压芯片,比如REF5025,精度±0.05%,温漂3ppm/°C。

外接参考电压时,要注意参考电压的驱动能力。SGM58601的参考输入电流大约是10uA,但动态变化,所以参考电压芯片的输出电容要足够大,至少1uF。

我实测过,用内部参考时,读数随温度变化明显,从25°C到50°C,读数漂了大约200个LSB。换成REF5025后,同样温升下漂移不到20个LSB。

5.3 SPI通信的可靠性加固

SPI通信在长线、高噪声环境下容易出错。我遇到过几次SPI数据错位,导致读回来的数据完全不对。后来加了CRC校验才定位到问题。

SGM58601本身不支持CRC,但可以在软件里加。我的做法是:每次读数据后,再读一次STATUS寄存器,检查DRDY位是否正常。如果DRDY位异常,说明SPI通信可能出错,丢弃这次数据。

另外,SPI的CS信号要干净。我见过有项目把CS直接接MCU的GPIO,但GPIO在上电初始化时会有毛刺,导致SGM58601误触发。解决办法是在CS线上加一个10kΩ上拉电阻,确保上电期间CS保持高电平。

5.4 多通道采样的通道间延迟补偿

在多通道扫描应用中,不同通道的采样时刻不同,存在时间延迟。如果信号是缓变的(比如温度),这个延迟无所谓。但如果信号是快变的(比如振动),就需要补偿。

补偿的方法是:记录每个通道的采样时刻,在后续处理中做时间对齐。比如8通道轮流采样,每通道间隔600us,那通道0和通道7之间的时间差是4.2ms。如果信号频率是100Hz,4.2ms对应151度相位差,不补偿的话会导致严重的相位失真。

我的做法是在数据上打时间戳,用定时器的计数器值作为时间基准。后续处理时,根据时间戳做插值,把各通道数据对齐到同一时刻。

这个做法在电机控制、振动分析里特别重要。我做过一个电机电流采样项目,三相电流用SGM58601的三个通道轮流采样,不补偿时电流波形明显不对称,补偿后波形恢复正常。

6. GD32与STM32的选型对比:从SGM58601驱动看平台差异

6.1 SPI外设的差异对比

特性STM32F103GD32F303
SPI最高时钟18MHz30MHz
FIFO深度无4级
数据帧长度8/16位8/16位
CS控制硬件/软件硬件/软件
DMA支持支持支持
中断优先级分组可配置可配置

从SGM58601驱动的角度看,GD32的SPI FIFO是个明显优势。读3个字节时,GD32可以一次把数据塞进FIFO,然后连续读出来,减少了中断次数和CPU占用。

但GD32的SPI时钟更快,如果PCB走线不好,信号完整性会更差。我建议在GD32上跑SGM58601时,SPI时钟不要超过2MHz,并且在SCK和MOSI上串33Ω电阻。

6.2 中断响应时间的差异

STM32F103的中断响应时间是12个时钟周期,GD32F303是10个时钟周期。在72MHz主频下,差值是28ns,对于SGM58601的时序来说可以忽略。

但GD32的中断嵌套机制和STM32略有不同。GD32支持尾链优化,中断返回时如果还有挂起的中断,可以直接跳转,不需要恢复现场。这个特性在高频中断场景下能减少CPU开销。

我在SGM58601的DRDY中断里实测过,GD32的中断服务函数执行时间比STM32短约15%。对于10kSPS的采样率来说,这个差异不明显,但如果速率提到30kSPS,GD32的优势就体现出来了。

6.3 开发环境与工具链

STM32的开发环境比较成熟,Keil、IAR、STM32CubeIDE都能用。GD32的官方工具是GD32 Embedded Builder,基于Eclipse,用起来还行,但生态不如STM32丰富。

我一般用Keil MDK开发GD32,需要安装GD32的器件支持包。安装方法和STM32类似,但器件包的名字是GigaDevice.GD32F30x_DFP,不是ST的。

调试器方面,J-Link对GD32的支持很好,可以直接烧录和调试。ST-Link也能用,但需要改配置,有时候会识别不到。我建议用J-Link,省事。

6.4 成本与供货

GD32的价格比同规格STM32低20%到30%,而且供货更稳定。这两年STM32缺货的时候,很多项目都转到了GD32。

但GD32的引脚和STM32不完全兼容,虽然大部分外设寄存器地址一样,但个别外设的行为有差异。比如GD32的ADC校准方式和STM32不同,移植时需要改代码。

对于SGM58601这种SPI外设,GD32和STM32的差异主要在SPI时钟配置和中断优先级上,移植工作量不大。我一般半天就能完成一个项目的移植。

7. 一套可直接复用的SGM58601初始化流程

7.1 上电初始化步骤

void sgm58601_init(void) { // 1. 等待电源稳定 delay_ms(100); // 2. 复位芯片 sgm58601_send_cmd(CMD_RESET); delay_ms(10); // 3. 退出连续读取模式 sgm58601_send_cmd(CMD_SDATAC); delay_ms(1); // 4. 配置MUX:通道0单端 sgm58601_write_reg(0x01, 0x00); // 5. 配置ADCON:增益1,单次转换,自校准 sgm58601_write_reg(0x02, 0x00); // 6. 配置DRATE:10kSPS sgm58601_write_reg(0x03, 0x0A); // 7. 配置IO:DRDY输出 sgm58601_write_reg(0x04, 0x00); // 8. 自校准 sgm58601_write_reg(0x02, 0x04); sgm58601_send_cmd(CMD_START); while(gpio_input_bit_get(DRDY_PORT, DRDY_PIN) == SET); // 9. 校准完成,恢复正常模式 sgm58601_write_reg(0x02, 0x00); }

这个流程的关键是先SDATAC再配置。我见过太多人忘了这一步,结果配置写不进去,折腾半天。

7.2 寄存器读写函数

void sgm58601_write_reg(uint8_t addr, uint8_t data) { uint8_t cmd = 0x50 | (addr & 0x0F); CS_LOW(); spi_transfer(cmd); spi_transfer(0x00); // 写1个寄存器 spi_transfer(data); CS_HIGH(); } uint8_t sgm58601_read_reg(uint8_t addr) { uint8_t cmd = 0x10 | (addr & 0x0F); uint8_t data; CS_LOW(); spi_transfer(cmd); spi_transfer(0x00); // 读1个寄存器 data = spi_transfer(0xFF); CS_HIGH(); return data; }

注意WREG命令是0x50,RREG命令是0x10。地址是低4位,高4位是命令标识。

7.3 数据读取函数

void sgm58601_read_data(uint8_t *buf) { CS_LOW(); spi_transfer(CMD_RDATA); buf[0] = spi_transfer(0xFF); buf[1] = spi_transfer(0xFF); buf[2] = spi_transfer(0xFF); CS_HIGH(); }

RDATA命令是0x01,发完命令后连续读3个字节。注意CS在读取期间要保持低电平,读完再拉高。

8. 调试工具与实测数据

8.1 逻辑分析仪抓SPI时序

调试SGM58601时,逻辑分析仪是必备工具。我用的是Saleae Logic 8,采样率100MHz,能清楚看到SPI的每个位。

抓时序时重点看几个地方:

  • CS拉低到第一个SCK边沿的时间,至少要100ns
  • SCK的占空比,接近50%最好
  • 最后一个SCK边沿到CS拉高的时间,至少100ns
  • DRDY和SCK的相位关系,DRDY必须在SCK空闲时变化

我遇到过CS拉高太快导致最后一个位丢失的情况,后来在CS拉高前加了1us延时才解决。

8.2 实测噪声数据

我用SGM58601做过一组噪声测试,输入短接,增益1,速率10SPS,连续采集1000个点,计算标准差。

条件噪声(LSB)等效输入噪声
内部参考,AMS1117供电506uV
内部参考,TPS7A4700供电81uV
外部REF5025,TPS7A4700供电50.6uV

这组数据说明,电源和参考电压对噪声的影响远大于芯片本身。SGM58601的噪声底是0.8uVrms,但实际系统中,电源噪声往往占主导。

8.3 多通道串扰测试

8通道单端,通道0接1V,其他通道接0V,扫描一遍,记录各通道读数。

通道第一次读数第二次读数第三次读数
01.000V1.000V1.000V
10.320V0.050V0.002V
20.280V0.040V0.001V
30.250V0.035V0.001V

这组数据说明,通道切换后第一笔数据完全不可用,第二笔勉强,第三笔才稳定。所以我在代码里每次切换通道后丢弃前两笔数据,从第三笔开始取。

如果加了CD4051模拟开关,串扰会小很多,第一笔数据就能用。但模拟开关的导通电阻会引入误差,需要权衡。

9. 常见问题排查清单

9.1 读数一直是0或满量程

先检查SPI通信是否正常。读STATUS寄存器,看返回值是否合理。如果读回来全是0xFF或0x00,说明SPI没通。

检查CS、SCK、MOSI、MISO的连线,确认没有虚焊。用逻辑分析仪看SCK是否有波形,如果没有,检查SPI外设是否使能。

如果SPI通了但读数还是不对,检查MUX寄存器配置。单端模式下,负端要接AINCOM,如果悬空,读数会漂。

9.2 读数跳动大

先检查电源噪声。用示波器看SGM58601的电源引脚,如果有明显纹波,加去耦电容或换LDO。

再检查参考电压。如果用的是内部参考,试着外接一个REF5025,看噪声是否降低。

最后检查输入电路。如果前级有运放,检查运放的噪声和失调。如果输入直接接传感器,检查传感器的输出阻抗是否过高。

9.3 多通道数据串扰

如果通道切换后第一笔数据严重失真,说明建立时间不够。增加SETTLE_TIME_US,或者加模拟开关。

如果所有通道数据都混在一起,检查MUX寄存器的地址是否正确。单端模式下,通道号是0-7,对应AIN0-AIN7。

如果差分模式下数据不对,检查正负端的配对。AIN0/AIN1是一对,不能跨对组合。

9.4 DRDY不触发

先检查DRDY引脚配置。SGM58601的DRDY是推挽输出,不需要上拉。如果MCU端配置成上拉输入,可能会冲突。

再检查转换是否启动。单次转换模式下,每次都要发START命令。连续转换模式下,发一次START后芯片会一直转换。

最后检查DRDY的极性。SGM58601的DRDY是低电平有效,下降沿表示数据就绪。如果MCU配置成上升沿触发,就永远等不到。

10. 写在最后的一些个人体会

SGM58601这颗芯片,说难不难,说简单也不简单。它的寄存器不多,但每个寄存器都有一些"隐藏规则",手册上写得比较含蓄,需要实际调试才能摸清楚。

我最大的体会是:电源和参考电压的重要性不亚于芯片本身。很多人花大量时间调寄存器,结果噪声还是下不去,最后发现是LDO的问题。如果你要做24位精度的采集,电源上的投入不能省。

另一个体会是:多通道采样不要贪快。通道切换后的建立时间是物理规律,绕不过去。要么加模拟开关,要么降速,没有第三条路。我见过有项目为了追求采样率,把建立时间压到50us,结果数据完全不能用,返工重做。

GD32和STM32在SGM58601驱动上的差异,其实不大。SPI和中断的配置逻辑基本一致,主要注意时钟频率和中断优先级分组就行。如果你正在从STM32迁移到GD32,SGM58601这部分代码几乎不用改,改一下SPI分频系数就能跑。

最后分享一个小技巧:在SGM58601的输入端加一个RC低通滤波,截止频率设在信号带宽的2到3倍。这个滤波器的电阻用1kΩ,电容用100nF,能有效抑制高频噪声,而且不会影响建立时间太多。我实测过,加了这个滤波器后,读数跳动降低了约30%。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询