24bits-高精度ADC---SGM5860x 应用笔记


笔记简介

本篇笔记用于记录SGM5860x系列ADC芯片的应用过程;整个内容围绕以下主题讲解:

· SGM5860x芯片参数性能介绍;

· SGM5860x芯片驱动代码实现;

最后总结方法,将SGM58601x芯片的应用方法、思路推广到其它芯片的应用。


一、SGM5860x芯片介绍

SGM5860x系列芯片是由国产厂商圣邦威电子(SGMICRO)推出的一款中高端模数转换器 (ADC) [注:本篇文章不是推广文章,对于圣邦威电子详情,可前往官网查看,此处不做详细介绍];

该系列芯片主要包括三个型号:SGM58600、SGM58601和SGM58602;

主要性能参数如下:

· 24bits转换位数;

· 最高62KSPS采样速率;

· 5V模拟电源供电;

· 2.7V-5V参考电压;

· 采用delta-sigma (ΔΣ) 类型调制器;

· 4通道差分输入或者8通道单端输入<可配置>;

· 标准SPI接口;

该系列下三个型号的AD芯片在原理、性能参数和使用上都一致,仅在可使用通道上有所区别,我们选取其中的SGM58601做使用说明。

关于SGM58601芯片更多详细数据,可在官网下载数据手册(datasheet):

Alt
详细下载地址如下:

SGM58601官方数据手册下载:
https://www.sg-micro.com/cnproduct/SGM58601


二、驱动代码实现

首先我们需要通过程序配置SPI通信接口,以保证MCU能够与SGM58601正常通信。

第一步,初始化SPI,包括使能SPI时钟,配置SPI数据线、时钟线的GPIO模式,并配置SPI相应的中断。

代码如下:

spi0_control spi0_ctr;    //定义spi0控制结构体

/*SPI初始化*/
uint8_t spi0_init(void)
{
    memset(&spi0_ctr, 0x00, sizeof(spi0_ctr));   //清空spi0控制结构体

    /*enable GPIO port RCU*/
    //rcu_periph_clock_enable(RCU_GPIOA);        在USART0中已经使能
    /*enable SPI0 RCU*/
    rcu_periph_clock_enable(RCU_SPI0);
    rcu_periph_clock_enable(RCU_AF);

    /* SPI0 GPIO config:SCK/PA5, MOSI/PA7 */
    gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5 | GPIO_PIN_7);
    /* SPI0 GPIO config:MISO/PA6 */
    gpio_init(GPIOA, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
    /* config PA4 as SPI0_NSS(SYNC) */
    //gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_4);    //in GSM58601.c enable

    //SET_SPI0_CS_HIHG; //pull up CS
    //SET_CS1_HIHG;  //pull up CS(SPI0-NSS)

    /* NVIC config */
    nvic_irq_enable(SPI0_IRQn, 0, 2);
    spi_i2s_interrupt_enable(SPI0, SPI_I2S_INT_RBNE);    //使能spi0接收缓存非空中断

    /*配置spi0*/
    spi0_config();
    return 1;
}

第二步,配置SPI接口的相关参数,如SPI通信速率、通信模式、帧大小等;

这些参数中尤其需要注意的是时钟的相位与极性,这一点可以查阅数据手册中有关SPI时序的描述,SGM58601的时钟相位与极性是:空闲态为低,在第二个边沿采样;

Alt

配置程序如下:

/*SPI0配置*/
uint8_t spi0_config(void)
{
    spi_parameter_struct  spi_init_struct;
    
    /* SPI0 parameter config */
    spi_init_struct.trans_mode           = SPI_TRANSMODE_FULLDUPLEX;   //配置模式:双向传输
    spi_init_struct.device_mode          = SPI_MASTER;                 //主-从配置: 主站
    spi_init_struct.frame_size           = SPI_FRAMESIZE_8BIT;         //帧大小:8bits
    spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_2EDGE;     //时钟空闲为低,第二个边沿采样
    spi_init_struct.nss                  = SPI_NSS_SOFT;               //NSS采用软件控制
    spi_init_struct.prescale             = SPI_PSC_32;                 //时钟分频因子120/64=1.875 MHz
    spi_init_struct.endian               = SPI_ENDIAN_MSB;             //数据发送高位在前
    spi_init(SPI0, &spi_init_struct);
    spi_enable(SPI0);
    return 1;
}

