From 19e44ae9a0b654aa49818a4acb0977e9be2b3855 Mon Sep 17 00:00:00 2001 From: Eric Holmberg Date: Thu, 20 Jul 2023 23:50:55 +1200 Subject: [PATCH] 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 --- drivers/sensor/ina23x/Kconfig | 14 ++++++ drivers/sensor/ina23x/ina237.c | 28 ++++++++++- drivers/sensor/ina23x/ina237.h | 3 ++ include/zephyr/drivers/sensor.h | 4 ++ tests/drivers/sensor/ina237/prj.conf | 1 + tests/drivers/sensor/ina237/src/ina237_test.c | 46 +++++++++++++++++++ 6 files changed, 95 insertions(+), 1 deletion(-) diff --git a/drivers/sensor/ina23x/Kconfig b/drivers/sensor/ina23x/Kconfig index 5624620b63d..c19b58d0d54 100644 --- a/drivers/sensor/ina23x/Kconfig +++ b/drivers/sensor/ina23x/Kconfig @@ -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 diff --git a/drivers/sensor/ina23x/ina237.c b/drivers/sensor/ina23x/ina237.c index fb8f2354d9f..d63c5e950ba 100644 --- a/drivers/sensor/ina23x/ina237.c +++ b/drivers/sensor/ina23x/ina237.c @@ -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; } diff --git a/drivers/sensor/ina23x/ina237.h b/drivers/sensor/ina23x/ina237.h index ff3c28cf885..08264f620fa 100644 --- a/drivers/sensor/ina23x/ina237.h +++ b/drivers/sensor/ina23x/ina237.h @@ -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; }; diff --git a/include/zephyr/drivers/sensor.h b/include/zephyr/drivers/sensor.h index 87721c670da..1569f4a27b3 100644 --- a/include/zephyr/drivers/sensor.h +++ b/include/zephyr/drivers/sensor.h @@ -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 **/ diff --git a/tests/drivers/sensor/ina237/prj.conf b/tests/drivers/sensor/ina237/prj.conf index 5bac59254f9..3c7471b31b9 100644 --- a/tests/drivers/sensor/ina237/prj.conf +++ b/tests/drivers/sensor/ina237/prj.conf @@ -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 diff --git a/tests/drivers/sensor/ina237/src/ina237_test.c b/tests/drivers/sensor/ina237/src/ina237_test.c index 9609b521b00..b5bedb0e5d3 100644 --- a/tests/drivers/sensor/ina237/src/ina237_test.c +++ b/tests/drivers/sensor/ina237/src/ina237_test.c @@ -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)