From 5c4b192859b235d71557aab0be638c34aed74557 Mon Sep 17 00:00:00 2001 From: bjackson312006 Date: Thu, 31 Oct 2024 17:51:03 -0400 Subject: [PATCH] (First draft) Added functions for reading/writing registers and converting to real current, power, and voltage --- general/include/INA226.h | 38 ++++++++++ general/src/INA226.c | 155 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 193 insertions(+) create mode 100644 general/include/INA226.h create mode 100644 general/src/INA226.c diff --git a/general/include/INA226.h b/general/include/INA226.h new file mode 100644 index 0000000..251bd69 --- /dev/null +++ b/general/include/INA226.h @@ -0,0 +1,38 @@ +/* + 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; diff --git a/general/src/INA226.c b/general/src/INA226.c new file mode 100644 index 0000000..d249373 --- /dev/null +++ b/general/src/INA226.c @@ -0,0 +1,155 @@ +/* + 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; // pretty sure it needs to be shifted + ina->current_lsb = + 0; // temporary value before ina226_calibrate (not sure if i need this?) +} + +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); // need to store as an int but not sure how since different current_lsb values might need different scaling factors + + 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) +{ + // (probably need to check if params <= 7 but im not sure) + 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 (kinda pointless) +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 (also kinda pointless) +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; +} + +// still need to do stuff w/ alert register and mask/enable register +// might also want to have functions to set each individual setting in the configuration register +// also not sure if the converted current, power, and voltage should be given as float \ No newline at end of file