drivers: sensor: ina237: fix current sign issue

Fix current sign extension logic and consolidate sensor scaling code
into a single block.

Signed-off-by: Eric Holmberg <eric.holmberg@northriversystems.co.nz>
This commit is contained in:
Eric Holmberg 2023-07-27 23:21:08 +12:00 committed by Maureen Helm
commit 2d3a391191
3 changed files with 47 additions and 35 deletions

View file

@ -31,58 +31,36 @@ LOG_MODULE_REGISTER(INA237, CONFIG_SENSOR_LOG_LEVEL);
*/
#define INA237_DIETEMP_TO_uDegC(x) (((x) >> 4) * 125000)
static void micro_s32_to_sensor_value(struct sensor_value *val, int32_t value_microX)
{
val->val1 = value_microX / 1000000L;
val->val2 = value_microX % 1000000L;
}
static int ina237_channel_get(const struct device *dev, enum sensor_channel chan,
struct sensor_value *val)
{
struct ina237_data *data = dev->data;
const struct ina237_data *data = dev->data;
const struct ina237_config *config = dev->config;
uint32_t bus_uv, current_ua, power_uw;
int32_t temp_uDegC;
int32_t sign = 1;
switch (chan) {
case SENSOR_CHAN_VOLTAGE:
bus_uv = INA237_BUS_VOLTAGE_TO_uV(data->bus_voltage);
val->val1 = bus_uv / 1000000U;
val->val2 = bus_uv % 1000000U;
micro_s32_to_sensor_value(val, INA237_BUS_VOLTAGE_TO_uV(data->bus_voltage));
break;
case SENSOR_CHAN_CURRENT:
if (data->current & INA23X_CURRENT_SIGN_BIT) {
current_ua = ~data->current + 1U;
sign = -1;
} else {
current_ua = data->current;
sign = 1;
}
/* see datasheet "Current and Power calculations" section */
current_ua = current_ua * config->current_lsb;
/* convert to fractional amperes */
val->val1 = sign * (int32_t)(current_ua / 1000000U);
val->val2 = sign * (int32_t)(current_ua % 1000000U);
micro_s32_to_sensor_value(val, data->current * config->current_lsb);
break;
case SENSOR_CHAN_POWER:
/* see datasheet "Current and Power calculations" section */
power_uw = (data->power * INA237_POWER_SCALING * config->current_lsb) / 10000U;
/* convert to fractional watts */
val->val1 = (int32_t)(power_uw / 1000000U);
val->val2 = (int32_t)(power_uw % 1000000U);
micro_s32_to_sensor_value(val,
(data->power * INA237_POWER_SCALING * config->current_lsb) / 10000U);
break;
case SENSOR_CHAN_DIE_TEMP:
temp_uDegC = INA237_DIETEMP_TO_uDegC(data->die_temp);
val->val1 = temp_uDegC / 1000000L;
val->val2 = abs(temp_uDegC) % 1000000L;
if (temp_uDegC < 0) {
val->val2 = -val->val2;
}
micro_s32_to_sensor_value(val, INA237_DIETEMP_TO_uDegC(data->die_temp));
break;
default:

View file

@ -37,7 +37,7 @@
struct ina237_data {
const struct device *dev;
uint16_t current;
int16_t current;
uint16_t bus_voltage;
uint32_t power;
int16_t die_temp;

View file

@ -44,6 +44,39 @@ ZTEST(ina237_0, test_default_config)
*
* @param fixture
*/
static void test_current(struct ina237_fixture *fixture)
{
/* 16-bit signed value for current register */
const int16_t current_reg_vectors[] = {
32767,
1000,
100,
1,
0,
-1,
-100,
-1000,
-32768,
};
for (int idx = 0; idx < ARRAY_SIZE(current_reg_vectors); idx++) {
struct sensor_value sensor_val;
int16_t current_register = current_reg_vectors[idx];
double current_expected_A = fixture->current_lsb_uA * 1e-6 * current_register;
/* set current reading */
ina237_mock_set_register(fixture->mock->data, INA237_REG_CURRENT, current_register);
/* Verify sensor value is correct */
zassert_ok(sensor_sample_fetch(fixture->dev));
zassert_ok(sensor_channel_get(fixture->dev, SENSOR_CHAN_CURRENT, &sensor_val));
double current_actual_A = sensor_value_to_double(&sensor_val);
zexpect_within(current_expected_A, current_actual_A, fixture->current_lsb_uA*1e-6,
"Expected %.6f A, got %.6f A", current_expected_A, current_actual_A);
}
}
static void test_bus_voltage(struct ina237_fixture *fixture)
{
zassert_not_null(fixture->mock);
@ -128,6 +161,7 @@ static struct ina237_fixture fixtures[] = {
/* Create a test suite for each enabled ina237 device node */
#define INA237_TESTS(inst) \
ZTEST(ina237_##inst, test_current) { test_current(&fixtures[inst]); } \
ZTEST(ina237_##inst, test_bus_voltage) { test_bus_voltage(&fixtures[inst]); } \
ZTEST(ina237_##inst, test_temperature) { test_temperature(&fixtures[inst]); } \
ZTEST_SUITE(ina237_##inst, NULL, NULL, NULL, NULL, NULL);