完成SPI通信接口的配置后,需要做的是将数据手册中有关的配置项、寄存器以宏定义的形式打包在头文件中;

这么做的好处就是在后续的调试过程中,不会混淆,提高程序的易读性;

关于SGM58601芯片的操作命令、寄存器地址、寄存器的描述在数据手册的末尾。

Alt

打包后的配置头文件如下:

***********************************************************************************
*说 明:此C文件为圣邦威58601-AD驱动头文件
*创 建:MaJinWen
*时 间:2023-03-09
*版 本:V_1.0.0
*修 改:none
************************************************************************************/
#ifndef __SGM58601_H__
#define __SGM58601_H__

#include "gd32f30x.h"

#define  SET_CS1_HIGH       do{GPIO_BOP(GPIOA) = GPIO_PIN_4;}while(0)       
#define  SET_CS1_LOW        do{GPIO_BC(GPIOA) = GPIO_PIN_4;}while(0)        
#define  SET_RESET1_HIGH    do{GPIO_BOP(GPIOB) = GPIO_PIN_1;}while(0)       //pull up RESET1
#define  SET_RESET1_LOW     do{GPIO_BC(GPIOB) = GPIO_PIN_1;}while(0)        //pull down RESET1

#define  SET_CS2_HIGH       do{GPIO_BOP(GPIOC) = GPIO_PIN_6;}while(0)     
#define  SET_CS2_LOW        do{GPIO_BC(GPIOC) = GPIO_PIN_6;}while(0)       
#define  SET_RESET2_HIGH    do{GPIO_BOP(GPIOB) = GPIO_PIN_2;}while(0)       //pull up RESET2
#define  SET_RESET2_LOW     do{GPIO_BC(GPIOB) = GPIO_PIN_2;}while(0)        //pull down RESET2

#define  READ_REG(regAddr)      ((uint32_t)0x00100000 | ((uint32_t)regAddr<<8))   //读寄存器地址
#define  WRITE_REG(regAddr)     ((uint32_t)0x00500000 | ((uint32_t)regAddr<<8))   //写寄存器地址

/*The number of operation registers*/
#define  OPREATION_REG_NUM_1            0x01        //操作一个寄存器
#define  OPREATION_REG_NUM_2            0x02        //操作两个寄存器
#define  OPREATION_REG_NUM_3            0x03        //操作三个寄存器
#define  OPREATION_REG_NUM_4            0x04        //操作四个寄存器

/*SGM58601寄存器地址*/
#define  STATUS_REG                     0x00         //状态寄存器
#define  MUX_REG                        0x01         //多路输入复用控制器寄存器
#define  ADCON_REG                      0x02         //A/D控制器寄存器
#define  DRATE_REG                      0x03         //A/D速率控制器
#define  IO_REG                         0x04         //GPIO控制寄存器
#define  OFC0_REG                       0x05         //偏移校准字节0-最小显著字节寄存器
#define  OFC1_REG                       0x06         //偏移校准字节1
#define  OFC2_REG                       0x07         //偏移校准字节2-最高显著字节寄存器
#define  FSC0_REG                       0x08         //全缩放校准字节0-最小显著字节
#define  FSC1_REG                       0x09         //全缩放校准字节1
#define  FSC2_REG                       0x0A         //全缩放校准字节2-最高显著字节
#define  STATUS1_REG                    0x0B         //状态1寄存器

