1 /*
2 * Copyright (c) 2023 Google LLC
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/gpio.h>
10 #include <zephyr/drivers/gpio/gpio_emul.h>
11 #include <zephyr/drivers/sensor.h>
12 #include <zephyr/fff.h>
13 #include <zephyr/ztest.h>
14
15 #include "icm42688_emul.h"
16 #include "icm42688_reg.h"
17
18 #define NODE DT_NODELABEL(icm42688)
19
20 DEFINE_FFF_GLOBALS;
21
22 struct icm42688_fixture {
23 const struct device *dev;
24 const struct emul *target;
25 };
26
icm42688_setup(void)27 static void *icm42688_setup(void)
28 {
29 static struct icm42688_fixture fixture = {
30 .dev = DEVICE_DT_GET(DT_NODELABEL(icm42688)),
31 .target = EMUL_DT_GET(DT_NODELABEL(icm42688)),
32 };
33
34 zassert_not_null(fixture.dev);
35 zassert_not_null(fixture.target);
36 return &fixture;
37 }
38
39 ZTEST_SUITE(icm42688, NULL, icm42688_setup, NULL, NULL, NULL);
40
ZTEST_F(icm42688,test_fetch_fail_no_ready_data)41 ZTEST_F(icm42688, test_fetch_fail_no_ready_data)
42 {
43 uint8_t status = 0;
44
45 icm42688_emul_set_reg(fixture->target, REG_INT_STATUS, &status, 1);
46 zassert_equal(-EBUSY, sensor_sample_fetch(fixture->dev));
47 }
48
test_fetch_temp_mc(const struct icm42688_fixture * fixture,int16_t temperature_mc)49 static void test_fetch_temp_mc(const struct icm42688_fixture *fixture, int16_t temperature_mc)
50 {
51 struct sensor_value value;
52 int64_t expected_uc;
53 int64_t actual_uc;
54 int16_t temperature_reg;
55 uint8_t buffer[2];
56
57 /* Set the INT_STATUS register to show we have data */
58 buffer[0] = BIT_INT_STATUS_DATA_RDY;
59 icm42688_emul_set_reg(fixture->target, REG_INT_STATUS, buffer, 1);
60
61 /*
62 * Set the temperature data to 22.5C via:
63 * reg_val / 132.48 + 25
64 */
65 temperature_reg = ((temperature_mc - 25000) * 13248) / 100000;
66 buffer[0] = (temperature_reg >> 8) & GENMASK(7, 0);
67 buffer[1] = temperature_reg & GENMASK(7, 0);
68 icm42688_emul_set_reg(fixture->target, REG_TEMP_DATA1, buffer, 2);
69
70 /* Fetch the data */
71 zassert_ok(sensor_sample_fetch(fixture->dev));
72 zassert_ok(sensor_channel_get(fixture->dev, SENSOR_CHAN_DIE_TEMP, &value));
73
74 /* Assert data is within 5 milli-C of the tested temperature */
75 expected_uc = temperature_mc * INT64_C(1000);
76 actual_uc = sensor_value_to_micro(&value);
77 zassert_within(expected_uc, actual_uc, INT64_C(5000),
78 "Expected %" PRIi64 "uC, got %" PRIi64 "uC", expected_uc, actual_uc);
79 }
80
ZTEST_F(icm42688,test_fetch_temp)81 ZTEST_F(icm42688, test_fetch_temp)
82 {
83 /* Test 22.5C */
84 test_fetch_temp_mc(fixture, 22500);
85 /* Test -3.175C */
86 test_fetch_temp_mc(fixture, -3175);
87 }
88
test_fetch_accel_with_range(const struct icm42688_fixture * fixture,int16_t accel_range_g,const int16_t accel_percent[3])89 static void test_fetch_accel_with_range(const struct icm42688_fixture *fixture,
90 int16_t accel_range_g, const int16_t accel_percent[3])
91 {
92 struct sensor_value values[3];
93 int32_t expect_ug;
94 int32_t actual_ug;
95 uint8_t register_buffer[6];
96
97 /* Se the INT_STATUS register to show we have data */
98 register_buffer[0] = BIT_INT_STATUS_DATA_RDY;
99 icm42688_emul_set_reg(fixture->target, REG_INT_STATUS, register_buffer, 1);
100
101 /* Set accel range */
102 sensor_g_to_ms2(accel_range_g, &values[0]);
103 zassert_ok(sensor_attr_set(fixture->dev, SENSOR_CHAN_ACCEL_XYZ, SENSOR_ATTR_FULL_SCALE,
104 &values[0]));
105
106 /* Set the accel data accel_percent * accel_range_g */
107 for (int i = 0; i < 3; ++i) {
108 register_buffer[i * 2] = (accel_percent[i] >> 8) & GENMASK(7, 0);
109 register_buffer[i * 2 + 1] = accel_percent[i] & GENMASK(7, 0);
110 }
111 icm42688_emul_set_reg(fixture->target, REG_ACCEL_DATA_X1, register_buffer, 6);
112
113 /* Fetch the data */
114 zassert_ok(sensor_sample_fetch(fixture->dev));
115 zassert_ok(sensor_channel_get(fixture->dev, SENSOR_CHAN_ACCEL_XYZ, values));
116
117 /* Assert the data is within 0.005g (0.05m/s2) */
118 actual_ug = sensor_ms2_to_ug(&values[0]);
119 expect_ug = (int32_t)(accel_percent[0] * INT64_C(1000000) * accel_range_g / INT16_MAX);
120 zassert_within(expect_ug, actual_ug, INT32_C(5000),
121 "Expected %" PRIi32 " ug, got X=%" PRIi32 " ug", expect_ug, actual_ug);
122
123 actual_ug = sensor_ms2_to_ug(&values[1]);
124 expect_ug = (int32_t)(accel_percent[1] * INT64_C(1000000) * accel_range_g / INT16_MAX);
125 zassert_within(expect_ug, actual_ug, INT32_C(5000),
126 "Expected %" PRIi32 " ug, got X=%" PRIi32 " ug", expect_ug, actual_ug);
127
128 actual_ug = sensor_ms2_to_ug(&values[2]);
129 expect_ug = (int32_t)(accel_percent[2] * INT64_C(1000000) * accel_range_g / INT16_MAX);
130 zassert_within(expect_ug, actual_ug, INT32_C(5000),
131 "Expected %" PRIi32 " ug, got X=%" PRIi32 " ug", expect_ug, actual_ug);
132 }
133
ZTEST_F(icm42688,test_fetch_accel)134 ZTEST_F(icm42688, test_fetch_accel)
135 {
136 /* Use (0.25, -0.33.., 0.91) * range for testing accel values */
137 const int16_t accel_percent[3] = {
138 INT16_MAX / INT16_C(4),
139 INT16_MIN / INT16_C(3),
140 (int16_t)((INT16_MAX * INT32_C(91)) / INT32_C(100)),
141 };
142
143 test_fetch_accel_with_range(fixture, 2, accel_percent);
144 test_fetch_accel_with_range(fixture, 4, accel_percent);
145 test_fetch_accel_with_range(fixture, 8, accel_percent);
146 test_fetch_accel_with_range(fixture, 16, accel_percent);
147 }
148
test_fetch_gyro_with_range(const struct icm42688_fixture * fixture,int32_t scale_mdps,const int16_t gyro_percent[3])149 static void test_fetch_gyro_with_range(const struct icm42688_fixture *fixture, int32_t scale_mdps,
150 const int16_t gyro_percent[3])
151 {
152 /* Set the epsilon to 0.075% of the scale */
153 const int32_t epsilon_10udps = scale_mdps * 75 / 1000;
154 struct sensor_value values[3];
155 int32_t expect_10udps;
156 int32_t actual_10udps;
157 uint8_t register_buffer[6];
158
159 /* Se the INT_STATUS register to show we have data */
160 register_buffer[0] = BIT_INT_STATUS_DATA_RDY;
161 icm42688_emul_set_reg(fixture->target, REG_INT_STATUS, register_buffer, 1);
162
163 /* Set gyro range */
164 sensor_degrees_to_rad((scale_mdps / 1000) + (scale_mdps % 1000 == 0 ? 0 : 1), &values[0]);
165 zassert_ok(sensor_attr_set(fixture->dev, SENSOR_CHAN_GYRO_XYZ, SENSOR_ATTR_FULL_SCALE,
166 &values[0]));
167
168 /* Set the gyro data to gyro_percent */
169 for (int i = 0; i < 3; ++i) {
170 register_buffer[i * 2] = (gyro_percent[i] >> 8) & GENMASK(7, 0);
171 register_buffer[i * 2 + 1] = gyro_percent[i] & GENMASK(7, 0);
172 }
173 icm42688_emul_set_reg(fixture->target, REG_GYRO_DATA_X1, register_buffer, 6);
174
175 /* Fetch the data */
176 zassert_ok(sensor_sample_fetch(fixture->dev));
177 zassert_ok(sensor_channel_get(fixture->dev, SENSOR_CHAN_GYRO_XYZ, values));
178
179 /* Assert the data is within 0.5 d/s (0.001 rad/s) */
180 actual_10udps = sensor_rad_to_10udegrees(&values[0]);
181 expect_10udps = (int32_t)(gyro_percent[0] * INT64_C(100) * scale_mdps / INT16_MAX);
182 zassert_within(expect_10udps, actual_10udps, epsilon_10udps,
183 "[scale=%" PRIi32 "md/s] Expected %" PRIi32 " 10ud/s, got %" PRIi32
184 " 10ud/s",
185 scale_mdps, expect_10udps, actual_10udps);
186
187 actual_10udps = sensor_rad_to_10udegrees(&values[1]);
188 expect_10udps = (int32_t)(gyro_percent[1] * INT64_C(100) * scale_mdps / INT16_MAX);
189 zassert_within(expect_10udps, actual_10udps, epsilon_10udps,
190 "[scale=%" PRIi32 "md/s] Expected %" PRIi32 " 10ud/s, got %" PRIi32
191 " 10ud/s, ",
192 scale_mdps, expect_10udps, actual_10udps);
193
194 actual_10udps = sensor_rad_to_10udegrees(&values[2]);
195 expect_10udps = (int32_t)(gyro_percent[2] * INT64_C(100) * scale_mdps / INT16_MAX);
196 zassert_within(expect_10udps, actual_10udps, epsilon_10udps,
197 "[scale=%" PRIi32 "md/s] Expected %" PRIi32 " 10ud/s, got %" PRIi32
198 " 10ud/s",
199 scale_mdps, expect_10udps, actual_10udps);
200 }
201
ZTEST_F(icm42688,test_fetch_gyro)202 ZTEST_F(icm42688, test_fetch_gyro)
203 {
204 /* Use (0.15, 0.68, -0.22) * range for testing gyro values */
205 const int16_t gyro_percent[3] = {
206 (int16_t)((INT16_MAX * INT32_C(15)) / INT32_C(100)),
207 (int16_t)((INT16_MAX * INT32_C(68)) / INT32_C(100)),
208 (int16_t)((INT16_MAX * INT32_C(-22)) / INT32_C(100)),
209 };
210
211 test_fetch_gyro_with_range(fixture, 2000000, gyro_percent);
212 test_fetch_gyro_with_range(fixture, 1000000, gyro_percent);
213 test_fetch_gyro_with_range(fixture, 500000, gyro_percent);
214 test_fetch_gyro_with_range(fixture, 250000, gyro_percent);
215 test_fetch_gyro_with_range(fixture, 125000, gyro_percent);
216 test_fetch_gyro_with_range(fixture, 62500, gyro_percent);
217 test_fetch_gyro_with_range(fixture, 31250, gyro_percent);
218 test_fetch_gyro_with_range(fixture, 15625, gyro_percent);
219 }
220
221 FAKE_VOID_FUNC(test_interrupt_trigger_handler, const struct device*, const struct sensor_trigger*);
222
ZTEST_F(icm42688,test_interrupt)223 ZTEST_F(icm42688, test_interrupt)
224 {
225 const struct gpio_dt_spec spec = GPIO_DT_SPEC_GET(NODE, int_gpios);
226 const struct sensor_trigger trigger = {
227 .type = SENSOR_TRIG_DATA_READY,
228 .chan = SENSOR_CHAN_ALL,
229 };
230
231 RESET_FAKE(test_interrupt_trigger_handler);
232 sensor_trigger_set(fixture->dev, &trigger, test_interrupt_trigger_handler);
233
234 /* Toggle the GPIO */
235 gpio_emul_input_set(spec.port, spec.pin, 0);
236 k_msleep(5);
237 gpio_emul_input_set(spec.port, spec.pin, 1);
238 k_msleep(5);
239
240 /* Verify the handler was called */
241 zassert_equal(test_interrupt_trigger_handler_fake.call_count, 1);
242 }
243