| /* |
| * Copyright (c) 2023 North River Systems Ltd |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <zephyr/device.h> |
| #include <zephyr/devicetree.h> |
| #include <zephyr/drivers/emul.h> |
| #include <zephyr/drivers/i2c_emul.h> |
| #include <zephyr/drivers/sensor.h> |
| #include <zephyr/dt-bindings/sensor/ina237.h> |
| #include <zephyr/ztest.h> |
| |
| #include <ina237_emul.h> |
| #include <ina237.h> |
| |
| struct ina237_fixture { |
| const struct device *dev; |
| const struct emul *mock; |
| const uint16_t current_lsb_uA; |
| const uint16_t rshunt_uOhms; |
| const uint16_t config; |
| }; |
| |
| /** |
| * @brief Verify devicetree default configuration is correct. |
| */ |
| ZTEST(ina237_0, test_default_config) |
| { |
| const struct ina237_config *config; |
| const struct device *dev = DEVICE_DT_GET(DT_NODELABEL(ina237_default_test)); |
| |
| zassert_not_null(dev); |
| config = dev->config; |
| zassert_not_null(config); |
| |
| /* confirm default DT settings */ |
| zexpect_equal(0xFB68, config->adc_config, |
| "0xFB68 != adc_config (0x%x)", config->adc_config); |
| zexpect_equal(0x0000, config->config); |
| } |
| |
| /** |
| * @brief Verify bus voltages for all ina237 nodes in DT |
| * |
| * @param fixture |
| */ |
| |
| static void test_shunt_cal(struct ina237_fixture *fixture) |
| { |
| /* Confirm SHUNT_CAL register which is 819.2e6 * Current_LSB * Rshunt */ |
| double shunt_cal = 819.2e6 * fixture->current_lsb_uA * 1e-6 * fixture->rshunt_uOhms * 1e-6; |
| |
| if (fixture->config & INA237_CFG_HIGH_PRECISION) { |
| /* High precision mode */ |
| shunt_cal *= 4; |
| } |
| |
| uint32_t shunt_register_actual; |
| uint16_t shunt_register_expected = (uint16_t)shunt_cal; |
| |
| zassert_ok(ina237_mock_get_register(fixture->mock->data, INA237_REG_CALIB, |
| &shunt_register_actual)); |
| zexpect_within(shunt_register_expected, shunt_register_actual, 1, |
| "Expected %d, got %d", shunt_register_expected, shunt_register_actual); |
| } |
| |
| 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); |
| |
| /* 16-bit signed value for voltage register (but always positive) 3.125 mV/bit */ |
| const int16_t voltage_reg_vectors[] = { |
| 32767, |
| 27200, /* 85V maximum voltage */ |
| 1000, |
| 100, |
| 1, |
| 0, |
| }; |
| |
| for (int idx = 0; idx < ARRAY_SIZE(voltage_reg_vectors); idx++) { |
| struct sensor_value sensor_val; |
| |
| ina237_mock_set_register(fixture->mock->data, INA237_REG_BUS_VOLT, |
| voltage_reg_vectors[idx]); |
| |
| /* Verify sensor value is correct */ |
| zassert_ok(sensor_sample_fetch(fixture->dev)); |
| zassert_ok(sensor_channel_get(fixture->dev, SENSOR_CHAN_VOLTAGE, &sensor_val)); |
| |
| double voltage_actual_V = sensor_value_to_double(&sensor_val); |
| double voltage_expected_V = voltage_reg_vectors[idx] * 3.125e-3; |
| |
| zexpect_within(voltage_expected_V, voltage_actual_V, 1e-6, |
| "Expected %.6f A, got %.6f A", voltage_expected_V, voltage_actual_V); |
| } |
| } |
| |
| static void test_power(struct ina237_fixture *fixture) |
| { |
| /* 24-bit unsigned value for power register */ |
| const uint32_t power_reg_vectors[] = { |
| 16777215, |
| 65535, |
| 32767, |
| 1000, |
| 100, |
| 1, |
| 0, |
| }; |
| |
| for (int idx = 0; idx < ARRAY_SIZE(power_reg_vectors); idx++) { |
| struct sensor_value sensor_val; |
| uint32_t power_register = power_reg_vectors[idx]; |
| |
| /* power is 0.2 * current_lsb * register */ |
| double power_expected_W = 0.2 * fixture->current_lsb_uA * 1e-6 * power_register; |
| |
| /* set current reading */ |
| ina237_mock_set_register(fixture->mock->data, INA237_REG_POWER, power_register); |
| |
| /* Verify sensor value is correct */ |
| zassert_ok(sensor_sample_fetch(fixture->dev)); |
| zassert_ok(sensor_channel_get(fixture->dev, SENSOR_CHAN_POWER, &sensor_val)); |
| double power_actual_W = sensor_value_to_double(&sensor_val); |
| |
| zexpect_within(power_expected_W, power_actual_W, 1e-6, |
| "Expected %.6f C, got %.6f C", power_expected_W, power_actual_W); |
| } |
| } |
| |
| static void test_temperature(struct ina237_fixture *fixture) |
| { |
| zassert_not_null(fixture->mock); |
| |
| /* 12-bit signed value with bottom 4-bits reserved - 125 mDegC / bit */ |
| const int16_t temp_reg_vectors[] = { |
| 16000, /* 125C */ |
| 1000, |
| 100, |
| 1, |
| 0, |
| -100, |
| -1000, |
| -5120, /* -40C */ |
| }; |
| |
| for (int idx = 0; idx < ARRAY_SIZE(temp_reg_vectors); idx++) { |
| struct sensor_value sensor_val; |
| |
| ina237_mock_set_register(fixture->mock->data, INA237_REG_DIETEMP, |
| temp_reg_vectors[idx]); |
| |
| /* Verify sensor value is correct */ |
| zassert_ok(sensor_sample_fetch(fixture->dev)); |
| zassert_ok(sensor_channel_get(fixture->dev, SENSOR_CHAN_DIE_TEMP, &sensor_val)); |
| |
| double temp_actual_degC = sensor_value_to_double(&sensor_val); |
| double temp_expected_degC = (temp_reg_vectors[idx] / 16) * 125e-3; |
| |
| zexpect_within(temp_expected_degC, temp_actual_degC, 125e-3, |
| "Expected %.6f A, got %.6f A", temp_expected_degC, temp_actual_degC); |
| } |
| } |
| |
| 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) \ |
| { \ |
| .dev = DEVICE_DT_INST_GET(inst), \ |
| .mock = EMUL_DT_GET(DT_DRV_INST(inst)), \ |
| .current_lsb_uA = DT_INST_PROP(inst, current_lsb_microamps), \ |
| .rshunt_uOhms = DT_INST_PROP(inst, rshunt_micro_ohms), \ |
| .config = DT_INST_PROP(inst, config), \ |
| }, |
| |
| static struct ina237_fixture fixtures[] = { |
| DT_INST_FOREACH_STATUS_OKAY(INA237_FIXTURE_ENTRY) |
| }; |
| |
| /* Create a test suite for each enabled ina237 device node */ |
| #define INA237_TESTS(inst) \ |
| ZTEST(ina237_##inst, test_shunt_cal) { test_shunt_cal(&fixtures[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_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) |