這篇介紹的時高精度、速度AD晶片AD7190的驅動,針對STM32,并且使用的時HAL庫,改成其他庫也很容易,隻需要把相關通訊部分改了就行。
- SPI設定,首先看AD7190的手冊時序圖

時序圖中已經包含了很多資訊,是以SPI配置如下,其中時鐘最高為5M,在資料手冊中看到的t3有最小時間限制:
- CS引腳可以一直為低的狀态,表示一直選中,如果要多片通訊,可以設定為其他,先把驅動程式放出來
#include "ad7190.h"
//#define CS_H HAL_GPIO_WritePin(SPI1_NSS_GPIO_Port, SPI1_NSS_Pin, GPIO_PIN_SET)
//#define CS_L HAL_GPIO_WritePin(SPI1_NSS_GPIO_Port, SPI1_NSS_Pin, GPIO_PIN_RESET)
static AD7190_REG_T ad7190_obj;
void init_AD7190_reg_cmds(AD7190_REG_Ptr ad7190_reg_ptr);
unsigned char SPIDEV1_single_transfer(unsigned char data_byte)
{
uint8_t data=0;
//CS_L;
//HAL_Delay(1);
HAL_SPI_TransmitReceive(&hspi4, &data_byte, &data, 1, 1000);
//HAL_Delay(1);
//CS_H;
return 0;
}
int SPIDEV1_transfer(unsigned char *send, unsigned char *receive, unsigned char bytes_num)
{
//uint8_t i=0;
//CS_L;
//HAL_Delay(1);
HAL_SPI_TransmitReceive(&hspi4, send, receive, bytes_num, 5000);
//HAL_Delay(1);
//CS_H;
return 0;
}
/****************************************************************
* Function Name : init_AD7190_reg_cmds
* Description : API to initialize the AD7190 commands structure
* for communication
* Returns : None
* Params @ad7190_reg_ptr: Pointer to commands structure
****************************************************************/
void init_AD7190_reg_cmds(AD7190_REG_Ptr ad7190_reg_ptr)
{
ad7190_reg_ptr->cmd_rd_ID_reg = COM_READ_ID_REG_CMD;
ad7190_reg_ptr->cmd_rd_config_reg = COM_READ_CONFIG_REG_CMD;
ad7190_reg_ptr->cmd_rd_data_reg = COM_READ_DATA_REG_CMD;
ad7190_reg_ptr->cmd_rd_full_scale_reg = COM_READ_FULL_SCALE_REG_CMD;
ad7190_reg_ptr->cmd_rd_gpocon_reg = COM_READ_GPCON_REG_CMD;
ad7190_reg_ptr->cmd_rd_mode_reg = COM_READ_MODE_REG_CMD;
ad7190_reg_ptr->cmd_rd_offset_reg = COM_READ_OFFSET_REG_CMD;
ad7190_reg_ptr->cmd_rd_status_reg = COM_READ_STATUS_REG_CMD;
ad7190_reg_ptr->cmd_wr_gpocon_reg = COM_WRITE_GPCON_RED_CMD;
ad7190_reg_ptr->cmd_wr_config_reg = COM_WRITE_CONFIG_REG_CMD;
ad7190_reg_ptr->cmd_wr_mode_reg = COM_WRITE_MODE_REG_CMD;
}
/****************************************************************
* Function Name : init_AD7190_cmds
* Description : Initialize the AD7190 commands structure
* for communication
* Returns : None
* Params : None
****************************************************************/
void init_AD7190_cmds()
{
init_AD7190_reg_cmds(&ad7190_obj);
}
/****************************************************************
* Function Name : AD7190_configure
* Description : Configure/Write to the configuration register
* for communication
* Returns : (-1) typecast for error, 0 for success
* Params @cbyte_2: Data to write to Most Significant Byte
* @cbyte_1: Data to write to Middle Byte
* @cbyte_0: Data to write to Least Significant Byte
****************************************************************/
char AD7190_configure(unsigned char cbyte_2, unsigned char cbyte_1, unsigned char cbyte_0)
{
char check_ret = 0x00;
unsigned char ad7190_id = 0x00;
ad7190_id = AD7190_get_ID();
//printf("Initializing AD7190 ADC Device ID = 0x%x\r\n", ad7190_id);
/* Go to write to configuration register */
check_ret = SPIDEV1_single_transfer(ad7190_obj.cmd_wr_config_reg);
/* Write to Most Significant Byte */
check_ret = SPIDEV1_single_transfer(cbyte_2);
/* Write to Mid Byte */
check_ret = SPIDEV1_single_transfer(cbyte_1);
/* Write to Least Significant Byte */
check_ret = SPIDEV1_single_transfer(cbyte_0);
return (check_ret);
}
/****************************************************************
* Function Name : AD7190_mode
* Description : Configure/Write to the mode register
* for communication
* Returns : (-1) typecast for error, 0 for success
* Params @mbyte_2: Data to write to Most Significant Byte
* @mbyte_1: Data to write to Middle Byte
* @mbyte_fs: Data to write to Least Significant Byte
****************************************************************/
char AD7190_mode(unsigned char mbyte_2, unsigned char mbyte_1, unsigned char mbyte_fs)
{
char check_ret = 0x00;
/* Go to write to configuration register */
check_ret = SPIDEV1_single_transfer(ad7190_obj.cmd_wr_mode_reg);
/* Write to Most Significant Byte */
check_ret = SPIDEV1_single_transfer(mbyte_2);
/* Write to Mid Byte */
check_ret = SPIDEV1_single_transfer(mbyte_1);
/* Write to Least Significant Byte */
check_ret = SPIDEV1_single_transfer(mbyte_fs);
//add new gpocon 打開switch
check_ret = SPIDEV1_single_transfer(ad7190_obj.cmd_wr_gpocon_reg);
check_ret = SPIDEV1_single_transfer(0x40);
return (check_ret);
}
/****************************************************************
* Function Name : AD7190_read_status_reg
* Description : Read the status register
* Returns : Contents of the status register
* Params : None
****************************************************************/
unsigned char AD7190_read_status_reg()
{
unsigned char status_reg = 0x00;
SPIDEV1_single_transfer(ad7190_obj.cmd_rd_status_reg);
status_reg = SPIDEV1_single_transfer(0x00);
return (status_reg);
}
/****************************************************************
* Function Name : AD7190_get_ID
* Description : Read the ID register
* Returns : Contents of the ID register
* Params : None
****************************************************************/
unsigned char AD7190_get_ID()
{
unsigned char ad7190_ID = 0x00;
SPIDEV1_single_transfer(ad7190_obj.cmd_rd_gpocon_reg);
ad7190_ID = SPIDEV1_single_transfer(0x00);
return (ad7190_ID);
}
/****************************************************************
* Function Name : AD7190_reset
* Description : Resets the AD7190
* Returns : None
* Params : None
****************************************************************/
void AD7190_reset()
{
char cnt;
for(cnt = 0 ; cnt < 55; cnt++)
SPIDEV1_single_transfer(0xFF);
}
/****************************************************************
* Function Name : AD7190_read_data
* Description : Read the data register
* Returns : Contents of the data register
* Params : None
****************************************************************/
int AD7190_read_data(void)
{
unsigned char Tx_bytes[]={0xff,0xff,0xff}, Rx_bytes[3] = {0,0,0}, reg_status = 0, drdy_bit;
int adc_data = 0x00;
//memset(Tx_bytes, 0xFF, sizeof(Tx_bytes));
//memset(Rx_bytes, 0, sizeof(Rx_bytes));
drdy_bit = 1;
reg_status = AD7190_read_status_reg();
drdy_bit = reg_status & 0x80;
if (drdy_bit == 0x00)
{
SPIDEV1_single_transfer(ad7190_obj.cmd_rd_data_reg);
if (SPIDEV1_transfer(Tx_bytes, Rx_bytes, 3) == 0)
{
adc_data = (adc_data | Rx_bytes[0]) << 8;
adc_data = (adc_data | Rx_bytes[1]) << 8;
adc_data = adc_data | Rx_bytes[2];
//printf("%lu\r\n",adc_data);
}
else
{
//printf("(AD7190_read_test)Transaction Failed\r\n");
adc_data = 0xffffffff;
}
}
else
{
adc_data = 0xffffffff;
}
return (adc_data);
}
/****************************************************************
* Function Name : AD7190_dump_regs
* Description : Dump the contents of the registers
* Returns : None
* Params @regs_to_dump: Registers to dump
****************************************************************/
void AD7190_dump_regs(REG_DumpT regs_to_dump)
{
unsigned char Tx_bytes[3]={0xff,0xff,0xff}, Rx_bytes[3] = {0,0,0}, reg_status_id = 0;
unsigned long read_config_mode = 0x00;
//memset(Tx_bytes, 0xFF, sizeof(Tx_bytes));
//memset(Rx_bytes, 0, sizeof(Rx_bytes));
switch(regs_to_dump)
{
case DUMP_CONFIG_REG_CONTENTS:
SPIDEV1_single_transfer(ad7190_obj.cmd_rd_config_reg);
if (SPIDEV1_transfer(Tx_bytes, Rx_bytes, 3) == 0)
{
read_config_mode = (read_config_mode | Rx_bytes[0]) << 8;
read_config_mode = (read_config_mode | Rx_bytes[1]) << 8;
read_config_mode = read_config_mode | Rx_bytes[2];
//printf("Dump - Configuration Register = 0X%x\r\n",read_config_mode);
}
else
{
//printf("(AD7190_dump_regs)Transaction Failed\r\n");
}
break;
case DUMP_MODE_REG_CONTENTS:
SPIDEV1_single_transfer(ad7190_obj.cmd_rd_mode_reg);
if (SPIDEV1_transfer(Tx_bytes, Rx_bytes, 3) == 0)
{
read_config_mode = (read_config_mode | Rx_bytes[0]) << 8;
read_config_mode = (read_config_mode | Rx_bytes[1]) << 8;
read_config_mode = read_config_mode | Rx_bytes[2];
//printf("Dump - Mode Register = 0X%x\r\n",read_config_mode);
}
else
{
//printf("(AD7190_dump_regs)Transaction Failed\r\n");
}
break;
case DUMP_STATUS_REG_CONTENTS:
reg_status_id = AD7190_read_status_reg();
//printf("Dump - Status Register = 0X%x\r\n",reg_status_id);
break;
case DUMP_ID_REG_CONTENTS:
reg_status_id = AD7190_get_ID();
//printf("Dump - ID Register = 0X%x\r\n",reg_status_id);
break;
case DUMP_CONFIG_AND_MODE_REG_CONTENTS:
default:
//SPIDEV1_single_transfer(ad7190_obj.cmd_rd_config_reg);
//if (SPIDEV1_transfer(Tx_bytes, Rx_bytes, 3) == 0)
//{
// read_config_mode = (read_config_mode | Rx_bytes[0]) << 8;
// read_config_mode = (read_config_mode | Rx_bytes[1]) << 8;
// read_config_mode = read_config_mode | Rx_bytes[2];
// //printf("Dump - Configuration Register = 0X%x\r\n",read_config_mode);
//}
//else
//{
// //printf("(AD7190_dump_regs)Transaction Failed\r\n");
//}
//
memset(Rx_bytes, 0, sizeof(Rx_bytes));
//read_config_mode = 0x00;
SPIDEV1_single_transfer(ad7190_obj.cmd_rd_mode_reg);
if (SPIDEV1_transfer(Tx_bytes, Rx_bytes, 3) == 0)
{
read_config_mode = (read_config_mode | Rx_bytes[0]) << 8;
read_config_mode = (read_config_mode | Rx_bytes[1]) << 8;
read_config_mode = read_config_mode | Rx_bytes[2];
//printf("Dump - Mode Register = 0X%x\r\n",read_config_mode);
}
else
{
//printf("(AD7190_dump_regs)Transaction Failed\r\n");
}
break;
}
}
下面時ad7190.h檔案
#include "stm32h7xx_hal.h"
#include "main.h"
#ifndef AD7190_H_
#define AD7190_H_
/* Commands to write to specific registers */
#define COM_WRITE_CONFIG_REG_CMD 0x10
#define COM_WRITE_MODE_REG_CMD 0x08
#define COM_WRITE_GPCON_RED_CMD 0x28
/* Commands to read from specific registers */
#define COM_READ_CONFIG_REG_CMD 0x50
#define COM_READ_STATUS_REG_CMD 0x40
#define COM_READ_MODE_REG_CMD 0x48
#define COM_READ_DATA_REG_CMD 0x58
#define COM_READ_GPCON_REG_CMD 0x68
#define COM_READ_ID_REG_CMD 0x60
#define COM_READ_OFFSET_REG_CMD 0x70
#define COM_READ_FULL_SCALE_REG_CMD 0x78
/* Sampling Rates */
#define FS_60_HZ 0x50
#define FS_300_HZ 0x10
#define FS_960_HZ 0x05
#define FS_2400_HZ 0x02
#define FS_4800_HZ 0x01
/* Register settings commands for Configuration Register */
#define CONFIG_REG_CMD_MSB 0x00
#define CONFIG_REG_CMD_MID 0x01
/*May have to change Gain depending on input signal voltage
See Table 19 in AD7190 datasheet for more information*/
#define CONFIG_REG_CMD_LSB 0x01//0x1F
/* Register settings commands for Mode Register */
#define MODE_REG_CMD_MSB 0x08
#define MODE_REG_CMD_MID 0x00
#define MODE_REG_CMD_LSB FS_4800_HZ
/* Read the data register continously and place the data on DOUT */
//#define COMM_REG_CREAD 0x5C
/* Structure Map of AD7190 internal registers
* for read and write operations
*/
typedef struct{
unsigned char cmd_rd_status_reg;
unsigned char cmd_wr_mode_reg;
unsigned char cmd_rd_mode_reg;
unsigned char cmd_wr_config_reg;
unsigned char cmd_rd_config_reg;
unsigned char cmd_rd_data_reg;
unsigned char cmd_rd_ID_reg;
unsigned char cmd_rd_gpocon_reg;
unsigned char cmd_wr_gpocon_reg;
unsigned char cmd_rd_offset_reg;
unsigned char cmd_rd_full_scale_reg;
}AD7190_REG_T, *AD7190_REG_Ptr;
/* Enum commands to dump register contents */
typedef enum{
DUMP_CONFIG_REG_CONTENTS,
DUMP_MODE_REG_CONTENTS,
DUMP_STATUS_REG_CONTENTS,
DUMP_ID_REG_CONTENTS,
DUMP_CONFIG_AND_MODE_REG_CONTENTS
}REG_DumpT;
/* AD7190 API's */
void init_AD7190_reg_cmds(AD7190_REG_Ptr ad7190_reg_ptr);
void init_AD7190_cmds(void);
char AD7190_configure(unsigned char cbyte_2, unsigned char cbyte_1, unsigned char cbyte_0);
char AD7190_mode(unsigned char mbyte_2, unsigned char mbyte_1, unsigned char mbyte_fs);
unsigned char AD7190_read_status_reg(void);
unsigned char AD7190_get_ID(void);
void AD7190_reset(void);
int AD7190_read_data(void);
void AD7190_dump_regs(REG_DumpT regs_to_dump);
#endif /* AD7190_H_ */
最後初始化
init_AD7190_cmds();
AD7190_reset();
HAL_Delay(20);
AD7190_configure(CONFIG_REG_CMD_MSB, CONFIG_REG_CMD_MID, CONFIG_REG_CMD_LSB);
AD7190_mode(MODE_REG_CMD_MSB, MODE_REG_CMD_MID, MODE_REG_CMD_LSB);
- 程式最後解讀關鍵部分
首先晶片的讀寫是都要先發送要操作的寄存器,然後才是讀或者寫,這個程式參照了github上面的,做了改進,在AD7190_mode中打開了基準電壓AGND的開關,
//add new gpocon 打開switch
check_ret = SPIDEV1_single_transfer(ad7190_obj.cmd_wr_gpocon_reg);
check_ret = SPIDEV1_single_transfer(0x40);
内部原理圖如下,必須要打開開關才能正常使用
其他的在注釋中已經有詳細的說明,具體還可以參照資料手冊