diff --git a/general/include/INA226.h b/general/include/INA226.h new file mode 100644 index 0000000..f586d36 --- /dev/null +++ b/general/include/INA226.h @@ -0,0 +1,74 @@ +/* + INA226AQDGSRQ1 Current Sensor I2C Driver + Datasheet: + https://www.ti.com/lit/ds/symlink/ina226-q1.pdf +*/ + +#ifndef INA226_H +#define INA226_H + +// REGISTERS +#define INA226_CONFIGURATION 0x00 +#define INA226_SHUNT_VOLTAGE 0x01 +#define INA226_BUS_VOLTAGE 0x02 +#define INA226_POWER 0x03 +#define INA226_CURRENT 0x04 +#define INA226_CALIBRATION 0x05 +#define INA226_MASK_ENABLE 0x06 +#define INA226_ALERT_LIMIT 0x07 +#define INA226_MANUFACTURER 0xFE +#define INA226_DIE_ID 0xFF + +// CONFIGURATION MASKS +#define INA226_CONFIG_RESET_MASK 0x8000 // Bit 15 +#define INA226_CONFIG_AVERAGE_MASK 0x0E00 // Bits 9-11 +#define INA226_CONFIG_BUSVC_MASK 0x01C0 // Bits 6-8 +#define INA226_CONFIG_SHUNTVC_MASK 0x0038 // Bits 3-5 +#define INA226_CONFIG_MODE_MASK 0x0007 // Bits 0-2 + +// Function Pointers +typedef int (*WritePtr)(uint16_t dev_addr, uint8_t reg, uint16_t *data); +typedef int (*ReadPtr)(uint16_t dev_addr, uint8_t reg, uint16_t *data); + +typedef struct { + uint16_t dev_addr; + WritePtr write; + ReadPtr read; + float current_lsb; +} ina226_t; + +void ina226_init(ina226_t *ina, WritePtr write, ReadPtr read, + uint16_t dev_addr); + +int ina226_read_reg(ina226_t *ina, uint8_t reg, uint16_t *data); + +int ina226_write_reg(ina226_t *ina, uint8_t reg, uint16_t *data); + +// Writes calibration register. r_shunt in ohms, max_current in amps +int ina226_calibrate(ina226_t *ina, float r_shunt, float max_current); + +// Reads current in amps +int ina226_read_current(ina226_t *ina, float *data); + +// Reads power in watts +int ina226_read_power(ina226_t *ina, float *data); + +// Reads shunt voltage in volts +int ina226_read_shunt_voltage(ina226_t *ina, float *data); + +// Reads bus voltage in volts +int ina226_read_bus_voltage(ina226_t *ina, float *data); + +// Sets configuration register bits 0-11 (operating mode, shunt voltage conversion time, bus voltage conversion time, and averaging mode) +// See datasheet for settings +int ina226_configure(ina226_t *ina, uint8_t mode, uint8_t vshct, uint8_t vbusct, + uint8_t avg); + +// Resets all registers to default values +int ina226_reset(ina226_t ina); + +// Reads manufacturer id register +int ina226_read_manufacturer_id(ina226_t ina, uint16_t *data); + +// Reads die id +int ina226_read_die_id(ina226_t ina, uint16_t *data); \ No newline at end of file diff --git a/general/src/INA226.c b/general/src/INA226.c new file mode 100644 index 0000000..16a98a3 --- /dev/null +++ b/general/src/INA226.c @@ -0,0 +1,146 @@ +/* + INA226AQDGSRQ1 Current Sensor I2C Driver + Datasheet: + https://www.ti.com/lit/ds/symlink/ina226-q1.pdf +*/ + +#include "INA226.h" + +void ina226_init(ina226_t *ina, WritePtr write, ReadPtr read, uint16_t dev_addr) +{ + ina->write = write; + ina->read = read; + ina->dev_addr = dev_addr << 1u; + ina->current_lsb = 0; +} + +int ina226_read_reg(ina226_t *ina, uint8_t reg, uint16_t *data) +{ + return ina->read(ina->dev_addr, reg, data); +} + +int ina226_write_reg(ina226_t *ina, uint8_t reg, uint16_t *data) +{ + return ina->write(ina->dev_addr, reg, data); +} + +// Writes calibration register. r_shunt in ohms, max_current in amps +int ina226_calibrate(ina226_t *ina, float r_shunt, float max_current) +{ + float current_lsb = max_current / 32768; + float cal = 0.00512 / (current_lsb * r_shunt); + uint16_t cal_reg = (uint16_t)floorf(cal); + ina->current_lsb = 0.00512 / (cal_reg * r_shunt); + + return ina226_write_reg(ina, INA226_CALIBRATION, &cal_reg); +} + +// Reads current in amps +int ina226_read_current(ina226_t *ina, float *data) +{ + uint16_t current_reg; + + int status = ina226_read_reg(ina, INA226_CURRENT, ¤t_reg); + if (status != 0) { + return status; + } + + *data = (float)(int16_t)current_reg * ina->current_lsb; + + return status; +} + +// Reads power in watts +int ina226_read_power(ina226_t *ina, float *data) +{ + uint16_t power_reg; + + int status = ina226_read_reg(ina, INA226_POWER, &power_reg); + if (status != 0) { + return status; + } + + *data = (float)(int16_t)power_reg * (ina->current_lsb * 25); + + return status; +} + +// Reads shunt voltage in volts +int ina226_read_shunt_voltage(ina226_t *ina, float *data) +{ + uint16_t shunt_voltage_reg; + + int status = + ina226_read_reg(ina, INA226_SHUNT_VOLTAGE, &shunt_voltage_reg); + if (status != 0) { + return status; + } + + *data = (float)(int16_t)shunt_voltage_reg * + 2.5e-6; // LSB = 2.5 uV per bit + + return status; +} + +// Reads bus voltage in volts +int ina226_read_bus_voltage(ina226_t *ina, float *data) +{ + uint16_t bus_voltage_reg; + + int status = ina226_read_reg(ina, INA226_BUS_VOLTAGE, &bus_voltage_reg); + if (status != 0) { + return status; + } + + *data = (float)bus_voltage_reg * 1.25e-3; // LSB = 1.25 mV per bit + + return status; +} + +// Sets configuration register bits 0-11 (operating mode, shunt voltage conversion time, bus voltage conversion time, and averaging mode) +// See datasheet for settings +int ina226_configure(ina226_t *ina, uint8_t mode, uint8_t vshct, uint8_t vbusct, + uint8_t avg) +{ + uint16_t configuration; + configuration = (avg << 9) | (vbusct << 6) | (vshct << 3) | mode; + return ina226_write_reg(ina, INA226_CONFIGURATION, &configuration); +} + +// Resets all registers to default values +int ina226_reset(ina226_t ina) +{ + uint16_t reset = INA226_CONFIG_RESET_MASK; + return ina226_write_reg(ina, INA226_CONFIGURATION, &reset); +} + +// Reads manufacturer id register +int ina226_read_manufacturer_id(ina226_t ina, uint16_t *data) +{ + uint16_t manufacturer_id; + + int status = + ina226_read_reg(ina, INA226_MANUFACTURER, &manufacturer_id); + if (status != 0) { + return status; + } + + *data = manufacturer_id; + + return status; +} + +// Reads die id +int ina226_read_die_id(ina226_t ina, uint16_t *data) +{ + uint16_t die_id; + + int status = ina226_read_reg(ina, INA226_DIE_ID, &die_id); + if (status != 0) { + return status; + } + + *data = die_id; + + return status; +}