打印
[学习资料]

以ADC芯片SGM51242向大家展示驱动代码的设计理念

[复制链接]
73|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
dffzh|  楼主 | 2025-5-23 11:15 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 dffzh 于 2025-5-23 11:17 编辑

#申请原创#
@21小跑堂

做嵌入式软件开发时,我们会经常编写包括ADC芯片和DAC芯片等在内的驱动代码;那怎么样编写驱动代码才能提高程序调试效率,以及提高驱动代码后续的可维护性和复用率呢?
今天作者就通过ADC芯片SGM51242向大家展示驱动代码的设计思路和方法,用到的C语言知识点主要包括宏定义、宏函数、枚举类型和位运算符,希望对大家以后设计和编写驱动代码有所帮助。
通用的芯片驱动代码一般包括一个源文件和一个头文件,源文件主要是函数定义,涉及芯片初始化配置、读芯片寄存器(读数据)、写芯片寄存器(写数据)和软复位寄存器等常用操作,头文件主要是宏定义,枚举定义,变量声明和函数声明等。
先附上驱动代码的头文件:
#ifndef __SGM51242_H__
#define __SGM51242_H__

#include "at32f403a_407.h"
#include "bsp_spi_bus.h"

#define SGM51242_GPIO                   GPIOA
#define SGM51242_CS_GPIO           GPIOA   //ADC nSYNC pin
#define SGM51242_CLK_GPIO                   GPIOB
#define SGM51242_MOSI_GPIO                   GPIOB
#define SGM51242_MISO_GPIO                   GPIOB

#define SGM51242_CS_PIN     GPIO_PINS_15
#define SGM51242_CLK_PIN     GPIO_PINS_3
#define SGM51242_MOSI_PIN     GPIO_PINS_5
#define SGM51242_MISO_PIN     GPIO_PINS_4

#define  SGM51242_CS_HIGH()    gpio_bits_write(SGM51242_CS_GPIO, SGM51242_CS_PIN, TRUE)
#define  SGM51242_CS_LOW()     gpio_bits_write(SGM51242_CS_GPIO, SGM51242_CS_PIN, FALSE)

#define  SGM51242_CLK_HIGH()    gpio_bits_write(SGM51242_CLK_GPIO, SGM51242_CLK_PIN, TRUE)
#define  SGM51242_CLK_LOW()     gpio_bits_write(SGM51242_CLK_GPIO, SGM51242_CLK_PIN, FALSE)

#define  SGM51242_MOSI_HIGH()    gpio_bits_write(SGM51242_MOSI_GPIO, SGM51242_MOSI_PIN, TRUE)
#define  SGM51242_MOSI_LOW()     gpio_bits_write(SGM51242_MOSI_GPIO, SGM51242_MOSI_PIN, FALSE)

#define  SGM51242_READ_MISO()   gpio_input_data_bit_read(SGM51242_MISO_GPIO,SGM51242_MISO_PIN)

//ADC register address define
typedef enum {
  NOP_REG = 0x00,  //0000
        SEQUENCE_REG  = 0x02,  //0010
        CONTROL_REG  = 0x03,  //0011
        PIN_CONFIG_REG  = 0x04,  //0100
        PULLDOWN_CONFIG_REG   = 0x06,  //0110
        READBACK_MODE_REG   = 0x07,  //0111
        POWERDOWN_AND_REFCTRL_REG   = 0x0B,  //1011
        SOFTWARE_RESET_REG   = 0x0F,  //1111
}sgm51242_reg_addr_e;

//control register
#define SGM51242_CTRL_REG_BUFFER(x)                (((x) & 0x0001) << 9)
typedef enum {
        BUFFER_CONFIG_DISABLE = 0, //default
        BUFFER_CONFIG_ENABLE = 1,
}sgm51242_control_reg_auxiliary_buffer_config_e;

#define SGM51242_CTRL_REG_LOCK(x)                (((x) & 0x0001) << 7)
typedef enum {
        LOCK_CONFIG_DISABLE = 0, //default
        LOCK_CONFIG_ENABLE = 1,
}sgm51242_control_reg_lock_config_e;

#define SGM51242_CTRL_REG_RANGE(x)                (((x) & 0x0001) << 5)
typedef enum {
        INPUT_RANGE_0_VREF = 0, //default
        INPUT_RANGE_0_2VREF = 1,
}sgm51242_control_reg_input_range_config_e;

//pin configuration register
#define SGM51242_PIN_REG_INPUT_MODE        0x03 //IN0 and IN1 as ADC input

//sequence register
#define SGM51242_SEQUENCE_REG_VDD_MONITOR(x)                (((x) & 0x0001) << 10)
typedef enum {
        VDD_MONITOR_DISABLE = 0, //default
        VDD_MONITOR_ENABLE = 1,
}sgm51242_sequence_reg_vdd_monitor_e;

#define SGM51242_SEQUENCE_REG_REP(x)                (((x) & 0x0001) << 9)
typedef enum {
        REPETITION_DISABLE = 0, //default
        REPETITION_ENABLE = 1,
}sgm51242_sequence_reg_repetition_e;

