/* * @Author: mypx * @Email: mypx_coder@163.com * @Date: 2025-06-23 10:26:12 * @LastEditors: mypx mypx_coder@163.com * @Description: AD7793 driver implementation */ #include "ad7793.h" #include #include #ifdef DEBUG #include #define DEBUG_PRINTF(fmt, ...) \ do { \ rt_kprintf("[AD7793] " fmt, ##__VA_ARGS__); \ } while (0) #else #define DEBUG_PRINTF(fmt, ...) \ do { \ } while (0) #endif /** * @brief Send SPI command and receive data. * @param dev Pointer to ad7793_dev_t instance. * @param cmd Command byte to send. * @param tx_buf Transmit buffer. * @param rx_buf Receive buffer. * @param len Data length to transfer. * @return Operation status. True if successful, false otherwise. */ static bool ad7793_spi_transfer(ad7793_dev_t *dev, uint8_t cmd, uint8_t *tx_buf, uint8_t *rx_buf, uint16_t len) { AD7793_CHECK_INITIALIZED(dev); uint8_t tx[32] = {0}; uint8_t rx[32] = {0}; tx[0] = cmd; if (tx_buf) { for (uint16_t i = 0; i < len; i++) { tx[i + 1] = tx_buf[i]; } } dev->hw_if->spi_transfer(tx, rx, len + 1); if (rx_buf) { for (uint16_t i = 0; i < len; i++) { rx_buf[i] = rx[i + 1]; } } return true; } /** * @brief Write communication register. * @param dev Pointer to ad7793_dev_t instance. * @param cmd Command byte to write to the communication register. * @return Operation status. True if successful, false otherwise. */ bool ad7793_write_communication(ad7793_dev_t *dev, uint8_t cmd) { AD7793_CHECK_INITIALIZED(dev); dev->hw_if->gpio_set(dev->cs_pin, false); ad7793_spi_transfer(dev, cmd, NULL, NULL, 0); dev->hw_if->gpio_set(dev->cs_pin, true); return true; } /** * @brief Write data to a specified register. * @param dev Pointer to ad7793_dev_t instance. * @param reg Register address to write to. * @param data Data buffer to be written. * @param len Data length (2/3 bytes). * @return Operation status. True if successful, false otherwise. * @detail This function constructs a communication command to write data to the specified register. * It first clears the chip select pin, then performs an SPI transfer to send the command and data. * Finally, it sets the chip select pin back to high. */ bool ad7793_write_reg(ad7793_dev_t *dev, uint8_t reg, uint32_t data, uint16_t len) { AD7793_CHECK_INITIALIZED(dev); uint8_t cmd = 0; uint8_t tmp[4] = {0}; /* Build communication command: WEN=0, R/W=0(write), register address */ cmd = (reg & 0x07) << 3; cmd &= ~COMM_RW; cmd &= ~COMM_WEN; if (len == 1) { tmp[0] = data >> 0; } else if (len == 2) { tmp[0] = data >> 8; tmp[1] = data >> 0; } else if (len == 3) { tmp[0] = data >> 16; tmp[1] = data >> 8; tmp[2] = data >> 0; } dev->hw_if->gpio_set(dev->cs_pin, false); dev->hw_if->spi_write(cmd, tmp, len); //ad7793_spi_transfer(dev, cmd, data, NULL, len); dev->hw_if->gpio_set(dev->cs_pin, true); return true; } /** * @brief Read data from a specified register. * @param dev Pointer to ad7793_dev_t instance. * @param reg Register address to read from. * @param data Buffer to store the read data. * @param len Data length (2/3 bytes). * @return Operation status. True if successful, false otherwise. * @detail This function constructs a communication command to read data from the specified register. * It first clears the chip select pin, then performs an SPI transfer to receive the data. * Finally, it sets the chip select pin back to high. */ bool ad7793_read_reg(ad7793_dev_t *dev, uint8_t reg, uint32_t *data, uint16_t len) { AD7793_CHECK_INITIALIZED(dev); uint8_t cmd = 0; uint8_t tmp[4] = {0}; /* Build communication command: WEN=0, R/W=1(read), register address */ cmd = (reg & 0x07) << 3; cmd |= COMM_RW; // 0: Write operation; 1: Read operation cmd &= ~COMM_WEN; // write enable bit should be 0 for read operation dev->hw_if->gpio_set(dev->cs_pin, false); dev->hw_if->spi_read(cmd, tmp, len); //ad7793_spi_transfer(dev, cmd, NULL, data, len); //dev->hw_if->delay_ms(1); dev->hw_if->gpio_set(dev->cs_pin, true); if (len == 1) { *data = tmp[0] << 0; } else if (len == 2) { *data = tmp[0] << 8 | tmp[1] << 0; } else if (len == 3) { *data = tmp[0] << 16 | tmp[1] << 8 | tmp[2] << 0; } return true; } /** * @brief Reset the device. * @param dev Pointer to ad7793_dev_t instance. * @return Operation status. True if successful, false otherwise. * @detail This function resets the device by writing 32 ones to the device. * It clears the chip select pin, sends the reset sequence via SPI, and then sets the chip select pin back to high. * After that, it waits for 1 millisecond to ensure the reset is completed. */ bool ad7793_reset(ad7793_dev_t *dev) { AD7793_CHECK_INITIALIZED(dev); dev->hw_if->gpio_set(dev->cs_pin, false); uint8_t reset_seq[4] = {0xFF, 0xFF, 0xFF, 0xFF}; dev->hw_if->spi_transfer(reset_seq, NULL, 4); dev->hw_if->gpio_set(dev->cs_pin, true); dev->hw_if->delay_ms(1); /* Wait for reset to complete */ return true; } /** * @brief Set the working mode of the device. * @param dev Pointer to ad7793_dev_t instance. * @param mode Mode enum value representing the desired working mode. * @return Operation status. True if successful, false otherwise. * @detail This function reads the current mode register, clears the mode bits, and then sets the new mode according to the input. * It updates the current mode in the device structure and writes the new mode to the mode register. */ bool ad7793_set_mode(ad7793_dev_t *dev, ad7793_mode_t mode) { AD7793_CHECK_INITIALIZED(dev); uint32_t mode_reg = 0; ad7793_read_reg(dev, REG_MODE, &mode_reg, 2); DEBUG_PRINTF("read current mode: 0x%04X\n", mode_reg); /* Clear mode bits */ mode_reg &= ~(MODE_MD2 | MODE_MD1 | MODE_MD0); /* Set new mode */ switch (mode) { case AD7793_MODE_CONTINUOUS: break; /* Default mode, MD2-MD0=000 */ case AD7793_MODE_SINGLE: mode_reg |= MODE_MD0; break; case AD7793_MODE_IDLE: mode_reg |= MODE_MD1; break; case AD7793_MODE_POWER_DOWN: mode_reg |= MODE_MD1 | MODE_MD0; break; case AD7793_MODE_INTERNAL_ZERO: mode_reg |= MODE_MD2; break; case AD7793_MODE_INTERNAL_FULL: mode_reg |= MODE_MD2 | MODE_MD0; break; case AD7793_MODE_SYSTEM_ZERO: mode_reg |= MODE_MD2 | MODE_MD1; break; case AD7793_MODE_SYSTEM_FULL: mode_reg |= MODE_MD2 | MODE_MD1 | MODE_MD0; break; } DEBUG_PRINTF("[mode-w]set mode: 0x%04X\n", mode_reg); dev->cur_mode = mode; return ad7793_write_reg(dev, REG_MODE, mode_reg, 2); } /** * @brief Set the gain of the device. * @param dev Pointer to ad7793_dev_t instance. * @param gain Gain enum value representing the desired gain setting. * @return Operation status. True if successful, false otherwise. * @detail This function reads the current configuration register, clears the gain bits, and then sets the new gain according to the input. * It updates the current gain in the device structure and writes the new configuration to the configuration register. */ bool ad7793_set_gain(ad7793_dev_t *dev, ad7793_gain_t gain) { AD7793_CHECK_INITIALIZED(dev); uint32_t config_reg = 0; ad7793_read_reg(dev, REG_CONFIG, &config_reg, 2); /* Clear gain bits (G2/G1/G0) */ config_reg &= ~(CONFIG_G2 | CONFIG_G1 | CONFIG_G0); /* Set new gain (PDF->table 17) */ switch (gain) { case AD7793_GAIN_1: // 000 break; case AD7793_GAIN_2: // 001 config_reg |= CONFIG_G0; break; case AD7793_GAIN_4: // 010 config_reg |= CONFIG_G1; break; case AD7793_GAIN_8: // 011 config_reg |= CONFIG_G1 | CONFIG_G0; break; case AD7793_GAIN_16: // 100 config_reg |= CONFIG_G2; break; case AD7793_GAIN_32: // 101 config_reg |= CONFIG_G2 | CONFIG_G0; break; case AD7793_GAIN_64: // 110 config_reg |= CONFIG_G2 | CONFIG_G1; break; case AD7793_GAIN_128: // 111 config_reg |= CONFIG_G2 | CONFIG_G1 | CONFIG_G0; break; default: DEBUG_PRINTF("Invalid gain value: %d\n", gain); return false; // unavailable gain } DEBUG_PRINTF("[config-w]set gain: 0x%04X\n", config_reg); dev->cur_gain = gain; return ad7793_write_reg(dev, REG_CONFIG, config_reg, 2); } /** * @brief Set the channel of the device. * @param dev Pointer to ad7793_dev_t instance. * @param channel Channel enum value representing the desired channel. * @return Operation status. True if successful, false otherwise. * @detail This function reads the current configuration register, clears the channel bits, * and then sets the new channel according to the input.It updates the current * channel in the device structure and writes the new configuration to the configuration register. */ bool ad7793_set_channel(ad7793_dev_t *dev, ad7793_channel_t channel) { AD7793_CHECK_INITIALIZED(dev); uint32_t config_reg = 0; ad7793_read_reg(dev, REG_CONFIG, &config_reg, 2); /* Clear channel bits */ config_reg &= ~(CONFIG_CH2 | CONFIG_CH1 | CONFIG_CH0); /* Set new channel */ switch (channel) { case AD7793_CHANNEL_1: break; /* CH2-CH0=000 */ case AD7793_CHANNEL_2: config_reg |= CONFIG_CH0; break; case AD7793_CHANNEL_3: config_reg |= CONFIG_CH1; break; case AD7793_CHANNEL_TEMP: config_reg |= CONFIG_CH1 | CONFIG_CH0; break; case AD7793_CHANNEL_AVDD: config_reg |= CONFIG_CH2 | CONFIG_CH1 | CONFIG_CH0; break; } dev->cur_channel = channel; DEBUG_PRINTF("[config-w]set channel: 0x%04X\n", config_reg); return ad7793_write_reg(dev, REG_CONFIG, config_reg, 2); } /** * @brief Set the update rate of the device. * @param dev Pointer to ad7793_dev_t instance. * @param rate Update rate enum value representing the desired update rate. * @return Operation status. True if successful, false otherwise. * @detail This function reads the current mode register, clears the rate bits, and then sets the new rate according to the input. * It updates the current update rate in the device structure and writes the new mode to the mode register. */ bool ad7793_set_rate(ad7793_dev_t *dev, ad7793_rate_t rate) { AD7793_CHECK_INITIALIZED(dev); uint32_t mode_reg = 0; ad7793_read_reg(dev, REG_MODE, &mode_reg, 2); /* Clear rate bits */ mode_reg &= ~(MODE_FS3 | MODE_FS2 | MODE_FS1 | MODE_FS0); /* Set new rate */ mode_reg |= (uint16_t)rate; dev->cur_rate = rate; DEBUG_PRINTF("[mode]set rate: 0x%04X\n", mode_reg); return ad7793_write_reg(dev, REG_MODE, mode_reg, 2); } /** * @brief Set the reference source of the device. * @param dev Pointer to ad7793_dev_t instance. * @param use_internal true=internal reference, false=external reference. * @param external_ref External reference voltage (if use_internal is false). * @return Operation status. True if successful, false otherwise. * @detail This function reads the current configuration register and sets the reference select bit according to the input. * It updates the reference source information in the device structure and writes the new configuration to the * configuration register. */ bool ad7793_set_reference(ad7793_dev_t *dev, bool use_internal, float external_ref) { AD7793_CHECK_INITIALIZED(dev); uint32_t config_reg = 0; ad7793_read_reg(dev, REG_CONFIG, &config_reg, 2); /* Set reference select bit */ if (use_internal) { dev->use_internal_ref = true; config_reg |= CONFIG_REFSEL; } else { dev->external_ref = external_ref; config_reg &= ~CONFIG_REFSEL; } DEBUG_PRINTF("[config-w]set reference: 0x%04X\n", config_reg); return ad7793_write_reg(dev, REG_CONFIG, config_reg, 2); } /** * @brief Wait for the conversion to be ready. * @param dev Pointer to ad7793_dev_t instance. * @param timeout_ms Timeout in milliseconds. * @return true=ready, false=timeout. * @detail This function continuously checks the GPIO pin status until the device is ready or the timeout occurs. * It waits for 1 millisecond between each check. */ bool ad7793_wait_ready(ad7793_dev_t *dev, uint16_t timeout_ms) { AD7793_CHECK_INITIALIZED(dev); uint16_t timeout = 0; uint32_t status = 0; while (timeout < timeout_ms) { ad7793_read_reg(dev, REG_STATUS, &status, 1); if (status & 0x40) // check if the device is in error state { DEBUG_PRINTF("Device in error state, status: 0x%02X\n", status); return false; // device error } // check RDY bit(bit7)is zero or not if ((status & 0x80) == 0) { return true; // data is rdy } dev->hw_if->delay_ms(1); timeout++; } DEBUG_PRINTF("Timeout waiting for data ready\n"); return false; // timeout } /** * @brief Read the conversion data from the device. * @param dev Pointer to ad7793_dev_t instance. * @param value Data buffer (3 bytes for AD7793) to store the read data. * @return Operation status. True if successful, false otherwise. * @detail This function reads the conversion data from the data register. * If the device is AD7793, it reads 3 bytes; if it is AD7792, it reads 2 bytes. */ bool ad7793_read_data(ad7793_dev_t *dev, uint32_t *value) { AD7793_CHECK_INITIALIZED(dev); uint32_t data = 0; bool status = false; if (dev->is_ad7793) { /* AD7793: 24-bit data, read 3 bytes */ status = ad7793_read_reg(dev, REG_DATA, &data, 3); } else { /* AD7792: 16-bit data, read 2 bytes */ status = ad7793_read_reg(dev, REG_DATA, &data, 2); } if (status) { *value = data; } return status; } /** * @brief Convert the raw digital data read from AD7793 to the corresponding voltage value. * @param dev Pointer to the ad7793_dev_t instance. * @param raw_data The raw digital data (24-bit) read from AD7793. * @return The converted voltage value (unit: volts). * @detail This function converts the raw digital data to the voltage value according to the formula provided in the AD7793 manual. * The formula is: V = (D * Vref) / (2^N * G) * Where: * V is the converted voltage value. * D is the raw digital data. * Vref is the reference voltage. * N is the number of ADC bits (24 bits for AD7793). * G is the gain setting. */ float ad7793_convert_to_voltage(ad7793_dev_t *dev, uint32_t adc_code) { AD7793_CHECK_INITIALIZED(dev); #if (USING_AUTO_READ_CONFIG_BITS == 1) // Determine the reference voltage: 1.17V for internal, or user-defined external VREF // Read configuration and mode registers from the AD7793 device uint32_t config_reg = 0; ad7793_read_reg(dev, REG_CONFIG, &config_reg, 2); DEBUG_PRINTF("read config: 0x%04X\n", config_reg); float vref = (config_reg & CONFIG_REFSEL) ? 1.17f : dev->external_ref; // Extract gain bits (G2, G1, G0) from config register and calculate gain = 2^gain_bits uint8_t gain_bits = 0; gain_bits |= (config_reg & CONFIG_G2) ? 0x04 : 0x00; gain_bits |= (config_reg & CONFIG_G1) ? 0x02 : 0x00; gain_bits |= (config_reg & CONFIG_G0) ? 0x01 : 0x00; uint8_t gain = 1 << gain_bits; // Gain = 2^gain_bits (e.g., 1, 2, ..., 128) // Determine bipolar mode: if CONFIG_U_B bit is 0, then bipolar is enabled (Offset Binary) bool bipolar = ((config_reg & CONFIG_U_B) == 0); // Determine if input buffer is enabled (bit CONFIG_BUF) bool buffer_enabled = (config_reg & CONFIG_BUF) ? true : false; #else float vref = dev->use_internal_ref ? 1.17f : dev->external_ref; uint8_t gain = dev->cur_gain; bool bipolar = !dev->unipolar_mode; bool buffer_enabled = dev->buffered; #endif // Set resolution: 24-bit for AD7793, 16-bit for AD7792 uint8_t resolution_bits = dev->is_ad7793 ? 24 : 16; // Validate parameters: if (vref <= 0.0f) return 0.0f; // Invalid reference voltage if (!(gain == 1 || gain == 2 || gain == 4 || gain == 8 || gain == 16 || gain == 32 || gain == 64 || gain == 128)) return 0.0f; // Invalid gain if (!(resolution_bits == 16 || resolution_bits == 24)) return 0.0f; // Invalid resolution if (!buffer_enabled && gain > 2) return 0.0f; // According to datasheet, buffer must be enabled when gain > 2 // Check that the ADC code is within valid range uint32_t max_code = (resolution_bits == 24) ? 0xFFFFFFu : 0xFFFFu; if (adc_code > max_code) return 0.0f; // ADC code out of range // Begin voltage calculation float voltage = 0.0f; if (!bipolar) { // Unipolar mode (Straight Binary) // Code range: 0x000000 to 0xFFFFFF // Input range: 0V to +VREF / gain // Voltage = (ADC_Code / 2^N) * (VREF / Gain) uint32_t full_range = (uint32_t)1 << resolution_bits; voltage = (float)((double)adc_code * vref / (gain * (double)full_range)); } else { // Bipolar mode (Offset Binary) // Code range: 0x000000 to 0xFFFFFF // Midpoint: 0x800000 (represents 0V) // Voltage = ((ADC_Code / 2^(N-1)) - 1) * (VREF / Gain) // This maps code range [0x000000, 0xFFFFFF] to voltage range [-VREF/Gain, +VREF/Gain] double half_range = (double)((uint32_t)1 << (resolution_bits - 1)); double code_norm = (double)adc_code / half_range; voltage = (float)((code_norm - 1.0) * (vref / gain)); } return voltage; } /** * @brief Convert the input voltage to the corresponding ADC code for AD7793. * @param dev Pointer to the AD7793 device structure. * @param voltage Input voltage value (V). * @return Corresponding ADC code value. */ uint32_t ad7793_convert_voltage_to_code(ad7793_dev_t *dev, float voltage) { AD7793_CHECK_INITIALIZED(dev); #if (USING_AUTO_READ_CONFIG_BITS == 1) // Read configuration and mode registers from the AD7793 device uint32_t config_reg = 0; ad7793_read_reg(dev, REG_CONFIG, &config_reg, 2); DEBUG_PRINTF("read config: 0x%04X\n", config_reg); float vref = (config_reg & CONFIG_REFSEL) ? 1.17f : dev->external_ref; // Extract gain bits (G2, G1, G0) from config register and calculate gain = 2^gain_bits uint8_t gain_bits = 0; gain_bits |= (config_reg & CONFIG_G2) ? 0x04 : 0x00; gain_bits |= (config_reg & CONFIG_G1) ? 0x02 : 0x00; gain_bits |= (config_reg & CONFIG_G0) ? 0x01 : 0x00; uint8_t gain = 1 << gain_bits; // Gain = 2^gain_bits (e.g., 1, 2, ..., 128) // Determine bipolar mode: if CONFIG_U_B bit is 0, then bipolar is enabled (Offset Binary) bool bipolar = ((config_reg & CONFIG_U_B) == 0); // Determine if input buffer is enabled (CONFIG_BUF bit) bool buffer_enabled = (config_reg & CONFIG_BUF) ? true : false; #else float vref = dev->use_internal_ref ? 1.17f : dev->external_ref; uint8_t gain = dev->cur_gain; bool bipolar = !dev->unipolar_mode; bool buffer_enabled = dev->buffered; #endif // Set resolution: 24-bit for AD7793, 16-bit for AD7792 uint8_t resolution_bits = dev->is_ad7793 ? 24 : 16; // Parameter validation: if (vref <= 0.0f) return 0; // Invalid reference voltage if (!(gain == 1 || gain == 2 || gain == 4 || gain == 8 || gain == 16 || gain == 32 || gain == 64 || gain == 128)) return 0; // Invalid gain if (!(resolution_bits == 16 || resolution_bits == 24)) return 0; // Invalid resolution if (!buffer_enabled && gain > 2) return 0; // According to datasheet, buffer must be enabled when gain > 2 // Calculate maximum ADC code value uint32_t max_code = (resolution_bits == 24) ? 0xFFFFFFu : 0xFFFFu; uint32_t adc_code = 0; // Voltage to ADC code conversion if (!bipolar) { // Unipolar mode (straight binary) // Voltage range: 0V to +VREF / gain // ADC code = (voltage * 2^N) / (VREF / gain) double full_scale = (double)vref / gain; double code_double = (double)voltage * ((double)max_code + 1) / full_scale; // Clamp to valid range if (code_double < 0.0) adc_code = 0; else if (code_double >= (double)max_code) adc_code = max_code; else adc_code = (uint32_t)(code_double + 0.5); // Round to nearest } else { // Bipolar mode (offset binary) // Voltage range: -VREF/gain to +VREF/gain // ADC code = ((voltage / (VREF / gain)) + 1) * 2^(N-1) double half_scale = (double)vref / gain; double normalized_voltage = (double)voltage / half_scale; double code_double = (normalized_voltage + 1.0) * ((double)max_code + 1) / 2.0; // Clamp to valid range if (code_double < 0.0) adc_code = 0; else if (code_double >= (double)max_code) adc_code = max_code; else adc_code = (uint32_t)(code_double + 0.5); // Round to nearest } return adc_code; } /** * @brief Perform internal zero-scale calibration. * @param dev Pointer to ad7793_dev_t instance. * @return Operation status. True if successful, false otherwise. * @detail This function sets the device to internal zero-scale calibration mode, waits for 10 milliseconds for the calibration to complete, * and then sets the device back to continuous conversion mode. */ bool ad7793_calibrate_internal_zero(ad7793_dev_t *dev) { AD7793_CHECK_INITIALIZED(dev); ad7793_set_mode(dev, AD7793_MODE_INTERNAL_ZERO); if (!ad7793_wait_ready(dev, 500)) /* Wait for calibration to complete */ return false; return ad7793_set_mode(dev, AD7793_MODE_CONTINUOUS); } /** * @brief Perform internal full-scale calibration. * @param dev Pointer to ad7793_dev_t instance. * @return Operation status. True if successful, false otherwise. * @detail This function sets the device to internal full-scale calibration mode, waits for 10 milliseconds for the calibration to complete, * and then sets the device back to continuous conversion mode. */ bool ad7793_calibrate_internal_full(ad7793_dev_t *dev) { AD7793_CHECK_INITIALIZED(dev); ad7793_set_mode(dev, AD7793_MODE_INTERNAL_FULL); dev->hw_if->delay_ms(10); /* Wait for calibration to complete */ return ad7793_set_mode(dev, AD7793_MODE_CONTINUOUS); } /** * @brief Perform system zero-scale calibration. * @param dev Pointer to ad7793_dev_t instance. * @return Operation status. True if successful, false otherwise. * @detail This function sets the device to system zero-scale calibration mode, waits for 10 milliseconds for the calibration to complete, * and then sets the device back to continuous conversion mode. */ bool ad7793_calibrate_system_zero(ad7793_dev_t *dev) { AD7793_CHECK_INITIALIZED(dev); ad7793_set_mode(dev, AD7793_MODE_SYSTEM_ZERO); dev->hw_if->delay_ms(10); /* Wait for calibration to complete */ return ad7793_set_mode(dev, AD7793_MODE_CONTINUOUS); } /** * @brief Perform system full-scale calibration. * @param dev Pointer to ad7793_dev_t instance. * @return Operation status. True if successful, false otherwise. * @detail This function sets the device to system full-scale calibration mode, waits for 10 milliseconds for the calibration to complete, * and then sets the device back to continuous conversion mode. */ bool ad7793_calibrate_system_full(ad7793_dev_t *dev) { AD7793_CHECK_INITIALIZED(dev); ad7793_set_mode(dev, AD7793_MODE_SYSTEM_FULL); dev->hw_if->delay_ms(10); /* Wait for calibration to complete */ return ad7793_set_mode(dev, AD7793_MODE_CONTINUOUS); } /** * @brief Configure the excitation current source. * @param dev Pointer to ad7793_dev_t instance. * @param current Current value (10/210/1000uA). * @param dir Current direction (0=IOUT1/IOUT2, 1=swap). * @return Operation status. True if successful, false otherwise. * @detail This function configures the excitation current source by setting the current value and direction in the IO register. * It then enables the current source and writes the configuration to the IO register. */ bool ad7793_config_iexc(ad7793_dev_t *dev, uint16_t current, uint8_t dir) { AD7793_CHECK_INITIALIZED(dev); uint32_t io_reg = 0; /* Set current value */ if (current == 10) { io_reg |= 0x01; } else if (current == 210) { io_reg |= 0x02; } else if (current == 1000) { io_reg |= 0x03; } else { return false; } /* Set current direction */ if (dir) { io_reg |= (0x03 << 2); } /* Enable current source */ io_reg |= (0x03 << 0); return ad7793_write_reg(dev, REG_IO, io_reg, 1); } /** * @brief Configure the AD7793 for unipolar or bipolar operation mode * @param dev Pointer to the AD7793 device structure * @param unipolar true = enable unipolar mode, false = enable bipolar mode * @return true if operation succeeded, false otherwise * @details * This function sets the U/B (Unipolar/Bipolar) bit in the configuration register * to determine the conversion mode: * - Unipolar mode (U/B=1): Converts 0V to VREF into 0x000000 to 0xFFFFFF * - Bipolar mode (U/B=0): Converts -VREF/2 to +VREF/2 into 0x000000 to 0xFFFFFF * * Note: Changing this bit affects the interpretation of the ADC output code. */ bool ad7793_set_unipolar(ad7793_dev_t *dev, bool unipolar) { AD7793_CHECK_INITIALIZED(dev); uint32_t config_reg = 0; // Read current configuration register ad7793_read_reg(dev, REG_CONFIG, &config_reg, 2); // Update the U/B bit (bit 8 in the config register) if (unipolar) { config_reg |= CONFIG_U_B; // Set U/B bit for unipolar mode } else { config_reg &= ~CONFIG_U_B; // Clear U/B bit for bipolar mode } // Save the current mode setting dev->unipolar_mode = unipolar; DEBUG_PRINTF("[config-w]Unipolar mode set to 0x%04x\n", config_reg); // Write updated configuration back to the device return ad7793_write_reg(dev, REG_CONFIG, config_reg, 2); } /** * @brief Configure the input buffer mode of AD7793 * @param dev Pointer to the ad7793_dev_t instance * @param enable true=Enable input buffer, false=Disable input buffer * @return Operation status. true=Success, false=Failure * @detail This function configures the input buffer mode of AD7793. * Enabling the buffer reduces input impedance requirements but increases power consumption. * Disabling the buffer is suitable for high-impedance sources but requires attention to input signal range limitations. */ bool ad7793_set_buffered(ad7793_dev_t *dev, bool enable) { AD7793_CHECK_INITIALIZED(dev); uint32_t config_reg = 0; // Read current configuration register value ad7793_read_reg(dev, REG_CONFIG, &config_reg, 2); // Update BUF bit (bit 7 of the configuration register) if (enable) { config_reg |= CONFIG_BUF; // Enable input buffer } else { config_reg &= ~CONFIG_BUF; // Disable input buffer } // Save current buffer mode state dev->buffered = enable; DEBUG_PRINTF("[config-w]set buffered %04x\n", config_reg); // Write updated configuration register return ad7793_write_reg(dev, REG_CONFIG, config_reg, 2); } /** * @brief Initialize the device. * @param dev Pointer to ad7793_dev_t instance. * @param hw_if Hardware interface structure containing function pointers. * @param cs_pin Chip select pin. * @param rdy_pin Ready pin * @return Operation status. True if successful, false otherwise. * @detail This function initializes the AD7793 device by saving the hardware interface and chip select information. * It resets the device, waits for the reset to complete, and then reads the ID register to confirm the device type. * Finally, it initializes the device with default configuration settings. */ bool ad7793_init(ad7793_dev_t *dev, ad7793_hw_if_t *hw_if, uint8_t cs_pin) { uint32_t mode_reg = 0; uint32_t config_reg = 0; if (hw_if == NULL) { DEBUG_PRINTF("hw_if is null\n"); return false; } /* Save hardware interface and chip select info */ dev->hw_if = hw_if; dev->cs_pin = cs_pin; dev->is_ad7793 = true; /* Default is AD7793, can be confirmed by ID register */ dev->is_initialized = true; /* Reset device */ ad7793_reset(dev); /* Wait for reset to complete */ dev->hw_if->delay_ms(1); /* Read ID register to confirm device type */ uint32_t id = 0; ad7793_read_reg(dev, REG_ID, &id, 1); DEBUG_PRINTF("ID: 0x%02X\n", id); dev->is_ad7793 = ((id & 0x0F) == 0x0B); /* AD7793 ID read out is 0x4B */ /* Initialize default configuration */ ad7793_set_mode(dev, AD7793_MODE_CONTINUOUS); ad7793_wait_ready(dev, 1000); ad7793_read_reg(dev, REG_MODE, &mode_reg, 2); DEBUG_PRINTF("[mode-r]: 0x%04X\n", mode_reg); ad7793_set_gain(dev, AD7793_GAIN_1); ad7793_wait_ready(dev, 1000); ad7793_read_reg(dev, REG_CONFIG, &config_reg, 2); DEBUG_PRINTF("[config-r]after gain config: 0x%04X\n", config_reg); ad7793_set_channel(dev, AD7793_CHANNEL_1); ad7793_wait_ready(dev, 1000); ad7793_read_reg(dev, REG_CONFIG, &config_reg, 2); DEBUG_PRINTF("[config-r]after channel config: 0x%04X\n", config_reg); ad7793_set_rate(dev, AD7793_RATE_8_33HZ); ad7793_wait_ready(dev, 1000); ad7793_read_reg(dev, REG_MODE, &mode_reg, 2); DEBUG_PRINTF("[mode-r]after rate mode: 0x%04X\n", mode_reg); ad7793_set_reference(dev, true, 2.5); /* Use internal reference */ ad7793_wait_ready(dev, 1000); ad7793_read_reg(dev, REG_CONFIG, &config_reg, 2); DEBUG_PRINTF("[config-r]after reference config: 0x%04X\n", config_reg); ad7793_set_unipolar(dev, true); /* Default to bipolar mode */ ad7793_wait_ready(dev, 1000); ad7793_read_reg(dev, REG_CONFIG, &config_reg, 2); DEBUG_PRINTF("[config-r]after polar config: 0x%04X\n", config_reg); ad7793_set_buffered(dev, false); /* Enable input buffer */ ad7793_wait_ready(dev, 1000); ad7793_read_reg(dev, REG_CONFIG, &config_reg, 2); DEBUG_PRINTF("final read config: 0x%04X\n", config_reg); ad7793_calibrate_system_zero(dev); return true; }