/*** * @Author: mypx * @Email: mypx_coder@163.com * @Date: 2025-06-23 10:26:23 * @LastEditors: mypx mypx_coder@163.com * @Description: AD7793 driver header */ #ifndef __AD7793_H__ #define __AD7793_H__ #include #include #define USING_AUTO_READ_CONFIG_BITS 0 // gain will set auto, so read it from register dynamic. /* Hardware interface abstraction - should be implemented for your platform */ typedef struct { void (*spi_transfer)(uint8_t *tx_buf, uint8_t *rx_buf, uint16_t len); /**< SPI transfer function */ void (*spi_write)(uint8_t cmd, uint8_t *tx_buf, uint16_t len); /**< SPI write function */ void (*spi_read)(uint8_t cmd, uint8_t *rx_buf, uint16_t len); /**< SPI read function */ void (*gpio_set)(uint8_t pin, bool state); /**< Set CS state */ bool (*gpio_get)(uint8_t pin); /**< Get RDY/MISO state */ void (*delay_ms)(uint16_t ms); /**< Millisecond delay */ } ad7793_hw_if_t; /* Register address definitions */ #define REG_COMMUNICATION 0x00 /**< Communication register */ #define REG_STATUS 0x00 /**< Status register (read mode) */ #define REG_MODE 0x01 /**< Mode register */ #define REG_CONFIG 0x02 /**< Configuration register */ #define REG_DATA 0x03 /**< Data register */ #define REG_ID 0x04 /**< ID register */ #define REG_IO 0x05 /**< IO register */ #define REG_OFFSET 0x06 /**< Offset register */ #define REG_FULLSCALE 0x07 /**< Full scale register */ /* Communication register bit definitions */ #define COMM_WEN (1 << 7) /**< Write enable */ #define COMM_RW (1 << 6) /**< Read/Write control */ #define COMM_RS2 (1 << 5) /**< Register select bit 2 */ #define COMM_RS1 (1 << 4) /**< Register select bit 1 */ #define COMM_RS0 (1 << 3) /**< Register select bit 0 */ #define COMM_CREAD (1 << 2) /**< Continuous read enable */ /* Mode register bit definitions */ #define MODE_MD2 (1 << 15) /**< Mode select bit 2 */ #define MODE_MD1 (1 << 14) /**< Mode select bit 1 */ #define MODE_MD0 (1 << 13) /**< Mode select bit 0 */ #define MODE_CLK1 (1 << 7) /**< Clock select bit 1 */ #define MODE_CLK0 (1 << 6) /**< Clock select bit 0 */ #define MODE_FS3 (1 << 3) /**< Update rate select bit 3 */ #define MODE_FS2 (1 << 2) /**< Update rate select bit 2 */ #define MODE_FS1 (1 << 1) /**< Update rate select bit 1 */ #define MODE_FS0 (1 << 0) /**< Update rate select bit 0 */ /* Configuration register bit definitions */ #define CONFIG_VBIAS1 (1 << 15) /**< Bias voltage bit 1 */ #define CONFIG_VBIAS0 (1 << 14) /**< Bias voltage bit 0 */ #define CONFIG_BO (1 << 13) /**< Burnout current enable */ #define CONFIG_U_B (1 << 12) /**< Unipolar/Bipolar mode */ #define CONFIG_BOOST (1 << 11) /**< Bias boost enable */ #define CONFIG_G2 (1 << 10) /**< Gain select bit 2 */ #define CONFIG_G1 (1 << 9) /**< Gain select bit 1 */ #define CONFIG_G0 (1 << 8) /**< Gain select bit 0 */ #define CONFIG_REFSEL (1 << 7) /**< Reference select */ #define CONFIG_BUF (1 << 4) /**< Buffer mode enable */ #define CONFIG_CH2 (1 << 2) /**< Channel select bit 2 */ #define CONFIG_CH1 (1 << 1) /**< Channel select bit 1 */ #define CONFIG_CH0 (1 << 0) /**< Channel select bit 0 */ /* IO register bit definitions */ #define IO_IEXCDIR1 (1 << 3) /**< Excitation current direction bit 1 */ #define IO_IEXCDIR0 (1 << 2) /**< Excitation current direction bit 0 */ #define IO_IEXCEN1 (1 << 1) /**< Excitation current enable bit 1 */ #define IO_IEXCEN0 (1 << 0) /**< Excitation current enable bit 0 */ /* Working mode enumeration */ typedef enum { AD7793_MODE_CONTINUOUS, /**< Continuous conversion mode */ AD7793_MODE_SINGLE, /**< Single conversion mode */ AD7793_MODE_IDLE, /**< Idle mode */ AD7793_MODE_POWER_DOWN, /**< Power-down mode */ AD7793_MODE_INTERNAL_ZERO, /**< Internal zero-scale calibration */ AD7793_MODE_INTERNAL_FULL, /**< Internal full-scale calibration */ AD7793_MODE_SYSTEM_ZERO, /**< System zero-scale calibration */ AD7793_MODE_SYSTEM_FULL /**< System full-scale calibration */ } ad7793_mode_t; /* Gain enumeration */ typedef enum { AD7793_GAIN_1 = 1, /**< Gain 1 */ AD7793_GAIN_2 = 2, /**< Gain 2 */ AD7793_GAIN_4 = 4, /**< Gain 4 */ AD7793_GAIN_8 = 8, /**< Gain 8 */ AD7793_GAIN_16 = 16, /**< Gain 16 */ AD7793_GAIN_32 = 32, /**< Gain 32 */ AD7793_GAIN_64 = 64, /**< Gain 64 */ AD7793_GAIN_128 = 128 /**< Gain 128 */ } ad7793_gain_t; /* Channel enumeration */ typedef enum { AD7793_CHANNEL_1, /**< Channel 1: AIN1(+)-AIN1(-) */ AD7793_CHANNEL_2, /**< Channel 2: AIN2(+)-AIN2(-) */ AD7793_CHANNEL_3, /**< Channel 3: AIN3(+)-AIN3(-) */ AD7793_CHANNEL_TEMP, /**< Temperature sensor channel */ AD7793_CHANNEL_AVDD /**< AVDD monitor channel */ } ad7793_channel_t; /* Update rate enumeration */ typedef enum { AD7793_RATE_4_17HZ = 0xF, /**< 4.17Hz */ AD7793_RATE_8_33HZ = 0xE, /**< 8.33Hz */ AD7793_RATE_16_7HZ = 0xA, /**< 16.7Hz */ AD7793_RATE_33_2HZ = 0x7, /**< 33.2Hz */ AD7793_RATE_62HZ = 0x4, /**< 62Hz */ AD7793_RATE_123HZ = 0x3, /**< 123Hz */ AD7793_RATE_242HZ = 0x2, /**< 242Hz */ AD7793_RATE_470HZ = 0x1 /**< 470Hz */ } ad7793_rate_t; /* Configuration structure for AD7793 */ typedef struct { bool use_internal_ref; /**< true: use internal reference, false: use external reference */ float external_ref; /**< External reference voltage (V), used if use_internal_ref is false */ ad7793_gain_t gain; /**< Gain setting */ ad7793_channel_t channel; /**< Channel selection */ ad7793_rate_t rate; /**< Output data rate */ bool buffered; /**< true: enable input buffer, false: disable buffer */ bool unipolar_mode; /**< true: unipolar mode, false: bipolar mode */ bool calibrate_system_zero; /**< true: perform system zero calibration at startup, false: skip calibration */ } ad7793_config_t; /* Default config as a compound literal so it can be used in expressions */ #ifndef AD7793_DEFAULT_CONFIG #define AD7793_DEFAULT_CONFIG \ (ad7793_config_t) \ { \ .use_internal_ref = true, .external_ref = 1.17f, .gain = AD7793_GAIN_1, .channel = AD7793_CHANNEL_1, \ .rate = AD7793_RATE_8_33HZ, .buffered = false, .unipolar_mode = true, .calibrate_system_zero = false \ } #endif /* Device structure */ typedef struct { ad7793_hw_if_t *hw_if; /**< Hardware interface function pointers */ uint8_t cs_pin; /**< Chip select pin */ ad7793_mode_t cur_mode; /**< Current working mode */ ad7793_gain_t cur_gain; /**< Current gain setting */ ad7793_channel_t cur_channel; /**< Current channel */ ad7793_rate_t cur_rate; /**< Current update rate */ float external_ref; /**< Set reference when use_internal_ref is false */ bool is_ad7793; /**< True if AD7793 (24-bit), false if AD7792 (16-bit) */ bool use_internal_ref; /**< True if using internal reference */ bool unipolar_mode; /**< True if unipolar mode, false if bipolar mode */ bool buffered; /**< True if buffer enable, false if buffer unused */ bool is_initialized; /**< True if the device has been initialized */ /* --- Runtime diagnostics --- */ uint32_t err_count; /**< Total STATUS.ERR (bit6) occurrences */ uint32_t err_recoveries; /**< Number of automatic recovery attempts */ uint32_t low_code_drops; /**< Dropped samples due to low code threshold */ uint32_t last_status; /**< Last read STATUS register */ } ad7793_dev_t; #define AD7793_CHECK_INITIALIZED(dev) \ do \ { \ if (!dev->is_initialized) \ { \ DEBUG_PRINTF("Device not initialized!\n"); \ return false; \ } \ } while (0) /* * AD7793 Driver Header * * Recommended Initialization Flow: * 1. Configure the ad7793_hw_if_t hardware interface struct, filling in SPI/GPIO/delay function pointers. * 2. Define the ad7793_config_t configuration struct, specifying reference source, gain, channel, rate, buffer, etc. * 3. Call ad7793_init(&dev, &hw_if, cs_pin, &cfg) to initialize the device. * 4. Before data acquisition, call ad7793_wait_ready to wait for data ready. * 5. Use ad7793_read_data to acquire data, and ad7793_convert_to_voltage to convert to voltage. * 6. If you need to switch channel/gain/reference, it is recommended to set idle mode first, then switch parameters, and finally restore continuous mode. * * Common Troubleshooting: * - STATUS=0x48/0xC8: Usually caused by reference source mismatch, buffer/gain conflict, or IEXC not configured as required by hardware. * - All readings zero or extremely large: Check reference voltage, SPI wiring, channel/gain configuration. * - Register write failure: Check SPI speed, CS timing, hardware interface implementation. * - Temperature jumps/spikes: Application layer should implement temperature jump/low code filtering. * - Abnormal sampling rate: Confirm rate configuration matches master clock and SPI speed. * * See API comments for typical usage. */ /** * @brief Write data to a specified register of the AD7793 device. * @param dev Device structure pointer. * @param reg Register address to write to. * @param data Data buffer to be written. * @param len Data length to write (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. * @note Boundary: Returns false if dev is not initialized or parameters are invalid. Example: ad7793_write_reg(&dev, REG_MODE, 0x200A, 2); */ bool ad7793_write_reg(ad7793_dev_t *dev, uint8_t reg, uint32_t data, uint16_t len); /** * @brief Read data from a specified register of the AD7793 device. * @param dev Device structure pointer. * @param reg Register address to read from. * @param data Buffer to store the read data. * @param len Data length to read (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. * @note Boundary: Returns false if dev is not initialized or parameters are invalid. Example: ad7793_read_reg(&dev, REG_CONFIG, &val, 2); */ bool ad7793_read_reg(ad7793_dev_t *dev, uint8_t reg, uint32_t *data, uint16_t len); /** * @brief Reset the AD7793 device. * @param dev Device structure pointer. * @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. * @note Example: ad7793_reset(&dev); */ bool ad7793_reset(ad7793_dev_t *dev); /** * @brief Set the working mode of the AD7793 device. * @param dev Device structure pointer. * @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. * @note Example: ad7793_set_mode(&dev, AD7793_MODE_CONTINUOUS); */ bool ad7793_set_mode(ad7793_dev_t *dev, ad7793_mode_t mode); /** * @brief Set the gain of the AD7793 device. * @param dev Device structure pointer. * @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. * @note Boundary: Returns false if BUF=0 and G>2. Example: ad7793_set_gain(&dev, AD7793_GAIN_4); */ bool ad7793_set_gain(ad7793_dev_t *dev, ad7793_gain_t gain); /** * @brief Set the channel of the AD7793 device. * @param dev Device structure pointer. * @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. * @note Example: ad7793_set_channel(&dev, AD7793_CHANNEL_1); */ bool ad7793_set_channel(ad7793_dev_t *dev, ad7793_channel_t channel); /** * @brief Set the update rate of the AD7793 device. * @param dev Device structure pointer. * @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. * @note Example: ad7793_set_rate(&dev, AD7793_RATE_8_33HZ); */ bool ad7793_set_rate(ad7793_dev_t *dev, ad7793_rate_t rate); /** * @brief Set the reference source of the AD7793 device. * @param dev Device structure pointer. * @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. * @note Example: ad7793_set_reference(&dev, false, 2.5f); */ bool ad7793_set_reference(ad7793_dev_t *dev, bool use_internal, float external_ref); /** * @brief Wait for the AD7793 device to be ready for conversion. * @param dev Device structure pointer. * @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. * @note Example: ad7793_wait_ready(&dev, 1000); */ bool ad7793_wait_ready(ad7793_dev_t *dev, uint16_t timeout_ms); /** * @brief Read the conversion data from the AD7793 device. * @param dev Device structure pointer. * @param value adc value to store the read data (3 bytes for AD7793). * @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. * @note Example: ad7793_read_data(&dev, &val); */ bool ad7793_read_data(ad7793_dev_t *dev, uint32_t *value); /** * @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. * @note Example: float v=ad7793_convert_to_voltage(&dev, code); */ float ad7793_convert_to_voltage(ad7793_dev_t *dev, uint32_t raw_data); /** * @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. * @note Example: uint32_t code=ad7793_convert_voltage_to_code(&dev, v); */ uint32_t ad7793_convert_voltage_to_code(ad7793_dev_t *dev, float voltage); /** * @brief Configure the excitation current source of the AD7793 device. * @param dev Device structure pointer. * @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. * @note Example: ad7793_config_iexc(&dev, 210, 0); */ bool ad7793_config_iexc(ad7793_dev_t *dev, uint16_t current, uint8_t dir); /** * @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. * @note Example: ad7793_set_unipolar(&dev, true); */ bool ad7793_set_unipolar(ad7793_dev_t *dev, bool unipolar); /** * @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. * @note Boundary: Returns false if G>2 and buffer is disabled. Example: ad7793_set_buffered(&dev, true); */ bool ad7793_set_buffered(ad7793_dev_t *dev, bool enable); /** * @brief Initialize the AD7793 device. * @param dev Device structure pointer. * @param hw_if Hardware interface structure containing function pointers. * @param cs_pin Chip select pin. * @param cfg Configuration struct * @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. * @note Example: ad7793_init(&dev, &hw_if, cs_pin, &cfg); */ bool ad7793_init(ad7793_dev_t *dev, ad7793_hw_if_t *hw_if, uint8_t cs_pin, const ad7793_config_t *cfg); /** * @brief Dump the contents of the AD7793 registers for debugging. * @param dev Device structure pointer. * @detail This function reads and prints the contents of the AD7793 registers. * It can be used to verify the register settings and diagnose issues. */ void ad7793_dump_registers(ad7793_dev_t *dev); void ad7793_dump_registers_mode(ad7793_dev_t *dev, int full); #endif // __AD7793_H__