笔记简介
本篇笔记用于记录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):
详细下载地址如下:
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的时钟相位与极性是:空闲态为低,在第二个边沿采样;
配置程序如下:
/*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芯片的操作命令、寄存器地址、寄存器的描述在数据手册的末尾。
打包后的配置头文件如下:
***********************************************************************************
*说 明:此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(®_value_cache1, 0x00, sizeof(reg_value_cache1));
memset(®_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芯片,想要快速上手,思路很重要;
总结起来,整体思路可分为四步:先熟悉、再了解、搭框架、后完善。
有整体思路作为方向指导,接着就是慢慢实现细节落地;
其中较为核心的是紧紧围绕数据手册,这一点至关重要,在绝大多数情况下,当应用过程出现问题,要想到去手册中寻找答案。
建议拿到数据手册时至少通篇读三遍,不放过一个细节!
说在最后,日拱一卒无有尽,功不唐捐终入海。