#define SGM51242_SEQUENCE_REG_TEMP(x)                (((x) & 0x0001) << 8)
typedef enum {
        TEMP_DISABLE = 0, //default
        TEMP_ENABLE = 1,
}sgm51242_sequence_reg_temp_e;

#define SGM51242_SEQUENCE_REG_CONVERSION        0x03 //IN0 and IN1 in conversion sequence

//power-down and reference control register
#define SGM51242_POWERDOWN_AND_REFCTRL_REG_PD_ALL(x)                (((x) & 0x0001) << 10)
typedef enum {
        PD_ALL_D9_BIT = 0, //default
        PD_ALL_POWERDOWN = 1,
}sgm51242_pd_and_ref_reg_pd_all_e;

#define SGM51242_POWERDOWN_AND_REFCTRL_REG_EN_REF(x)                (((x) & 0x0001) << 9)
typedef enum {
        EN_REF_DISABLE = 0, //default
        EN_REF_ENABLE = 1,
}sgm51242_pd_and_ref_reg_en_ref_e;

//software reset register
#define SGM51242_SOFTWARE_RESET_VALUE (0x7DAC)

//readback mode register
#define SGM51242_READBACK_MODE_REG_EN(x)                (((x) & 0x0001) << 6)
typedef enum {
        READBACK_DISABLE = 0, //default
        READBACK_ENABLE = 1,
}sgm51242_readback_mode_reg_en_e;

#define SGM51242_READBACK_REG_VALUE (0x3840)

//pull-down configuration register
#define SGM51242_PULLDOWN_REG_PD_CONFIG(x)                (x)
typedef enum {
        PULLDOWN_85K_DISABLE = 0x00, //default
        PULLDOWN_85K_ENABLE = 0xFF,
}sgm51242_pulldown_reg_pd_en_e;

//ADC channel address
typedef enum {
        ADC_CHANNEL_ADDR_0 = 0x00,
        ADC_CHANNEL_ADDR_1 = 0x01,
}sgm51242_adc_chnnel_addr_e;

extern void sgm51242_delay_us(uint16_t delay_us);
extern void sgm51242_init(void);
extern void sgm51242_write_register(uint16_t addr, uint16_t value);
extern uint16_t sgm51242_read_register(uint16_t addr);
extern uint16_t sgm51242_read_adc_data(void);
extern void sgm51242_software_reset(void);
extern void sgm51242_spi_test(void);
extern uint16_t sgm51242_rw_data(uint16_t data);
extern void sgm51242_sequence_reg_config(void);


#endif /* __SGM51242_H__ */

再附上驱动代码的源文件:
#include "sgm51242.h"

//uint16_t write_data = 0;
uint16_t read_data = 0;
//uint16_t send_data = 0;

void sgm51242_delay_us(uint16_t delay_us)
{
        uint16_t i;

        for(i = 0; i < delay_us; i++)
        {
                ;
        }
}

uint8_t sgm51242_write(uint16_t value)
{
    uint8_t i;

        for(i = 0; i < 16; i++)
        {
            SGM51242_CLK_HIGH();
                if (value & 0x8000)
                {
                        SGM51242_MOSI_HIGH();
                }
                else
                {
                        SGM51242_MOSI_LOW();
                }
                sgm51242_delay_us(2);
                value <<= 1;        
                SGM51242_CLK_LOW();
                sgm51242_delay_us(2);
        }
        //sgm51242_delay_us(2);
    return 0;
}

uint16_t sgm51242_read(void)
{
        uint16_t read_data = 0;
        uint8_t i;

        for(i = 0; i<16; i++)
        {
                SGM51242_CLK_LOW();
                sgm51242_delay_us(2);
                SGM51242_CLK_HIGH();
                read_data = read_data << 1;
                if(SGM51242_READ_MISO())
                {
                        read_data |= 0x0001;
                }
                else
                {
                        read_data &= ~0x0001;
                }
                sgm51242_delay_us(2);
        }
        return read_data;
}


/*sgm51242 init config*/
void sgm51242_init(void)
{
        uint16_t write_data = 0;
        
        SGM51242_CS_HIGH();

        //config readback register
        write_data = SGM51242_READBACK_MODE_REG_EN(READBACK_ENABLE);
        sgm51242_write_register(READBACK_MODE_REG, write_data);

#if 1
        //config sequence register
        write_data = SGM51242_SEQUENCE_REG_VDD_MONITOR(VDD_MONITOR_DISABLE) \
                     | SGM51242_SEQUENCE_REG_REP(REPETITION_ENABLE) \
                     | SGM51242_SEQUENCE_REG_TEMP(TEMP_DISABLE) \
                     | SGM51242_SEQUENCE_REG_CONVERSION;
        sgm51242_write_register(SEQUENCE_REG, write_data);
#endif

        //config control register
        write_data = SGM51242_CTRL_REG_BUFFER(BUFFER_CONFIG_DISABLE)\
                     | SGM51242_CTRL_REG_LOCK(LOCK_CONFIG_DISABLE)\
                     | SGM51242_CTRL_REG_RANGE(INPUT_RANGE_0_VREF);
        sgm51242_write_register(CONTROL_REG, write_data);
        
        //config pin configuration register
        write_data = SGM51242_PIN_REG_INPUT_MODE;
        sgm51242_write_register(PIN_CONFIG_REG, write_data);
        
        //config power-down and reference control register
        write_data = SGM51242_POWERDOWN_AND_REFCTRL_REG_PD_ALL(PD_ALL_D9_BIT)\
                     | SGM51242_POWERDOWN_AND_REFCTRL_REG_EN_REF(EN_REF_DISABLE);
        sgm51242_write_register(POWERDOWN_AND_REFCTRL_REG, write_data);
        
        //config pull-down configuration register
        write_data = SGM51242_PULLDOWN_REG_PD_CONFIG(PULLDOWN_85K_DISABLE);
        sgm51242_write_register(PULLDOWN_CONFIG_REG, write_data);

        SGM51242_CS_HIGH();
}

