drivers: sensor: ina237: add shunt voltage support

Add ability to retrieve the shunt voltage if the end user wants to do
the power calculation manually to handle negative power values.

Signed-off-by: Eric Holmberg <eric.holmberg@northriversystems.co.nz>
This commit is contained in:
Eric Holmberg 2023-07-20 23:50:55 +12:00 committed by Maureen Helm
parent a70d056513
commit 19e44ae9a0
6 changed files with 95 additions and 1 deletions

View file

@ -26,6 +26,20 @@ config INA237
help
Enable driver for INA237.
config INA237_VSHUNT
bool "INA237 VShunt Measurement Enable"
depends on DT_HAS_TI_INA237_ENABLED
help
Enable shunt voltage measurement for INA237.
This is the actual shunt voltage measured which is scaled within the
INA237 based upon the SHUNT_CAL register. This value is useful for
looking at measurement noise or debugging the SHUNT_CAL value.
Note that enabling this option requires an extra I2C read when
SENSOR_CHAN_ALL is selected, so only enable if the shunt voltage
measurement is required.
config INA230_TRIGGER
bool "INA230 trigger mode"
depends on INA230

View file

@ -65,6 +65,18 @@ static int ina237_channel_get(const struct device *dev, enum sensor_channel chan
INA237_POWER_TO_uW((uint64_t)data->power * config->current_lsb));
break;
#ifdef CONFIG_INA237_VSHUNT
case SENSOR_CHAN_VSHUNT:
if (config->config & INA237_CFG_HIGH_PRECISION) {
/* high-resolution mode - 1.25 uV/bit, sensor value is in mV */
micro_s32_to_sensor_value(val, data->shunt_voltage * 1250);
} else {
/* standard-resolution - 5 uV/bit -> nano-volts */
micro_s32_to_sensor_value(val, data->shunt_voltage * 5000);
}
break;
#endif /* CONFIG_INA237_VSHUNT */
case SENSOR_CHAN_DIE_TEMP:
micro_s32_to_sensor_value(val, INA237_DIETEMP_TO_uDegC(data->die_temp));
break;
@ -165,6 +177,16 @@ static int ina237_read_data(const struct device *dev)
}
}
#ifdef CONFIG_INA237_VSHUNT
if ((data->chan == SENSOR_CHAN_ALL) || (data->chan == SENSOR_CHAN_VSHUNT)) {
ret = ina23x_reg_read_16(&config->bus, INA237_REG_SHUNT_VOLT, &data->shunt_voltage);
if (ret < 0) {
LOG_ERR("Failed to read shunt voltage");
return ret;
}
}
#endif /* CONFIG_INA237_VSHUNT */
return 0;
}
@ -179,7 +201,11 @@ static int ina237_sample_fetch(const struct device *dev, enum sensor_channel cha
struct ina237_data *data = dev->data;
if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_VOLTAGE && chan != SENSOR_CHAN_CURRENT &&
chan != SENSOR_CHAN_POWER && chan != SENSOR_CHAN_DIE_TEMP) {
chan != SENSOR_CHAN_POWER &&
#ifdef CONFIG_INA237_VSHUNT
chan != SENSOR_CHAN_VSHUNT &&
#endif /* CONFIG_INA237_VSHUNT */
chan != SENSOR_CHAN_DIE_TEMP) {
return -ENOTSUP;
}

View file

@ -43,6 +43,9 @@ struct ina237_data {
uint16_t bus_voltage;
uint32_t power;
int16_t die_temp;
#ifdef CONFIG_INA237_VSHUNT
int16_t shunt_voltage;
#endif
enum sensor_channel chan;
struct ina23x_trigger trigger;
};

View file

@ -124,6 +124,10 @@ enum sensor_channel {
/** Voltage, in volts **/
SENSOR_CHAN_VOLTAGE,
/** Current Shunt Voltage in milli-volts **/
SENSOR_CHAN_VSHUNT,
/** Current, in amps **/
SENSOR_CHAN_CURRENT,
/** Power in watts **/

View file

@ -10,5 +10,6 @@ CONFIG_I2C_EMUL=y
CONFIG_I2C_LOG_LEVEL_DBG=y
CONFIG_INA237=y
CONFIG_INA237_VSHUNT=y
CONFIG_CBPRINTF_FP_SUPPORT=y

View file

@ -197,6 +197,51 @@ static void test_temperature(struct ina237_fixture *fixture)
}
}
static void test_vshunt(struct ina237_fixture *fixture)
{
zassert_not_null(fixture->mock);
/* 16-bit signed value for voltage register (but always positive) 3.125 mV/bit */
const int16_t vshunt_reg_vectors[] = {
32767, /* maximum shunt voltage of 163.84 mV or 40.96 mV */
27200,
1000,
100,
1,
0,
-1,
-100,
-1000,
-32768, /* minimum shunt voltage of -163.84 mV or -40.96 mV */
};
for (int idx = 0; idx < ARRAY_SIZE(vshunt_reg_vectors); idx++) {
struct sensor_value sensor_val;
ina237_mock_set_register(fixture->mock->data, INA237_REG_SHUNT_VOLT,
vshunt_reg_vectors[idx]);
/* Verify sensor value is correct */
zassert_ok(sensor_sample_fetch_chan(fixture->dev, SENSOR_CHAN_VSHUNT));
zassert_ok(sensor_channel_get(fixture->dev, SENSOR_CHAN_VSHUNT, &sensor_val));
double vshunt_actual_mV = sensor_value_to_double(&sensor_val);
double vshunt_expected_mV = vshunt_reg_vectors[idx];
if (fixture->config & INA237_CFG_HIGH_PRECISION) {
/* High precision mode - 1.25 uV/bit = 1250 nV/bit*/
vshunt_expected_mV *= 1000 * 1.250e-6;
} else {
/* Standard precision mode - 5 uV/bit = 5000 nV/bit */
vshunt_expected_mV *= 1000 * 5e-6;
}
zexpect_within(vshunt_expected_mV, vshunt_actual_mV, 1e-9,
"For %d, Expected %.6f mV, got %.6f mV", vshunt_reg_vectors[idx],
vshunt_expected_mV, vshunt_actual_mV);
}
}
/* Create a test fixture for each enabled ina237 device node */
#define DT_DRV_COMPAT ti_ina237
#define INA237_FIXTURE_ENTRY(inst) \
@ -219,6 +264,7 @@ static struct ina237_fixture fixtures[] = {
ZTEST(ina237_##inst, test_bus_voltage) { test_bus_voltage(&fixtures[inst]); } \
ZTEST(ina237_##inst, test_power) { test_power(&fixtures[inst]); } \
ZTEST(ina237_##inst, test_temperature) { test_temperature(&fixtures[inst]); } \
ZTEST(ina237_##inst, test_vshunt) { test_vshunt(&fixtures[inst]); } \
ZTEST_SUITE(ina237_##inst, NULL, NULL, NULL, NULL, NULL);
DT_INST_FOREACH_STATUS_OKAY(INA237_TESTS)