signal_generator/User/driver/ad7124.c

456 lines
17 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "ad7124.h"
/* Error codes */
#define INVALID_VAL -1 /* Invalid argument */
#define COMM_ERR -2 /* Communication error on receive */
#define AD7124_TIMEOUT -3 /* A timeout has occured */
// 配置ad7124寄存器的值根据实际项目需求配置
static ad7124_st_reg_t ad7124_regs[AD7124_REG_NO] = {
{AD7124_STATUS, 0x00, AD7124_SIZE_1, AD7124_R}, /* AD7124_Status */
{AD7124_ADC_CONTROL, 0x0280, AD7124_SIZE_2, AD7124_RW}, /* AD7124_ADC_Control */
{AD7124_DATA, 0x000000, AD7124_SIZE_3, AD7124_R}, /* AD7124_Data */
{AD7124_IOCON1, 0x000000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_IOCon1 */
{AD7124_IOCON2, 0x0000, AD7124_SIZE_2, AD7124_RW}, /* AD7124_IOCon2 */
{AD7124_ID, 0x02, AD7124_SIZE_1, AD7124_R}, /* AD7124_ID */
{AD7124_ERROR, 0x000000, AD7124_SIZE_3, AD7124_R}, /* AD7124_Error */
{AD7124_ERROR_EN, 0x000040, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Error_En */
{AD7124_MCLK_COUNT, 0x00, AD7124_SIZE_1, AD7124_R}, /* AD7124_Mclk_Count */
{AD7124_CHANNEL_0, 0x0051, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_0 */
{AD7124_CHANNEL_1, 0x0071, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_1 */
{AD7124_CHANNEL_2, 0x0091, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_2 */
{AD7124_CHANNEL_3, 0x00B1, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_3 */
{AD7124_CHANNEL_4, 0x00D1, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_4 */
{AD7124_CHANNEL_5, 0x00F1, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_5 */
{AD7124_CHANNEL_6, 0x0111, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_6 */
{AD7124_CHANNEL_7, 0x0131, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_7 */
{AD7124_CHANNEL_8, 0x0151, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_8 */
{AD7124_CHANNEL_9, 0x0171, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_9 */
{AD7124_CHANNEL_10, 0x0001, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_10 */
{AD7124_CHANNEL_11, 0x0001, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_11 */
{AD7124_CHANNEL_12, 0x0001, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_12 */
{AD7124_CHANNEL_13, 0x0001, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_13 */
{AD7124_CHANNEL_14, 0x0001, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_14 */
{AD7124_CHANNEL_15, 0x0001, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_15 */
{AD7124_CONFIG_0, 0x01E0, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Config_0 */
{AD7124_CONFIG_1, 0x0040, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Config_1 */
{AD7124_CONFIG_2, 0x0860, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Config_2 */
{AD7124_CONFIG_3, 0x0860, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Config_3 */
{AD7124_CONFIG_4, 0x0860, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Config_4 */
{AD7124_CONFIG_5, 0x0860, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Config_5 */
{AD7124_CONFIG_6, 0x0860, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Config_6 */
{AD7124_CONFIG_7, 0x0860, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Config_7 */
{AD7124_FILTER_0, 0x060040, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Filter_0 */
{AD7124_FILTER_1, 0x060180, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Filter_1 */
{AD7124_FILTER_2, 0x060180, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Filter_2 */
{AD7124_FILTER_3, 0x060180, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Filter_3 */
{AD7124_FILTER_4, 0x060180, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Filter_4 */
{AD7124_FILTER_5, 0x060180, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Filter_5 */
{AD7124_FILTER_6, 0x060180, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Filter_6 */
{AD7124_FILTER_7, 0x060180, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Filter_7 */
{AD7124_OFFSET_0, 0x800000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Offset_0 */
{AD7124_OFFSET_1, 0x800000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Offset_1 */
{AD7124_OFFSET_2, 0x800000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Offset_2 */
{AD7124_OFFSET_3, 0x800000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Offset_3 */
{AD7124_OFFSET_4, 0x800000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Offset_4 */
{AD7124_OFFSET_5, 0x800000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Offset_5 */
{AD7124_OFFSET_6, 0x800000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Offset_6 */
{AD7124_OFFSET_7, 0x800000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Offset_7 */
{AD7124_GAIN_0, 0x500000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Gain_0 */
{AD7124_GAIN_1, 0x500000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Gain_1 */
{AD7124_GAIN_2, 0x500000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Gain_2 */
{AD7124_GAIN_3, 0x500000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Gain_3 */
{AD7124_GAIN_4, 0x500000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Gain_4 */
{AD7124_GAIN_5, 0x500000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Gain_5 */
{AD7124_GAIN_6, 0x500000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Gain_6 */
{AD7124_GAIN_7, 0x500000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Gain_7 */
};
static ad7124_st_reg_t ad7124_channel_regs[AD7124_CHANNEL_EN_MAX] = {
{AD7124_CHANNEL_0, 0x8051, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_0 */
{AD7124_CHANNEL_1, 0x8071, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_1 */
{AD7124_CHANNEL_2, 0x8091, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_2 */
{AD7124_CHANNEL_3, 0x80B1, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_3 */
{AD7124_CHANNEL_4, 0x80D1, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_4 */
{AD7124_CHANNEL_5, 0x80F1, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_5 */
{AD7124_CHANNEL_6, 0x8111, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_6 */
{AD7124_CHANNEL_7, 0x8131, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_7 */
{AD7124_CHANNEL_8, 0x8151, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_8 */
{AD7124_CHANNEL_9, 0x8171, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_9 */
};
ad7124_analog_t ad7124_analog[AD7124_CHANNEL_EN_MAX] = {NULL}; // AD通道采样结构体数组用于存放AD通道采样数据
/**
* @brief 无校验读取AD7124寄存器
*
* 读取AD7124的寄存器值不进行校验。
*
* @param p_reg 指向要读取的寄存器结构的指针
*
* @return 读取成功返回0失败返回负值
*/
int32_t ad7124_no_check_read_register(ad7124_st_reg_t *p_reg)
{
int32_t ret = 0;
uint8_t buffer[8] = {0, 0, 0, 0, 0, 0, 0, 0};
uint8_t i = 0;
uint8_t add_status_length = 0;
/* Build the Command word */
buffer[0] = AD7124_COMM_REG_WEN | AD7124_COMM_REG_RD |
AD7124_COMM_REG_RA(p_reg->addr);
/*
* If this is an AD7124_DATA register read, and the DATA_STATUS bit is set
* in ADC_CONTROL, need to read 4, not 3 bytes for DATA with STATUS
*/
if ((p_reg->addr == AD7124_DATA) &&
(ad7124_regs[AD7124_ADC_CONTROL].value & AD7124_ADC_CTRL_REG_DATA_STATUS))
{
add_status_length = 1; // 此处是根据寄存器配置而决定,根据AD7124_ADC_CONTROL第10位决定
}
/* Read data from the device */
ret = ad7124_read_write_spi(buffer, p_reg->size + 1 + add_status_length);
if (ret < 0)
return ret;
/*
* if reading Data with 4 bytes, need to copy the status byte to the STATUS
* register struct value member
*/
if (add_status_length)
{
ad7124_regs[AD7124_STATUS].value = buffer[p_reg->size + 1];
}
/* Build the result */
p_reg->value = 0;
for (i = 1; i < p_reg->size + 1; i++)
{
p_reg->value <<= 8;
p_reg->value += buffer[i];
}
return ret;
}
/**
* @brief 向AD7124寄存器写入数据不进行校验
*
* 将数据写入指定的AD7124寄存器不进行数据校验。
*
* @param reg 指向要写入数据的寄存器地址和值的指针
* @return 写入结果成功返回0失败返回负值
*/
int32_t ad7124_no_check_write_register(ad7124_st_reg_t *reg)
{
int32_t ret = 0;
int32_t reg_value = 0;
uint8_t wr_buf[8] = {0, 0, 0, 0, 0, 0, 0, 0};
uint8_t i = 0;
/* Build the Command word */
wr_buf[0] = AD7124_COMM_REG_WEN | AD7124_COMM_REG_WR |
AD7124_COMM_REG_RA(reg->addr);
/* Fill the write buffer */
reg_value = reg->value;
for (i = 0; i < reg->size; i++)
{
wr_buf[reg->size - i] = reg_value & 0xFF;
reg_value >>= 8;
}
/* Write data to the device */
ret = ad7124_read_write_spi(wr_buf, reg->size + 1);
return ret;
}
/**
* @brief 从AD7124寄存器读取数据
*
* 该函数用于从AD7124的指定寄存器中读取数据。
*
* @param p_reg 指向一个ad7124_st_reg_t类型的指针其中包含了要读取的寄存器的地址。
*
* @return 返回读取到的数据,如果读取失败则返回负数。
*
* 在读取寄存器之前会先检查ERROR寄存器的SPI_IGNORE_ERR位
*/
int32_t ad7124_read_register(ad7124_st_reg_t *p_reg)
{
int32_t ret;
if (p_reg->addr != AD7124_ERROR && (ad7124_regs[AD7124_ERROR_EN].value & AD7124_ERREN_REG_SPI_IGNORE_ERR_EN))
{
ret = ad7124_wait_for_spi_ready(AD7124_RDY); // 读寄存器之前检查ERROR寄存器的SPI_IGNORE_ERR位
if (ret < 0)
return ret;
}
ret = ad7124_no_check_read_register(p_reg);
return ret;
}
/**
* @brief 向AD7124寄存器写入数据
*
* 将数据写入AD7124的指定寄存器。如果错误寄存器中启用了忽略SPI错误的功能则在写入前会等待SPI接口准备就绪。
*
* @param p_reg 指向要写入数据的寄存器结构体的指针
*
* @return 返回写入操作的结果。如果操作成功则返回0否则返回负数表示错误。
*/
int32_t ad7124_write_register(ad7124_st_reg_t *p_reg)
{
int32_t ret;
if ((ad7124_regs[AD7124_ERROR_EN].value & AD7124_ERREN_REG_SPI_IGNORE_ERR_EN))
{
ret = ad7124_wait_for_spi_ready(AD7124_RDY);
if (ret < 0)
return ret;
}
ret = ad7124_no_check_write_register(p_reg);
return ret;
}
/**
* @brief 重置AD7124设备
*
* 该函数通过SPI接口向AD7124发送重置命令并等待设备完成上电过程。
*
* @return 返回函数执行结果成功返回0失败返回错误码。
*/
int32_t ad7124_reset(void)
{
int32_t ret = 0;
uint8_t wr_buf[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; // 发送64个1复位ad7124芯片
ret = ad7124_read_write_spi(wr_buf, 8);
/* Read POR bit to clear */
ret = ad7124_wait_to_power_on(AD7124_RDY);
return ret;
}
/**
* @brief 等待SPI接口准备就绪
*
* 等待AD7124的SPI接口准备就绪直到超时。
*
* @param timeout 超时时间(单位:毫秒)
* @return 成功返回0超时返回AD7124_TIMEOUT
*/
int32_t ad7124_wait_for_spi_ready(uint32_t timeout)
{
int32_t ret;
int8_t ready = 0;
while (!ready && --timeout)
{
/* Read the value of the Error Register */
ret = ad7124_read_register(&ad7124_regs[AD7124_ERROR]);
if (ret < 0)
return ret;
/* Check the SPI IGNORE Error bit in the Error Register */
ready = (ad7124_regs[AD7124_ERROR].value &
AD7124_ERR_REG_SPI_IGNORE_ERR) == 0;
}
return timeout ? 0 : AD7124_TIMEOUT;
}
/**
* @brief 等待AD7124电源开启
*
* 此函数将等待AD7124设备电源开启直到超时或检测到电源开启标志。
*
* @param timeout 超时时间
*
* @return 返回0表示成功返回AD7124_TIMEOUT表示超时
*/
int32_t ad7124_wait_to_power_on(uint32_t timeout)
{
int32_t ret;
int8_t powered_on = 0;
while (!powered_on && timeout--)
{
ret = ad7124_read_register(&ad7124_regs[AD7124_STATUS]);
if (ret < 0)
return ret;
/* Check the POR_FLAG bit in the Status Register */
powered_on = (ad7124_regs[AD7124_STATUS].value &
AD7124_STATUS_REG_POR_FLAG) == 0;
}
return (timeout || powered_on) ? 0 : AD7124_TIMEOUT;
}
/**
* @brief 等待AD7124转换准备就绪
*
* 该函数等待AD7124完成转换并准备就绪。如果等待超时则返回错误码。
*
* @param timeout 超时时间
* @return 成功时返回0超时时返回AD7124_TIMEOUT
*/
int32_t ad7124_wait_for_conv_ready(uint32_t timeout)
{
int32_t ret;
int8_t ready = 0;
while (!ready && --timeout)
{
/* Read the value of the Status Register */
ret = ad7124_read_register(&ad7124_regs[AD7124_STATUS]);
if (ret < 0)
return ret;
/* Check the RDY bit in the Status Register */
ready = (ad7124_regs[AD7124_STATUS].value &
AD7124_STATUS_REG_RDY) == 0;
}
return timeout ? 0 : AD7124_TIMEOUT;
}
/**
* @brief 从AD7124读取数据
*
* 从AD7124的数据寄存器中读取数据值。
*
* @return 读取到的数据值
*/
int32_t ad7124_read_data(void)
{
int32_t read_data;
/* Read the value of the Status Register */
ad7124_read_register(&ad7124_regs[AD7124_DATA]);
/* Get the read result */
read_data = ad7124_regs[AD7124_DATA].value;
return read_data;
}
/**
* @brief 从AD7124获取模拟信号数据
*
* 该函数通过SPI接口从AD7124芯片获取模拟信号数据并将数据保存到ad7124_analog中。
*
* @details
* - 遍历所有模拟通道,对每个通道执行以下操作:
* - 等待AD7124完成转换。
* - 读取转换后的数据。
* - 计算电压值(单极性计算公式)。
* - 计算电流值(基于电压值和电阻值),有的通道没有电流值可以忽略。
*
* @note
* - 转换完成后通过公式计算电压和电流值并将结果保存到全局数组ad7124_analog中。
* - 电压计算公式Code = (0xFFFFFF × AIN × Gain)/VREF其中VREF为参考电压GAIN为增益AD_CODE为AD代码。
* - 电流计算公式:电流 = 电压 / 电阻 * 1000其中电阻值为AD7124_RES单位转换为mA。
*/
// void ad7124_get_analog(void)
// {
// int32_t read_data;
// uint8_t i;
// uint8_t channel;
// // for (i = STOP_NC_ADC; i < AD7124_CHANNEL_EN_MAX; i++)
// // {
// // ad7124_regs[AD7124_CHANNEL_0].value = ad7124_channel_regs[i].value;
// // ad7124_write_register(&ad7124_regs[AD7124_CHANNEL_0]);
// // ad7124_read_register(&ad7124_regs[AD7124_STATUS]);
// while (ad7124_wait_for_conv_ready(AD7124_RDY))
// ; // 等待转换完成
// channel = ad7124_regs[AD7124_STATUS].value;
// ad7124_analog[channel].channel = channel;
// read_data = ad7124_read_data();
// ad7124_analog[channel].data = read_data;
// ad7124_analog[channel].voltage = (float)(read_data * VREF / GAIN / AD_CODE); // AD7124单极性计算公式Code = (0xFFFFFF × AIN × Gain)/VREF
// ad7124_analog[channel].current = (float)(ad7124_analog[channel].voltage / AD7124_RES * 1000); // 乘1000是为了将单位转换为mA
// // ad7124_regs[AD7124_CHANNEL_0].value = 0;
// // ad7124_write_register(&ad7124_regs[AD7124_CHANNEL_0]);
// // }
// }
void ad7124_get_analog(uint8_t channel_nr)
{
int32_t read_data;
// for (i = STOP_NC_ADC; i < AD7124_CHANNEL_EN_MAX; i++)
// {
ad7124_regs[AD7124_CHANNEL_0].value = ad7124_channel_regs[channel_nr].value;
ad7124_write_register(&ad7124_regs[AD7124_CHANNEL_0]);
while (ad7124_wait_for_conv_ready(AD7124_RDY))
; // 等待转换完成
ad7124_analog[channel_nr].channel = channel_nr;
read_data = ad7124_read_data();
ad7124_analog[channel_nr].data = read_data;
ad7124_analog[channel_nr].voltage = (float)(read_data * VREF / GAIN / AD_CODE); // AD7124单极性计算公式Code = (0xFFFFFF × AIN × Gain)/VREF
ad7124_analog[channel_nr].current = (float)(ad7124_analog[channel_nr].voltage / AD7124_RES * 1000); // 乘1000是为了将单位转换为mA
ad7124_regs[AD7124_CHANNEL_0].value = 0;
ad7124_write_register(&ad7124_regs[AD7124_CHANNEL_0]);
// }
}
/**
* @brief 配置AD7124设备
*
* 该函数负责初始化AD7124设备初始化寄存器。
*
* @return 初始化结果成功返回0失败返回负数
*/
int32_t ad7124_setup(void)
{
int32_t ret;
uint8_t reg_nr;
// board_spi_init(AD7124); // 初始化SPI,因为DAC161的SPI要和AD7124共用并且时序不一样所以要先初始化SPI接口。
/* Reset the device interface.*/
ret = ad7124_reset();
if (ret < 0)
return ret;
HAL_Delay(10);
ad7124_read_register(&ad7124_regs[AD7124_ID]);
/* Initialize registers AD7124_ADC_Control through AD7124_Filter_7. */
for (reg_nr = AD7124_STATUS; reg_nr < AD7124_OFFSET_0; reg_nr++) // 对ad7124的可写寄存器进行配置不包括只读寄存器
{
// ret = ad7124_read_register(&ad7124_regs[reg_nr]);
if (ad7124_regs[reg_nr].rw == AD7124_RW)
{
ret = ad7124_write_register(&ad7124_regs[reg_nr]);
ret = ad7124_read_register(&ad7124_regs[reg_nr]);
if (ret < 0)
break;
}
}
HAL_GPIO_WritePin(AD7124_SYNC_GPIO_Port, AD7124_SYNC_Pin, GPIO_PIN_SET); // AD7124同步信号使能
return ret;
}
/**
* @brief 通过SPI接口对AD7124进行读写操作
*
* 通过SPI接口对AD7124进行读写操作
*
* @param buff 指向待传输数据的指针
* @param length 待传输数据的长度
*
* @return 传输结果成功返回0失败返回负数
*/
int32_t ad7124_read_write_spi(uint8_t *buff, uint8_t length)
{
int32_t ret;
board_spi_init(AD7124); // 初始化SPI,因为DAC161的SPI要和AD7124共用并且时序不一样所以要先初始化SPI接口。
board_spi_cs_on(AD7124);
ret = spi_transmit_receive(&hspi1, buff, length);
board_spi_cs_off(AD7124);
return ret;
}