Files
ch32v208_sens/inc/gxht30_hw_i2c.h

160 lines
4.8 KiB
C

#ifndef _GXHT30_HW_I2C_H
#define _GXHT30_HW_I2C_H
#include <stdbool.h>
#include <stdint.h>
#include "hw_i2c.h"
// GXHT30 I2C addresses
#define GXHT30_I2C_ADDR_DEFAULT 0x44
#define GXHT30_I2C_ADDR_ALT 0x45
// GXHT30 cmds
#define GXHT30_CMD_MEAS_MSB 0x2C
#define GXHT30_CMD_MEAS_LSB 0x06
#define GXHT30_CMD_SOFT_RESET_MSB 0x30
#define GXHT30_CMD_SOFT_RESET_LSB 0xA2
#define GXHT30_CMD_HEATER_ON_MSB 0x30
#define GXHT30_CMD_HEATER_ON_LSB 0x6D
#define GXHT30_CMD_HEATER_OFF_MSB 0x30
#define GXHT30_CMD_HEATER_OFF_LSB 0x66
#define GXHT30_CMD_STATUS_MSB 0xF3
#define GXHT30_CMD_STATUS_LSB 0x2D
#define GXHT30_CMD_CLEAR_STATUS_MSB 0x30
#define GXHT30_CMD_CLEAR_STATUS_LSB 0x41
// conversion constants
#define GXHT30_TEMP_MULTIPLIER 2670
#define GXHT30_TEMP_OFFSET 45000000L
#define GXHT30_HUM_MULTIPLIER 1526
#define GXHT30_SCALE_DIVISOR 10000
typedef struct {
int32_t temperature_x100; // Temperature in hundredths of a degree C
int32_t humidity_x100; // Humidity in hundredths of a percent RH
uint8_t error; // Last error code
} GXHT30_Data;
typedef struct {
uint8_t alert_pending; // Bit 15: Alert status
uint8_t heater_on; // Bit 13: Heater status
uint8_t humidity_alert; // Bit 11: Humidity tracking alert
uint8_t temperature_alert; // Bit 10: Temperature tracking alert
uint8_t reset_detected; // Bit 4: System reset detected
uint8_t command_status; // Bit 1: Last command execution status
uint8_t crc_status; // Bit 0: Write data CRC checksum status
uint16_t raw_status; // Raw 16-bit status value
} GXHT30_Status;
enum GXHT30_Error {
GXHT30_OK = 0,
GXHT30_ERR_TIMEOUT,
GXHT30_ERR_CRC,
GXHT30_ERR_I2C
};
static inline bool gxht30_crc8_check(uint8_t msb, uint8_t lsb, uint8_t crc) {
uint8_t calc_crc = 0xFF;
uint8_t data[2] = {msb, lsb};
for (uint8_t byte = 0; byte < 2; byte++) {
calc_crc ^= data[byte];
for (uint8_t i = 0; i < 8; i++) {
calc_crc = (calc_crc & 0x80) ? (calc_crc << 1) ^ 0x31 : (calc_crc << 1);
}
}
return calc_crc == crc;
}
static inline uint8_t gxht30_send_command(uint8_t addr, uint8_t cmd_msb,
uint8_t cmd_lsb) {
uint8_t cmd[2] = {cmd_msb, cmd_lsb};
uint8_t err = i2c_write(addr, cmd, 2);
return (err == I2C_OK) ? GXHT30_OK : GXHT30_ERR_I2C;
}
static inline uint8_t gxht30_read_data(uint8_t addr, GXHT30_Data* data) {
uint8_t cmd[2] = {GXHT30_CMD_MEAS_MSB, GXHT30_CMD_MEAS_LSB};
uint8_t rx_data[6];
uint8_t err;
// send measurement command and read
if ((err = i2c_write_read(addr, cmd, 2, rx_data, 6)) != I2C_OK) {
data->error = GXHT30_ERR_I2C;
return GXHT30_ERR_I2C;
}
// verify CRC for both temp and humidity
if (!gxht30_crc8_check(rx_data[0], rx_data[1], rx_data[2]) ||
!gxht30_crc8_check(rx_data[3], rx_data[4], rx_data[5])) {
data->error = GXHT30_ERR_CRC;
return GXHT30_ERR_CRC;
}
// calc the values
uint16_t temp_raw = (rx_data[0] << 8) | rx_data[1];
uint16_t hum_raw = (rx_data[3] << 8) | rx_data[4];
data->temperature_x100 =
(((int64_t)temp_raw * GXHT30_TEMP_MULTIPLIER) - GXHT30_TEMP_OFFSET) /
GXHT30_SCALE_DIVISOR;
data->humidity_x100 =
((int64_t)hum_raw * GXHT30_HUM_MULTIPLIER) / GXHT30_SCALE_DIVISOR;
data->error = GXHT30_OK;
return GXHT30_OK;
}
static inline uint8_t gxht30_read_status(uint8_t addr, GXHT30_Status* status) {
uint8_t cmd[2] = {GXHT30_CMD_STATUS_MSB, GXHT30_CMD_STATUS_LSB};
uint8_t rx_data[3];
uint8_t err;
if ((err = i2c_write_read(addr, cmd, 2, rx_data, 3)) != I2C_OK) {
return GXHT30_ERR_I2C;
}
// verify CRC
if (!gxht30_crc8_check(rx_data[0], rx_data[1], rx_data[2])) {
return GXHT30_ERR_CRC;
}
// parse status register
uint16_t raw = (rx_data[0] << 8) | rx_data[1];
status->raw_status = raw;
status->alert_pending = (raw >> 15) & 0x01;
status->heater_on = (raw >> 13) & 0x01;
status->humidity_alert = (raw >> 11) & 0x01;
status->temperature_alert = (raw >> 10) & 0x01;
status->reset_detected = (raw >> 4) & 0x01;
status->command_status = (raw >> 1) & 0x01;
status->crc_status = raw & 0x01;
return GXHT30_OK;
}
static inline uint8_t gxht30_soft_reset(uint8_t addr) {
return gxht30_send_command(addr, GXHT30_CMD_SOFT_RESET_MSB,
GXHT30_CMD_SOFT_RESET_LSB);
}
static inline uint8_t gxht30_heater_on(uint8_t addr) {
return gxht30_send_command(addr, GXHT30_CMD_HEATER_ON_MSB,
GXHT30_CMD_HEATER_ON_LSB);
}
static inline uint8_t gxht30_heater_off(uint8_t addr) {
return gxht30_send_command(addr, GXHT30_CMD_HEATER_OFF_MSB,
GXHT30_CMD_HEATER_OFF_LSB);
}
static inline uint8_t gxht30_clear_status(uint8_t addr) {
return gxht30_send_command(addr, GXHT30_CMD_CLEAR_STATUS_MSB,
GXHT30_CMD_CLEAR_STATUS_LSB);
}
#endif // _GXHT30_HW_I2C_H