blob: d3073fd307f760ea43b7655c446600b835b12981 [file] [log] [blame]
#include "ina231.h"
#include <err.h>
#include <dev/i2c.h>
#include <lib/console.h>
#include <platform.h>
#include <stdint.h>
#include <stdio.h>
enum {
INA231_REG_CONFIG = 0,
INA231_REG_SHUNT_VOLTAGE = 1,
INA231_REG_BUS_VOLTAGE = 2,
INA231_REG_POWER = 3,
INA231_REG_CURRENT = 4,
INA231_REG_CALIBRATION = 5,
INA231_REG_MASK_ENABLE = 6,
INA231_REG_MASK_ALERT_LIMIT = 7,
};
enum {
INA231_CONFIG_MODE_POWER_DOWN = 0 << 0,
INA231_CONFIG_MODE_TRIG_SHUNT = 1 << 0,
INA231_CONFIG_MODE_TRIG_BUS = 2 << 0,
INA231_CONFIG_MODE_TRIG_SHUNT_BUS = 3 << 0,
INA231_CONFIG_MODE_POWER_DOWN2 = 4 << 0,
INA231_CONFIG_MODE_CONT_SHUNT = 5 << 0,
INA231_CONFIG_MODE_CONT_BUS = 6 << 0,
INA231_CONFIG_MODE_CONT_SHUNT_BUS = 7 << 0,
INA231_CONFIG_V_SHUNT_CT_140_US = 0 << 3,
INA231_CONFIG_V_SHUNT_CT_204_US = 1 << 3,
INA231_CONFIG_V_SHUNT_CT_332_US = 2 << 3,
INA231_CONFIG_V_SHUNT_CT_588_US = 3 << 3,
INA231_CONFIG_V_SHUNT_CT_1100_US = 4 << 3,
INA231_CONFIG_V_SHUNT_CT_2116_US = 5 << 3,
INA231_CONFIG_V_SHUNT_CT_4156_US = 6 << 3,
INA231_CONFIG_V_SHUNT_CT_8244_US = 7 << 3,
INA231_CONFIG_V_BUS_CT_140_US = 0 << 6,
INA231_CONFIG_V_BUS_CT_204_US = 1 << 6,
INA231_CONFIG_V_BUS_CT_332_US = 2 << 6,
INA231_CONFIG_V_BUS_CT_588_US = 3 << 6,
INA231_CONFIG_V_BUS_CT_1100_US = 4 << 6,
INA231_CONFIG_V_BUS_CT_2116_US = 5 << 6,
INA231_CONFIG_V_BUS_CT_4156_US = 6 << 6,
INA231_CONFIG_V_BUS_CT_8244_US = 7 << 6,
INA231_CONFIG_AVG_1 = 0 << 9,
INA231_CONFIG_AVG_4 = 1 << 9,
INA231_CONFIG_AVG_16 = 2 << 9,
INA231_CONFIG_AVG_64 = 3 << 9,
INA231_CONFIG_AVG_128 = 4 << 9,
INA231_CONFIG_AVG_256 = 5 << 9,
INA231_CONFIG_AVG_512 = 6 << 9,
INA231_CONFIG_AVG_1024 = 7 << 9,
INA231_CONFIG_RST = 1 << 16,
};
enum {
INA231_ME_LEN = 1 << 0, // Alert Latch Enable.
INA231_ME_APOL = 1 << 1, // Alert Polarity.
INA231_ME_OVF = 1 << 2, // Math Overflow.
INA231_ME_CRVF = 1 << 3, // Conversion Ready Flag.
INA231_ME_AFF = 1 << 4, // Alert Function Flag.
INA231_ME_CNVR = 1 << 10, // Assert Alert on Conversion Ready.
INA231_ME_POL = 1 << 11, // Assert Alert on Power Over Limit.
INA231_ME_BUL = 1 << 12, // Assert Alert on Bus Under Voltage Limit.
INA231_ME_BOL = 1 << 13, // Assert Alert on Bus Over Voltage Limit.
INA231_ME_SUL = 1 << 14, // Assert Alert on Shunt Under Voltage Limit.
INA231_ME_SOL = 1 << 15, // Assert Alert on Shunt Over Voltage Limit.
};
static const int INA231_BUS = 2;
static const uint8_t INA231_ADDR = 0x40;
static const float INA231_SHUNT_R = 0.010; // [Ohms]
static lk_bigtime_t ina231_start_time;
static uint32_t ina231_errors;
static uint32_t ina231_samples;
static uint16_t ina231_v_shunt;
static uint16_t ina231_v_bus;
static status_t ina231_write(uint8_t reg, uint16_t val) {
uint8_t data[2];
data[0] = val >> 8;
data[1] = val & 0xff;
status_t ret = i2c_write_reg_bytes(INA231_BUS, INA231_ADDR, reg, data, 2);
if (ret != NO_ERROR) {
return ret;
}
return NO_ERROR;
}
static status_t ina231_read(uint8_t reg, uint16_t *val) {
uint8_t data[2];
status_t ret = i2c_read_reg_bytes(INA231_BUS, INA231_ADDR, reg, data, 2);
if (ret != NO_ERROR) {
return ret;
}
*val = data[0] << 8 | data[1];
return NO_ERROR;
}
void ina231_init(void) {
status_t ret = ina231_write(INA231_REG_CONFIG,
INA231_CONFIG_MODE_CONT_SHUNT_BUS
| INA231_CONFIG_V_SHUNT_CT_332_US
| INA231_CONFIG_V_BUS_CT_332_US
| INA231_CONFIG_AVG_1);
if (ret != NO_ERROR) {
printf("Error configuring ina231: %d\n", ret);
}
ina231_start_time = current_time_hires();
}
void ina231_ping(void) {
status_t ret;
uint16_t status;
ret = ina231_read(INA231_REG_MASK_ENABLE, &status);
if (ret != NO_ERROR) {
ina231_errors++;
return;
}
if (!(status & INA231_ME_CRVF)) {
return;
}
uint16_t v_shunt;
uint16_t v_bus;
ret = ina231_read(INA231_REG_SHUNT_VOLTAGE, &v_shunt);
if (ret != NO_ERROR) {
ina231_errors++;
return;
}
ret = ina231_read(INA231_REG_BUS_VOLTAGE, &v_bus);
if (ret != NO_ERROR) {
ina231_errors++;
return;
}
ina231_v_shunt = v_shunt;
ina231_v_bus = v_bus;
ina231_samples++;
}
static int cmd_ina231_status(int argc, const cmd_args *argv) {
lk_bigtime_t delta = current_time_hires() - ina231_start_time;
float samples_per_sec = (float) ina231_samples / delta * 1000000.0f;
float v_shunt = ina231_v_shunt * 0.0025;
float v_bus = ina231_v_bus * 0.00125;
float i_shunt = v_shunt / INA231_SHUNT_R;
float power = i_shunt * v_bus;
printf("samples: %u\n", ina231_samples);
printf("samples/sec: %f\n", samples_per_sec);
printf("errors: %u\n", ina231_errors);
printf("v_bus: %f V \n", v_bus);
printf("v_shunt: %f mV\n", v_shunt);
printf("i_shunt: %f mA\n", i_shunt);
printf("power: %f mW\n", power);
return 0;
}
static int cmd_ina231_dump(int argc, const cmd_args *argv) {
int i;
for (i = 0; i < 8; i++) {
uint16_t data;
status_t ret = ina231_read(i, &data);
printf("%d: ", i);
if (ret != NO_ERROR) {
printf("error %d\n", ret);
} else {
printf("%04x\n", data);
}
}
return 0;
}
static int cmd_ina231_read(int argc, const cmd_args *argv) {
if (argc != 2) {
printf("usage: ina_231_read <reg>\n");
return 1;
}
uint8_t reg = argv[1].u;
uint16_t data;
status_t ret = ina231_read(reg, &data);
if (ret != NO_ERROR) {
printf("error: %d\n", ret);
return 1;
}
printf("%02x: %04x\n", reg, data);
return 0;
}
STATIC_COMMAND_START
STATIC_COMMAND("ina231_read", "read an ina231 register", &cmd_ina231_read)
STATIC_COMMAND("ina231_dump", "dump ina231 registers", &cmd_ina231_dump)
STATIC_COMMAND("ina231_status", "ina231 status", &cmd_ina231_status)
STATIC_COMMAND_END(nucleo);