/*SGM58601命令*/
#define  WAKEUP                         0x00         //完成同步模式并退出备用模式
#define  RDATA                          0x01         //read data
#define  RDATAC                         0x03         //continuous read data
#define  SDATAC                         0x0F         //stop continuous read data
#define  RREG                           0x10         //读reg寄存器
#define  WREG                           0x50         //写reg寄存器
#define  SELFCAL                        0xF0         //偏移和增益自校准
#define  SELFOCAL                       0xF1         //偏移量自校准
#define  SELFGCAL                       0xF2         //增益自校准
#define  SYSOCAL                        0xF3         //系统偏移校准
#define  SYSGCAL                        0xF4         //系统增益校准
#define  SYNC                           0xFC         //同步A/D转换
#define  STANDBY                        0xFD         //开始待机模式
#define  CHIP_RESET                     0xFE         //重置为通电值

/*SGM58601 auto-Calibration bit*/
#define AUTO_CALIBRATION_ENABLE         0x04

/*SGM58601 analog input buffer enable bit*/
#define ANALOG_INPUT_BUFFER_ENABLE      0x02
/*SGM58601 buffer control*/
#define REF_BUFP_ENABLE                 0x08        //Positive Reference Input Buffer Enable
#define REF_BUFM_ENABLE                 0x04        //Negative Reference Input Buffer Enable
#define AIN_BUFP_ENABLE                 0x02        //Positive Analog Input Buffer Enable
#define AIN_BUFM_ENABLE                 0x01        //Negative Analog Input Buffer Enable

/*SGM58601 PGA configuration*/
#define SET_PGA_1                       0x00
#define SET_PGA_2                       0x01
#define SET_PGA_4                       0x02
#define SET_PGA_8                       0x03
#define SET_PGA_16                      0x04
#define SET_PGA_32                      0x05
#define SET_PGA_64                      0x06
#define SET_PGA_128                     0x07

/*SGM58601 data rate configuration*/
#define SET_DATA_RATE_60000SPS          0xF1
#define SET_DATA_RATE_30000SPS          0xF0
#define SET_DATA_RATE_15000SPS          0xE0
#define SET_DATA_RATE_7500SPS           0xD0
#define SET_DATA_RATE_3750SPS           0xC0
#define SET_DATA_RATE_2000SPS           0xB0
#define SET_DATA_RATE_1000SPS           0xA1
#define SET_DATA_RATE_500SPS            0x92
#define SET_DATA_RATE_100SPS            0x82
#define SET_DATA_RATE_60SPS             0x72
#define SET_DATA_RATE_50SPS             0x63
#define SET_DATA_RATE_30SPS             0x53
#define SET_DATA_RATE_25SPS             0x43
#define SET_DATA_RATE_15SPS             0x33
#define SET_DATA_RATE_10SPS             0x23
#define SET_DATA_RATE_5SPS              0x13
#define SET_DATA_RATE_2_5SPS            0x03

/*SGM58601 Register configuration*/
#define  STATUS_REG_SET_VALUE           0x00    //status register
#define  ADC_CONTORL_REG_SET_VALUE      0x00    //ADC control register(PGA=1)
#define  AD_DATA_RATE_REG_SET_VALUE     0x00    //ADC data rate register(50SPS)
#define  IO_CONTORL_REG_SET_VALUE       0xF0    //I/O contorl register
#define  STATUS1_REG_SET_VALUE          0x00    //status1 register

/*SGM58601 MUX register configuration*/
#define  MUX_CHN1_SET_VALUE             0x78    //0x08 Indicates the conversion of AD channel 1
#define  MUX_CHN2_SET_VALUE             0x68    //0x18 Indicates the conversion of AD channel 2
#define  MUX_CHN3_SET_VALUE             0x58    //0x28 Indicates the conversion of AD channel 3
#define  MUX_CHN4_SET_VALUE             0x48    //0x38 Indicates the conversion of AD channel 4
#define  MUX_CHN5_SET_VALUE             0x38    //0x48 Indicates the conversion of AD channel 5
#define  MUX_CHN6_SET_VALUE             0x28    //0x58 Indicates the conversion of AD channel 6
#define  MUX_CHN7_SET_VALUE             0x18    //0x68 Indicates the conversion of AD channel 7
#define  MUX_CHN8_SET_VALUE             0x08    //0x78 Indicates the conversion of AD channel 8
#endif /*__SGM58601_H__*/

