1 /*
2 * Copyright (c) 2023 The ChromiumOS Authors
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/drivers/adc.h>
8 #include <zephyr/drivers/adc/adc_emul.h>
9 #include <zephyr/drivers/adc/voltage_divider.h>
10 #include <zephyr/drivers/adc/current_sense_shunt.h>
11 #include <zephyr/drivers/adc/current_sense_amplifier.h>
12 #include <zephyr/kernel.h>
13 #include <zephyr/ztest.h>
14
15 /* Raw to millivolt conversion doesn't handle rounding */
16 #define MV_OUTPUT_EPS 10
17
18 #define ADC_TEST_NODE_0 DT_NODELABEL(sensor0)
19 #define ADC_TEST_NODE_1 DT_NODELABEL(sensor1)
20 #define ADC_TEST_NODE_2 DT_NODELABEL(sensor2)
21 #define ADC_TEST_NODE_3 DT_NODELABEL(sensor3)
22
23 /**
24 * @brief Get ADC emulated device
25 *
26 * @return pointer to ADC device
27 */
get_adc_device(void)28 const struct device *get_adc_device(void)
29 {
30 const struct device *const adc_dev = DEVICE_DT_GET(DT_NODELABEL(adc0));
31
32 zassert_true(device_is_ready(adc_dev), "ADC device is not ready");
33
34 return adc_dev;
35 }
36
init_adc(const struct adc_dt_spec * spec,int input_mv)37 static int init_adc(const struct adc_dt_spec *spec, int input_mv)
38 {
39 int ret;
40
41 zassert_true(adc_is_ready_dt(spec), "ADC device is not ready");
42
43 ret = adc_channel_setup_dt(spec);
44 zassert_equal(ret, 0, "Setting up of the first channel failed with code %d", ret);
45
46 /* ADC emulator-specific setup */
47 ret = adc_emul_const_value_set(spec->dev, spec->channel_id, input_mv);
48 zassert_ok(ret, "adc_emul_const_value_set() failed with code %d", ret);
49
50 return ret;
51 }
52
53 /*
54 * test_adc_voltage_divider
55 */
test_task_voltage_divider(void)56 static int test_task_voltage_divider(void)
57 {
58 int ret;
59 int32_t calculated_voltage = 0;
60 int32_t calculated_microvolts;
61 int32_t input_mv = 1000;
62 const struct voltage_divider_dt_spec adc_node_0 =
63 VOLTAGE_DIVIDER_DT_SPEC_GET(ADC_TEST_NODE_0);
64
65 ret = init_adc(&adc_node_0.port, input_mv);
66 zassert_equal(ret, 0, "Setting up of the first channel failed with code %d", ret);
67
68 struct adc_sequence sequence = {
69 .buffer = &calculated_voltage,
70 .buffer_size = sizeof(calculated_voltage),
71 };
72 adc_sequence_init_dt(&adc_node_0.port, &sequence);
73
74 ret = adc_read_dt(&adc_node_0.port, &sequence);
75 zassert_equal(ret, 0, "adc_read() failed with code %d", ret);
76 calculated_microvolts = calculated_voltage;
77
78 ret = adc_raw_to_millivolts_dt(&adc_node_0.port, &calculated_voltage);
79 zassert_equal(ret, 0, "adc_raw_to_millivolts_dt() failed with code %d", ret);
80
81 ret = adc_raw_to_microvolts_dt(&adc_node_0.port, &calculated_microvolts);
82 zassert_equal(ret, 0, "adc_raw_to_microvolts_dt() failed with code %d", ret);
83 zassert_equal(calculated_microvolts / 1000, calculated_voltage);
84
85 ret = voltage_divider_scale_dt(&adc_node_0, &calculated_voltage);
86 zassert_equal(ret, 0, "divider_scale_voltage_dt() failed with code %d", ret);
87
88 zassert_within(calculated_voltage, input_mv * 2, MV_OUTPUT_EPS,
89 "%u != %u should have set value", calculated_voltage, input_mv * 2);
90
91 return TC_PASS;
92 }
93
ZTEST_USER(adc_rescale,test_adc_voltage_divider)94 ZTEST_USER(adc_rescale, test_adc_voltage_divider)
95 {
96 zassert_true(test_task_voltage_divider() == TC_PASS);
97 }
98
99 /*
100 * test_adc_current_sense_shunt
101 */
test_task_current_sense_shunt(void)102 static int test_task_current_sense_shunt(void)
103 {
104 int ret;
105 int32_t calculated_current = 0;
106 int32_t calculated_microvolts;
107 int32_t input_mv = 3000;
108 const struct current_sense_shunt_dt_spec adc_node_1 =
109 CURRENT_SENSE_SHUNT_DT_SPEC_GET(ADC_TEST_NODE_1);
110
111 ret = init_adc(&adc_node_1.port, input_mv);
112 zassert_equal(ret, 0, "Setting up of the second channel failed with code %d", ret);
113
114 struct adc_sequence sequence = {
115 .buffer = &calculated_current,
116 .buffer_size = sizeof(calculated_current),
117 };
118 adc_sequence_init_dt(&adc_node_1.port, &sequence);
119
120 ret = adc_read_dt(&adc_node_1.port, &sequence);
121 zassert_equal(ret, 0, "adc_read() failed with code %d", ret);
122 calculated_microvolts = calculated_current;
123
124 ret = adc_raw_to_millivolts_dt(&adc_node_1.port, &calculated_current);
125 zassert_equal(ret, 0, "adc_raw_to_millivolts_dt() failed with code %d", ret);
126
127 ret = adc_raw_to_microvolts_dt(&adc_node_1.port, &calculated_microvolts);
128 zassert_equal(ret, 0, "adc_raw_to_microvolts_dt() failed with code %d", ret);
129 zassert_equal(calculated_microvolts / 1000, calculated_current);
130
131 current_sense_shunt_scale_dt(&adc_node_1, &calculated_current);
132
133 zassert_within(calculated_current, input_mv * 2, MV_OUTPUT_EPS,
134 "%u != %u should have set value", calculated_current,
135 input_mv * 2);
136
137 return TC_PASS;
138 }
139
ZTEST_USER(adc_rescale,test_adc_current_sense_shunt)140 ZTEST_USER(adc_rescale, test_adc_current_sense_shunt)
141 {
142 zassert_true(test_task_current_sense_shunt() == TC_PASS);
143 }
144
145 /*
146 * test_adc_current_sense_amplifier
147 */
test_task_current_sense_amplifier(void)148 static int test_task_current_sense_amplifier(void)
149 {
150 int ret;
151 int32_t calculated_current = 0;
152 int32_t calculated_microvolts;
153 int32_t input_mv = 3000;
154 const struct current_sense_amplifier_dt_spec adc_node_2 =
155 CURRENT_SENSE_AMPLIFIER_DT_SPEC_GET(ADC_TEST_NODE_2);
156
157 ret = init_adc(&adc_node_2.port, input_mv);
158 zassert_equal(ret, 0, "Setting up of the third channel failed with code %d", ret);
159
160 struct adc_sequence sequence = {
161 .buffer = &calculated_current,
162 .buffer_size = sizeof(calculated_current),
163 };
164 adc_sequence_init_dt(&adc_node_2.port, &sequence);
165
166 ret = adc_read_dt(&adc_node_2.port, &sequence);
167 zassert_equal(ret, 0, "adc_read() failed with code %d", ret);
168 calculated_microvolts = calculated_current;
169
170 ret = adc_raw_to_millivolts_dt(&adc_node_2.port, &calculated_current);
171 zassert_equal(ret, 0, "adc_raw_to_millivolts_dt() failed with code %d", ret);
172
173 ret = adc_raw_to_microvolts_dt(&adc_node_2.port, &calculated_microvolts);
174 zassert_equal(ret, 0, "adc_raw_to_microvolts_dt() failed with code %d", ret);
175 zassert_equal(calculated_microvolts / 1000, calculated_current);
176
177 current_sense_amplifier_scale_dt(&adc_node_2, &calculated_current);
178
179 zassert_within(calculated_current, input_mv * 2, MV_OUTPUT_EPS,
180 "%u != %u should have set value", calculated_current,
181 input_mv * 2);
182
183 return TC_PASS;
184 }
185
ZTEST_USER(adc_rescale,test_adc_current_sense_amplifier)186 ZTEST_USER(adc_rescale, test_adc_current_sense_amplifier)
187 {
188 zassert_true(test_task_current_sense_amplifier() == TC_PASS);
189 }
190
ZTEST(adc_rescale,test_adc_current_sense_amplifier_with_offset)191 ZTEST(adc_rescale, test_adc_current_sense_amplifier_with_offset)
192 {
193 int32_t v_to_i;
194 const struct current_sense_amplifier_dt_spec amplifier_spec =
195 CURRENT_SENSE_AMPLIFIER_DT_SPEC_GET(ADC_TEST_NODE_3);
196
197 /**
198 * test a voltage that corresponds to 0 mA
199 */
200 v_to_i = amplifier_spec.zero_current_voltage_mv;
201 current_sense_amplifier_scale_dt(&lifier_spec, &v_to_i);
202 zassert_equal(v_to_i, 0);
203
204 /**
205 * test a voltage that corresponds to 200 mA
206 */
207 v_to_i = (200 * amplifier_spec.sense_gain_mult / amplifier_spec.sense_gain_div) / 1000;
208 v_to_i = v_to_i + amplifier_spec.zero_current_voltage_mv;
209 current_sense_amplifier_scale_dt(&lifier_spec, &v_to_i);
210 zassert_equal(v_to_i, 200);
211
212 /**
213 * test a voltage that corresponds to -1100 mA
214 */
215 v_to_i = (-1100 * amplifier_spec.sense_gain_mult / amplifier_spec.sense_gain_div) / 1000;
216 v_to_i = v_to_i + amplifier_spec.zero_current_voltage_mv;
217 current_sense_amplifier_scale_dt(&lifier_spec, &v_to_i);
218 zassert_equal(v_to_i, -1100);
219 }
220
adc_rescale_setup(void)221 void *adc_rescale_setup(void)
222 {
223 k_object_access_grant(get_adc_device(), k_current_get());
224
225 return NULL;
226 }
227
228 ZTEST_SUITE(adc_rescale, NULL, adc_rescale_setup, NULL, NULL, NULL);
229