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
22 /**
23 * @brief Get ADC emulated device
24 *
25 * @return pointer to ADC device
26 */
get_adc_device(void)27 const struct device *get_adc_device(void)
28 {
29 const struct device *const adc_dev = DEVICE_DT_GET(DT_NODELABEL(adc0));
30
31 zassert_true(device_is_ready(adc_dev), "ADC device is not ready");
32
33 return adc_dev;
34 }
35
init_adc(const struct adc_dt_spec * spec,int input_mv)36 static int init_adc(const struct adc_dt_spec *spec, int input_mv)
37 {
38 int ret;
39
40 zassert_true(adc_is_ready_dt(spec), "ADC device is not ready");
41
42 ret = adc_channel_setup_dt(spec);
43 zassert_equal(ret, 0, "Setting up of the first channel failed with code %d", ret);
44
45 /* ADC emulator-specific setup */
46 ret = adc_emul_const_value_set(spec->dev, spec->channel_id, input_mv);
47 zassert_ok(ret, "adc_emul_const_value_set() failed with code %d", ret);
48
49 return ret;
50 }
51
52 /*
53 * test_adc_voltage_divider
54 */
test_task_voltage_divider(void)55 static int test_task_voltage_divider(void)
56 {
57 int ret;
58 int32_t calculated_voltage = 0;
59 int32_t input_mv = 1000;
60 const struct voltage_divider_dt_spec adc_node_0 =
61 VOLTAGE_DIVIDER_DT_SPEC_GET(ADC_TEST_NODE_0);
62
63 ret = init_adc(&adc_node_0.port, input_mv);
64 zassert_equal(ret, 0, "Setting up of the first channel failed with code %d", ret);
65
66 struct adc_sequence sequence = {
67 .buffer = &calculated_voltage,
68 .buffer_size = sizeof(calculated_voltage),
69 };
70 adc_sequence_init_dt(&adc_node_0.port, &sequence);
71
72 ret = adc_read_dt(&adc_node_0.port, &sequence);
73 zassert_equal(ret, 0, "adc_read() failed with code %d", ret);
74
75 ret = adc_raw_to_millivolts_dt(&adc_node_0.port, &calculated_voltage);
76 zassert_equal(ret, 0, "adc_raw_to_millivolts_dt() failed with code %d", ret);
77
78 ret = voltage_divider_scale_dt(&adc_node_0, &calculated_voltage);
79 zassert_equal(ret, 0, "divider_scale_voltage_dt() failed with code %d", ret);
80
81 zassert_within(calculated_voltage, input_mv * 2, MV_OUTPUT_EPS,
82 "%u != %u should have set value", calculated_voltage, input_mv * 2);
83
84 return TC_PASS;
85 }
86
ZTEST_USER(adc_rescale,test_adc_voltage_divider)87 ZTEST_USER(adc_rescale, test_adc_voltage_divider)
88 {
89 zassert_true(test_task_voltage_divider() == TC_PASS);
90 }
91
92 /*
93 * test_adc_current_sense_shunt
94 */
test_task_current_sense_shunt(void)95 static int test_task_current_sense_shunt(void)
96 {
97 int ret;
98 int32_t calculated_current = 0;
99 int32_t input_mv = 3000;
100 const struct current_sense_shunt_dt_spec adc_node_1 =
101 CURRENT_SENSE_SHUNT_DT_SPEC_GET(ADC_TEST_NODE_1);
102
103 ret = init_adc(&adc_node_1.port, input_mv);
104 zassert_equal(ret, 0, "Setting up of the second channel failed with code %d", ret);
105
106 struct adc_sequence sequence = {
107 .buffer = &calculated_current,
108 .buffer_size = sizeof(calculated_current),
109 };
110 adc_sequence_init_dt(&adc_node_1.port, &sequence);
111
112 ret = adc_read_dt(&adc_node_1.port, &sequence);
113 zassert_equal(ret, 0, "adc_read() failed with code %d", ret);
114
115 ret = adc_raw_to_millivolts_dt(&adc_node_1.port, &calculated_current);
116 zassert_equal(ret, 0, "adc_raw_to_millivolts_dt() failed with code %d", ret);
117
118 current_sense_shunt_scale_dt(&adc_node_1, &calculated_current);
119
120 zassert_within(calculated_current, input_mv * 2, MV_OUTPUT_EPS,
121 "%u != %u should have set value", calculated_current,
122 input_mv * 2);
123
124 return TC_PASS;
125 }
126
ZTEST_USER(adc_rescale,test_adc_current_sense_shunt)127 ZTEST_USER(adc_rescale, test_adc_current_sense_shunt)
128 {
129 zassert_true(test_task_current_sense_shunt() == TC_PASS);
130 }
131
132 /*
133 * test_adc_current_sense_amplifier
134 */
test_task_current_sense_amplifier(void)135 static int test_task_current_sense_amplifier(void)
136 {
137 int ret;
138 int32_t calculated_current = 0;
139 int32_t input_mv = 3000;
140 const struct current_sense_amplifier_dt_spec adc_node_2 =
141 CURRENT_SENSE_AMPLIFIER_DT_SPEC_GET(ADC_TEST_NODE_2);
142
143 ret = init_adc(&adc_node_2.port, input_mv);
144 zassert_equal(ret, 0, "Setting up of the third channel failed with code %d", ret);
145
146 struct adc_sequence sequence = {
147 .buffer = &calculated_current,
148 .buffer_size = sizeof(calculated_current),
149 };
150 adc_sequence_init_dt(&adc_node_2.port, &sequence);
151
152 ret = adc_read_dt(&adc_node_2.port, &sequence);
153 zassert_equal(ret, 0, "adc_read() failed with code %d", ret);
154
155 ret = adc_raw_to_millivolts_dt(&adc_node_2.port, &calculated_current);
156 zassert_equal(ret, 0, "adc_raw_to_millivolts_dt() failed with code %d", ret);
157
158 current_sense_amplifier_scale_dt(&adc_node_2, &calculated_current);
159
160 zassert_within(calculated_current, input_mv * 2, MV_OUTPUT_EPS,
161 "%u != %u should have set value", calculated_current,
162 input_mv * 2);
163
164 return TC_PASS;
165 }
166
ZTEST_USER(adc_rescale,test_adc_current_sense_amplifier)167 ZTEST_USER(adc_rescale, test_adc_current_sense_amplifier)
168 {
169 zassert_true(test_task_current_sense_amplifier() == TC_PASS);
170 }
171
adc_rescale_setup(void)172 void *adc_rescale_setup(void)
173 {
174 k_object_access_grant(get_adc_device(), k_current_get());
175
176 return NULL;
177 }
178
179 ZTEST_SUITE(adc_rescale, NULL, adc_rescale_setup, NULL, NULL, NULL);
180