blob: 9ddda5db71ceba98fd3ebb773001c4deb8376f4d [file] [log] [blame]
/*
* 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/ina230.h>
#include <zephyr/ztest.h>
#include <ina230_emul.h>
#include <ina230.h>
struct ina230_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(ina230_0, test_default_config)
{
const struct ina230_config *config;
const struct device *dev = DEVICE_DT_GET(DT_NODELABEL(ina230_default_test));
zassert_not_null(dev);
config = dev->config;
zassert_not_null(config);
/* confirm default DT configuration */
uint16_t expected = 0x0127;
zexpect_equal(expected, config->config, "0x%x != config (0x%x)",
expected, config->config);
}
static void test_datasheet_example(struct ina230_fixture *fixture)
{
struct sensor_value sensor_val;
double actual;
/* only run test for datasheet example of 1mA current LSB and 2 mOhm shunt */
if (fixture->current_lsb_uA != 1000 || fixture->rshunt_uOhms != 2000) {
ztest_test_skip();
}
ina230_mock_set_register(fixture->mock->data, INA230_REG_BUS_VOLT, 9584);
ina230_mock_set_register(fixture->mock->data, INA230_REG_CURRENT, 10000);
ina230_mock_set_register(fixture->mock->data, INA230_REG_POWER, 4792);
zassert_ok(sensor_sample_fetch(fixture->dev));
zassert_ok(sensor_channel_get(fixture->dev, SENSOR_CHAN_VOLTAGE, &sensor_val));
actual = sensor_value_to_double(&sensor_val);
zexpect_within(11.98, actual, 1.25e-3, "Expected 11.98 V, got %.6f V", actual);
zassert_ok(sensor_channel_get(fixture->dev, SENSOR_CHAN_CURRENT, &sensor_val));
actual = sensor_value_to_double(&sensor_val);
zexpect_within(10.0, actual, 1e-3, "Expected 10 A, got %.6f V", actual);
zassert_ok(sensor_channel_get(fixture->dev, SENSOR_CHAN_POWER, &sensor_val));
actual = sensor_value_to_double(&sensor_val);
zexpect_within(119.82, actual, 25e-3, "Expected 119.82 W, got %.6f W", actual);
}
/**
* @brief Verify bus voltages for all ina230 nodes in DT
*
* @param fixture
*/
static void test_shunt_cal(struct ina230_fixture *fixture)
{
/* Confirm SHUNT_CAL register which is 5120e-6 / Current_LSB * Rshunt */
double shunt_cal = 5120e-6 / (fixture->current_lsb_uA * 1e-6 *
fixture->rshunt_uOhms * 1e-6);
uint32_t shunt_register_actual;
uint16_t shunt_register_expected = (uint16_t)shunt_cal;
zassert_ok(ina230_mock_get_register(fixture->mock->data, INA230_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 ina230_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 */
ina230_mock_set_register(fixture->mock->data, INA230_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 ina230_fixture *fixture)
{
zassert_not_null(fixture->mock);
/* 16-bit signed value for voltage register (but always positive) 1.25 mV/bit */
const int16_t voltage_reg_vectors[] = {
32767,
28800, /* 36V maximum voltage */
1000,
100,
1,
0,
};
for (int idx = 0; idx < ARRAY_SIZE(voltage_reg_vectors); idx++) {
struct sensor_value sensor_val;
ina230_mock_set_register(fixture->mock->data, INA230_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] * 1.25e-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 ina230_fixture *fixture)
{
/* 16-bit unsigned value for power register */
const uint16_t power_reg_vectors[] = {
65535,
32767,
10000,
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 power_register * 25 * current_lsb */
double power_expected_W = power_register * 25 * fixture->current_lsb_uA * 1e-6;
/* set current reading */
ina230_mock_set_register(fixture->mock->data, INA230_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 W, got %.6f W for %d",
power_expected_W, power_actual_W, power_register);
}
}
/* Create a test fixture for each enabled ina230 device node */
#define DT_DRV_COMPAT ti_ina230
#define INA230_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 ina230_fixture fixtures[] = {
DT_INST_FOREACH_STATUS_OKAY(INA230_FIXTURE_ENTRY)
};
/* Create a test suite for each enabled ina230 device node */
#define INA230_TESTS(inst) \
ZTEST(ina230_##inst, test_datasheet_example) { test_datasheet_example(&fixtures[inst]); } \
ZTEST(ina230_##inst, test_shunt_cal) { test_shunt_cal(&fixtures[inst]); } \
ZTEST(ina230_##inst, test_current) { test_current(&fixtures[inst]); } \
ZTEST(ina230_##inst, test_bus_voltage) { test_bus_voltage(&fixtures[inst]); } \
ZTEST(ina230_##inst, test_power) { test_power(&fixtures[inst]); } \
ZTEST_SUITE(ina230_##inst, NULL, NULL, NULL, NULL, NULL);
DT_INST_FOREACH_STATUS_OKAY(INA230_TESTS)