完成前期的准备工作后,进入SGM58601的调试阶段;

在这一部分正式开始编写SGM58601的驱动源代码,内容包括CS片选及相关的GPIO配置、按照数据手册的配置指导进行芯片初始化、最后执行通道扫描。

初始化源程序如下:

/***********************************************************************************
*说 明:此C文件为圣邦威58601-AD驱动源文件
*创 建:MaJinWen
*时 间:2023-03-09
*版 本:V_1.0.0
*修 改:none
************************************************************************************/
#include <string.h>
#include "SGM58601.h"
#include "spi0.h"

ai_contorl  ai_Ctr;  //ADC控制结构体
/*SGM58601初始化*/
uint8_t SGM58601_init(void)
{
    memset(&ai_Ctr, 0x00, sizeof(ai_contorl));    //clear AI contorl register
    
    /*enable GPIO port RCU*/
//  rcu_periph_clock_enable(RCU_GPIOA);         in USART0 enable
    rcu_periph_clock_enable(RCU_GPIOB);       
//  rcu_periph_clock_enable(RCU_GPIOC);         in USART2 enable
    
    /*SPI0初始化*/
    spi0_init();
    
    /*AD1: SYNC1 as SPI0-NSS*/
    /* config PC5 as DRDY1 */
//  gpio_init(GPIOC, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_5);      //initialization has already been done elsewhere---20241226
    /* config PB1 as RESET1 */
    gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_1);
    /* config PA4 as SPI0_NSS(CS1) */
    gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_4);   
    
    SET_RESET1_HIGH;
    SET_CS1_HIGH;  
    
    /*SGM58601初始化配置*/
    SGM58601_init_config();
    return 1;
}

SGM58601配置源代码如下:

/*SGM58601 initialization*/
uint8_t SGM58601_init_config(void)
{
    uint16_t i = 0;  //as temporary delay count
    
    memset(&reg_value_cache1, 0x00, sizeof(reg_value_cache1));
    memset(&reg_value_cache2, 0x00, sizeof(reg_value_cache2));
    
    /*calc default calibration coefficient*/
    default_cali_calc();
    
    //reset SGM58601
    SET_RESET1_LOW;
    for(i = 0; i < 200; i++){/*none*/};   //delay 7us
    SET_RESET1_HIGH;   
    DRDY1_ready_flag = 0;
    while(DRDY1_ready_flag==0){/*none*/};

    /*configuration SGM58601 status register*/
    ai_Ctr.status_reg[0] = STATUS_REG_SET_VALUE; //   | ANALOG_INPUT_BUFFER_ENABLE;
    ai_Ctr.tran_commond[0] = (ai_Ctr.status_reg[0] << 16) | ((uint32_t)OPREATION_REG_NUM_1 << 8) | ((uint32_t)STATUS_REG|(uint32_t)WREG);
        
    spi0_transmit_data(3, (uint8_t *)&ai_Ctr.tran_commond[0]);
    
    /*configuration SGM58601 I/O contorl register*/
    ai_Ctr.gpio_conReg[0] = IO_CONTORL_REG_SET_VALUE ;
    ai_Ctr.tran_commond[0] = (ai_Ctr.gpio_conReg[0] << 16) | ((uint32_t)OPREATION_REG_NUM_1 << 8) | ((uint32_t)IO_REG|(uint32_t)WREG);
    
    spi0_transmit_data(3, (uint8_t *)&ai_Ctr.tran_commond[0]);
        
    /*configuration SGM58601 adc contorl register*/
    ai_Ctr.ad_conReg[0] = SET_PGA_1;
    ai_Ctr.tran_commond[0] = (ai_Ctr.ad_conReg[0] << 16) | ((uint32_t)OPREATION_REG_NUM_1 << 8) | ((uint32_t)ADCON_REG|(uint32_t)WREG);
      
    spi0_transmit_data(3, (uint8_t *)&ai_Ctr.tran_commond[0]);
    
    /*configuration SGM58601 adc data rate register*/
    ai_Ctr.dataRate_reg[0] = SET_DATA_RATE_50SPS;
    ai_Ctr.tran_commond[0] = (ai_Ctr.dataRate_reg[0] << 16) | ((uint32_t)OPREATION_REG_NUM_1 << 8) | ((uint32_t)DRATE_REG | (uint32_t)WREG);
    
    spi0_transmit_data(3, (uint8_t *)&ai_Ctr.tran_commond[0]);

    DRDY1_ready_flag = 0;
    while(DRDY1_ready_flag==0){/*none*/};
     
    return 1;
}