/**/
/**/
uint16_t sgm51242_rw_data(uint16_t data)
{
    uint16_t read_data = 0;

    while(spi_i2s_flag_get(ADC_SPI_TYPE, SPI_I2S_TDBE_FLAG) == RESET);
        spi_i2s_data_transmit(ADC_SPI_TYPE, data);

        while(spi_i2s_flag_get(ADC_SPI_TYPE, SPI_I2S_RDBF_FLAG) == RESET);
        read_data = spi_i2s_data_receive(ADC_SPI_TYPE);
        return read_data;
}

void sgm51242_send_data(uint16_t write_data)
{
    while(spi_i2s_flag_get(ADC_SPI_TYPE, SPI_I2S_TDBE_FLAG) == RESET);
        spi_i2s_data_transmit(ADC_SPI_TYPE, write_data);
}

uint16_t sgm51242_read_data(void)
{
    uint16_t read_data = 0;

    while(spi_i2s_flag_get(ADC_SPI_TYPE, SPI_I2S_RDBF_FLAG) == RESET);
        read_data = spi_i2s_data_receive(ADC_SPI_TYPE);
        return read_data;
}


/*write data to sgm51242 register*/
void sgm51242_write_register(uint16_t addr, uint16_t value)
{
        uint16_t data_in = 0x0000;
        
        data_in = addr;
        data_in = (data_in << 11) | (value & 0x07FF);
        SGM51242_CS_LOW();
        sgm51242_rw_data(data_in);
        //sgm51242_write(data_in);
        SGM51242_CS_HIGH();
}

/*read data from sgm51242 register*/
uint16_t sgm51242_read_register(uint16_t addr)
{
        uint16_t data_in = 0x0000;
        uint16_t data_out = 0x0000;
        
        data_in = addr;
        data_in = (data_in << 2) | SGM51242_READBACK_REG_VALUE; //first, write data to readback register
        SGM51242_CS_LOW();
        sgm51242_rw_data(data_in);
        SGM51242_CS_HIGH();
        sgm51242_delay_us(1);
        
        SGM51242_CS_LOW();
        data_in = 0x0000;
        data_out = sgm51242_rw_data(data_in); //second, read register data from config addr
        SGM51242_CS_HIGH();
        
        return data_out;
}

/*read adc conversion data from adc data register*/
uint16_t sgm51242_read_adc_data(void)
{
        uint16_t data_out = 0x0000;

        SGM51242_CS_LOW();
        sgm51242_delay_us(60);
        data_out = sgm51242_rw_data(0x0000);
        //data_out = sgm51242_read();
        SGM51242_CS_HIGH();
        sgm51242_delay_us(6);
        
        return data_out;
}

/*config sequence register*/
void sgm51242_sequence_reg_config(void)
{
        uint16_t write_data = 0;

        //config sequence register
        write_data = SGM51242_SEQUENCE_REG_VDD_MONITOR(VDD_MONITOR_DISABLE) \
                     | SGM51242_SEQUENCE_REG_REP(REPETITION_ENABLE) \
                     | SGM51242_SEQUENCE_REG_TEMP(TEMP_DISABLE) \
                     | SGM51242_SEQUENCE_REG_CONVERSION;
        sgm51242_write_register(SEQUENCE_REG, write_data);
}

/*reset sgm51242*/
void sgm51242_software_reset(void)
{
        sgm51242_write_register(SOFTWARE_RESET_REG, SGM51242_SOFTWARE_RESET_VALUE);
        sgm51242_delay_us(1000); //need delay?
}


/*sgm51242 spi test*/
void sgm51242_spi_test(void)
{
        //uint16_t vdd_flag = 0;
        
        //read sequence register
        //read_data = sgm51242_read_register(SEQUENCE_REG);

        //read_data = sgm51242_read_adc_data();
        //if((read_data>>12)==1)
        //{
        //    vdd_flag = 1;
        //}
}

以上向大家展示了一款ADC芯片的驱动代码设计,虽然有些函数由于宏函数和宏定义比较多而看上去比较繁琐复杂,但是其可维护性和可读性却大大提升,希望对大家有一些帮助;你有更好的idea也欢迎来贴分享!毕竟山外有山,人外有人嘛。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

48

主题

500

帖子

5

粉丝