1 /*
2 * Copyright (c) 2023 North River Systems Ltd
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6 #include <zephyr/device.h>
7 #include <zephyr/devicetree.h>
8 #include <zephyr/drivers/emul.h>
9 #include <zephyr/drivers/i2c_emul.h>
10 #include <zephyr/drivers/sensor.h>
11 #include <zephyr/dt-bindings/sensor/ina230.h>
12 #include <zephyr/ztest.h>
13
14 #include <ina230_emul.h>
15 #include <ina230.h>
16
17 enum ina23x_ids {
18 INA230,
19 INA236
20 };
21
22 struct ina230_fixture {
23 const struct device *dev;
24 const struct emul *mock;
25 const uint16_t current_lsb_uA;
26 const uint16_t rshunt_uOhms;
27 const uint16_t config;
28 const enum ina23x_ids dev_type;
29 };
30
31 /**
32 * @brief Verify devicetree default configuration is correct.
33 */
ZTEST(ina230_0,test_default_config)34 ZTEST(ina230_0, test_default_config)
35 {
36 const struct ina230_config *config;
37 const struct device *dev = DEVICE_DT_GET(DT_NODELABEL(ina230_default_test));
38
39 zassert_not_null(dev);
40 config = dev->config;
41 zassert_not_null(config);
42
43 /* confirm default DT configuration */
44 uint16_t expected = 0x0127;
45
46 zexpect_equal(expected, config->config, "0x%x != config (0x%x)",
47 expected, config->config);
48 }
49
test_datasheet_example(struct ina230_fixture * fixture)50 static void test_datasheet_example(struct ina230_fixture *fixture)
51 {
52 struct sensor_value sensor_val;
53 uint16_t raw_voltage, raw_current, raw_power;
54 double actual;
55
56 /* only run test for datasheet example of 1mA current LSB and 2 mOhm shunt */
57 if (fixture->current_lsb_uA != 1000 || fixture->rshunt_uOhms != 2000) {
58 ztest_test_skip();
59 }
60
61 if (fixture->dev_type == INA230) {
62 raw_voltage = 9584;
63 raw_current = 10000;
64 raw_power = 4792;
65 } else {
66 raw_voltage = 7487;
67 raw_current = 10000;
68 raw_power = 3744;
69 }
70
71 ina230_mock_set_register(fixture->mock->data, INA230_REG_BUS_VOLT, raw_voltage);
72 ina230_mock_set_register(fixture->mock->data, INA230_REG_CURRENT, raw_current);
73 ina230_mock_set_register(fixture->mock->data, INA230_REG_POWER, raw_power);
74 zassert_ok(sensor_sample_fetch(fixture->dev));
75
76 zassert_ok(sensor_channel_get(fixture->dev, SENSOR_CHAN_VOLTAGE, &sensor_val));
77 actual = sensor_value_to_double(&sensor_val);
78 zexpect_within(11.98, actual, 1.25e-3, "Expected 11.98 V, got %.6f V", actual);
79
80 zassert_ok(sensor_channel_get(fixture->dev, SENSOR_CHAN_CURRENT, &sensor_val));
81 actual = sensor_value_to_double(&sensor_val);
82 zexpect_within(10.0, actual, 1e-3, "Expected 10 A, got %.6f V", actual);
83
84 zassert_ok(sensor_channel_get(fixture->dev, SENSOR_CHAN_POWER, &sensor_val));
85 actual = sensor_value_to_double(&sensor_val);
86 zexpect_within(119.82, actual, 25e-3, "Expected 119.82 W, got %.6f W", actual);
87 }
88
89 /**
90 * @brief Verify bus voltages for all ina230 nodes in DT
91 *
92 * @param fixture
93 */
test_shunt_cal(struct ina230_fixture * fixture)94 static void test_shunt_cal(struct ina230_fixture *fixture)
95 {
96 /* Confirm SHUNT_CAL register which is 5120e-6 / Current_LSB * Rshunt */
97 double shunt_cal = 5120e-6 / (fixture->current_lsb_uA * 1e-6 *
98 fixture->rshunt_uOhms * 1e-6);
99
100 uint32_t shunt_register_actual;
101 uint16_t shunt_register_expected = (uint16_t)shunt_cal;
102
103 zassert_ok(ina230_mock_get_register(fixture->mock->data, INA230_REG_CALIB,
104 &shunt_register_actual));
105 zexpect_within(shunt_register_expected, shunt_register_actual, 1,
106 "Expected %d, got %d", shunt_register_expected, shunt_register_actual);
107 }
108
test_current(struct ina230_fixture * fixture)109 static void test_current(struct ina230_fixture *fixture)
110 {
111 /* 16-bit signed value for current register */
112 const int16_t current_reg_vectors[] = {
113 32767,
114 1000,
115 100,
116 1,
117 0,
118 -1,
119 -100,
120 -1000,
121 -32768,
122 };
123
124 for (int idx = 0; idx < ARRAY_SIZE(current_reg_vectors); idx++) {
125 struct sensor_value sensor_val;
126 int16_t current_register = current_reg_vectors[idx];
127 double current_expected_A = fixture->current_lsb_uA * 1e-6 * current_register;
128
129 /* set current reading */
130 ina230_mock_set_register(fixture->mock->data, INA230_REG_CURRENT, current_register);
131
132 /* Verify sensor value is correct */
133 zassert_ok(sensor_sample_fetch(fixture->dev));
134 zassert_ok(sensor_channel_get(fixture->dev, SENSOR_CHAN_CURRENT, &sensor_val));
135 double current_actual_A = sensor_value_to_double(&sensor_val);
136
137 zexpect_within(current_expected_A, current_actual_A, fixture->current_lsb_uA*1e-6,
138 "Expected %.6f A, got %.6f A", current_expected_A, current_actual_A);
139 }
140 }
141
test_bus_voltage(struct ina230_fixture * fixture)142 static void test_bus_voltage(struct ina230_fixture *fixture)
143 {
144 zassert_not_null(fixture->mock);
145
146 /* 16-bit signed value for voltage register (but always positive) 1.25 mV/bit */
147 const int16_t voltage_reg_vectors[] = {
148 32767,
149 28800, /* 36V maximum voltage */
150 1000,
151 100,
152 1,
153 0,
154 };
155
156 double bitres = fixture->dev_type == INA236 ? 1.6e-3 : 1.25e-3;
157
158 for (int idx = 0; idx < ARRAY_SIZE(voltage_reg_vectors); idx++) {
159 struct sensor_value sensor_val;
160
161 ina230_mock_set_register(fixture->mock->data, INA230_REG_BUS_VOLT,
162 voltage_reg_vectors[idx]);
163
164 /* Verify sensor value is correct */
165 zassert_ok(sensor_sample_fetch(fixture->dev));
166 zassert_ok(sensor_channel_get(fixture->dev, SENSOR_CHAN_VOLTAGE, &sensor_val));
167
168 double voltage_actual_V = sensor_value_to_double(&sensor_val);
169 double voltage_expected_V = voltage_reg_vectors[idx] * bitres;
170
171 zexpect_within(voltage_expected_V, voltage_actual_V, 1e-6,
172 "Expected %.6f A, got %.6f A", voltage_expected_V, voltage_actual_V);
173 }
174 }
175
test_power(struct ina230_fixture * fixture)176 static void test_power(struct ina230_fixture *fixture)
177 {
178 /* 16-bit unsigned value for power register */
179 const uint16_t power_reg_vectors[] = {
180 65535,
181 32767,
182 10000,
183 1000,
184 100,
185 1,
186 0,
187 };
188
189 int scale = fixture->dev_type == INA236 ? 32 : 25;
190
191 for (int idx = 0; idx < ARRAY_SIZE(power_reg_vectors); idx++) {
192 struct sensor_value sensor_val;
193 uint32_t power_register = power_reg_vectors[idx];
194
195 /* power is power_register * SCALE * current_lsb */
196 double power_expected_W = power_register * scale * fixture->current_lsb_uA * 1e-6;
197
198 /* set current reading */
199 ina230_mock_set_register(fixture->mock->data, INA230_REG_POWER, power_register);
200
201 /* Verify sensor value is correct */
202 zassert_ok(sensor_sample_fetch(fixture->dev));
203 zassert_ok(sensor_channel_get(fixture->dev, SENSOR_CHAN_POWER, &sensor_val));
204 double power_actual_W = sensor_value_to_double(&sensor_val);
205
206 zexpect_within(power_expected_W, power_actual_W, 1e-6,
207 "Expected %.6f W, got %.6f W for %d", power_expected_W,
208 power_actual_W, power_register);
209 }
210 }
211
212 /* Create a test fixture for each enabled ina230 device node */
213 #define INA230_FIXTURE_ENTRY(inst, v) \
214 static struct ina230_fixture fixture_23##v##_##inst = { \
215 .dev = DEVICE_DT_INST_GET(inst), \
216 .mock = EMUL_DT_GET(DT_DRV_INST(inst)), \
217 .current_lsb_uA = DT_INST_PROP(inst, current_lsb_microamps), \
218 .rshunt_uOhms = DT_INST_PROP(inst, rshunt_micro_ohms), \
219 .config = DT_INST_PROP(inst, config), \
220 .dev_type = INA23##v, \
221 }
222
223 /* Create a test suite for each enabled ina230 device node */
224 #define INA230_TESTS(inst, v) \
225 INA230_FIXTURE_ENTRY(inst, v); \
226 ZTEST(ina23##v##_##inst, test_datasheet_example) \
227 { \
228 test_datasheet_example(&fixture_23##v##_##inst); \
229 } \
230 ZTEST(ina23##v##_##inst, test_shunt_cal) \
231 { \
232 test_shunt_cal(&fixture_23##v##_##inst); \
233 } \
234 ZTEST(ina23##v##_##inst, test_current) \
235 { \
236 test_current(&fixture_23##v##_##inst); \
237 } \
238 ZTEST(ina23##v##_##inst, test_bus_voltage) \
239 { \
240 test_bus_voltage(&fixture_23##v##_##inst); \
241 } \
242 ZTEST(ina23##v##_##inst, test_power) \
243 { \
244 test_power(&fixture_23##v##_##inst); \
245 } \
246 ZTEST_SUITE(ina23##v##_##inst, NULL, NULL, NULL, NULL, NULL);
247
248 #undef DT_DRV_COMPAT
249 #define DT_DRV_COMPAT ti_ina230
250 DT_INST_FOREACH_STATUS_OKAY_VARGS(INA230_TESTS, 0)
251
252 #undef DT_DRV_COMPAT
253 #define DT_DRV_COMPAT ti_ina236
254 DT_INST_FOREACH_STATUS_OKAY_VARGS(INA230_TESTS, 6)
255