至此,SGM58601的配置工作已经全部完成,接着便是进入周期扫描过程。

注意:由于篇幅有限,此处仅扫描了一个通道,其它通道扫描过程相同。

/*SGM58601 Scan*/
uint8_t sgm58601_scan(uint16_t scan_count)
{
    uint32_t cache1[3] = {0, 0, 0};
    
    uint16_t samp_count = 0; //Sampling count   
    
    /*Scan channel_1*/
    for(ai_Ctr.sample_count = 0, ai_Ctr.sample_sum[0] = 0, ai_Ctr.sample_count < scan_count; /*count in */)
    {
        if(samp_count == 0)  
        {    
            /*configuration SGM58601 MUX register*/
            ai_Ctr.mux_conReg[0] = MUX_CHN1_SET_VALUE;   //enable AD channel_1
            ai_Ctr.tran_commond[0] = (ai_Ctr.mux_conReg[0] << 16) | ((uint32_t)OPREATION_REG_NUM_1 << 8) | ((uint32_t)MUX_REG|(uint32_t)WREG);
         
            spi0_transmit_data(3, (uint8_t *)&ai_Ctr.tran_commond[0]);
            samp_count=1;   
        }   
        
        /*read back data register*/
        ai_Ctr.tran_commond[0] = (uint32_t)RDATA;   //read AD channel_1
        
        DRDY1_ready_flag = 0;
        while(DRDY1_ready_flag==0){/*none*/};       
        
        spi0_transmit_data(4, (uint8_t *)&ai_Ctr.tran_commond[0]);
        read_adc_data(0, &spi0_ctr.rec_data[1]);   //fill AD channel_1
            
        cache1[ai_Ctr.sample_count-1] = ai_Ctr.adc_data[0];
        
        if(ai_Ctr.sample_count == (scan_count-1))
        {               
            ai_Ctr.sample_ave[0] = medianFilter(cache1[0], cache1[1], cache1[2]);
        }
        ai_Ctr.sample_count++;
    }
}

至此,SGM58601芯片就可以正常运行。

如果要投入实际项目中,我们还需要额外加一些异常保护,例如:

· 每次回读采样值时,检查配置寄存器的值是否被异常篡改;

· 虽然delta-sigma (ΔΣ) 类型ADC自带滤波功能,但为了保险以及高精度应用,也可以额外加一些软件滤波算法:如平均滤波、中值滤波等,进一步防止异常抖动。


总结思考

以此类推,当拿到一款陌生的AD芯片,想要快速上手,思路很重要;

总结起来,整体思路可分为四步:先熟悉、再了解、搭框架、后完善

有整体思路作为方向指导,接着就是慢慢实现细节落地;

其中较为核心的是紧紧围绕数据手册,这一点至关重要,在绝大多数情况下,当应用过程出现问题,要想到去手册中寻找答案。

建议拿到数据手册时至少通篇读三遍,不放过一个细节!

说在最后,日拱一卒无有尽,功不唐捐终入海

Alt

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值