1 /*
2 * Copyright (c) 2020 Libre Solar Technologies GmbH
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /*
8 * @addtogroup test_dac_loopback
9 * @{
10 * @defgroup t_dac_basic_loopback test_dac_loopback
11 * @brief TestPurpose: read back DAC driver output with ADC
12 * @}
13 */
14
15 #include <zephyr/drivers/dac.h>
16 #include <zephyr/drivers/adc.h>
17 #include <zephyr/kernel.h>
18 #include <zephyr/ztest.h>
19
20 /*
21 * We need to define an ADC channel to read back the output generated by the
22 * ADC. The two pins need to be connected with a jumper in order to pass the
23 * test in actual hardware.
24 *
25 * ADC and DAC need to use the same reference voltage, as the test sampling
26 * point is at half of the full scale voltage.
27 */
28
29 #if defined(CONFIG_BOARD_NUCLEO_L152RE) || \
30 defined(CONFIG_BOARD_STM32F3_DISCO) || \
31 defined(CONFIG_BOARD_STM32L562E_DK) || \
32 defined(CONFIG_BOARD_NUCLEO_L552ZE_Q) || \
33 defined(CONFIG_BOARD_NUCLEO_WL55JC) || \
34 defined(CONFIG_BOARD_RONOTH_LODEV)
35
36 /*
37 * DAC output on PA4 (Arduino A2 pin of Nucleo board)
38 * ADC input read from PA1 (Arduino A1 pin of Nucleo board)
39 */
40
41 #define DAC_DEVICE_NODE DT_NODELABEL(dac1)
42 #define DAC_CHANNEL_ID 1
43 #define DAC_RESOLUTION 12
44
45 #define ADC_DEVICE_NODE DT_NODELABEL(adc1)
46 #if defined(CONFIG_BOARD_STM32L562E_DK)
47 #define ADC_CHANNEL_ID 13
48 #else
49 #define ADC_CHANNEL_ID 1
50 #endif /* CONFIG_BOARD_STM32L562E_DK */
51 #define ADC_RESOLUTION 12
52 #define ADC_GAIN ADC_GAIN_1
53 #define ADC_REFERENCE ADC_REF_INTERNAL
54 /* The STM32L562E_DK does not accept ADC_ACQ_TIME_DEFAULT (=0) but the MAX one */
55 #define ADC_ACQUISITION_TIME ADC_ACQ_TIME_MAX
56
57
58 #elif defined(CONFIG_BOARD_NUCLEO_L073RZ) || \
59 defined(CONFIG_BOARD_NUCLEO_F207ZG) || \
60 defined(CONFIG_BOARD_NUCLEO_F429ZI) || \
61 defined(CONFIG_BOARD_NUCLEO_F746ZG) || \
62 defined(CONFIG_BOARD_NUCLEO_G071RB)
63 /*
64 * DAC output on PA4
65 * ADC input read from PA0
66 */
67
68 #define DAC_DEVICE_NODE DT_NODELABEL(dac1)
69 #define DAC_CHANNEL_ID 1
70 #define DAC_RESOLUTION 12
71
72 #define ADC_DEVICE_NODE DT_NODELABEL(adc1)
73 #define ADC_CHANNEL_ID 0
74 #define ADC_RESOLUTION 12
75 #define ADC_GAIN ADC_GAIN_1
76 #define ADC_REFERENCE ADC_REF_INTERNAL
77 /* The NUCLEO_G071RB does not accept ADC_ACQ_TIME_DEFAULT (=0) but the MAX one */
78 #define ADC_ACQUISITION_TIME ADC_ACQ_TIME_MAX
79
80 #elif defined(CONFIG_BOARD_TWR_KE18F)
81
82 /*
83 * DAC0 output is internally available on ADC0_SE23 when test output
84 * is enabled.
85 */
86
87 #define DAC_DEVICE_NODE DT_NODELABEL(dac0)
88 #define DAC_RESOLUTION 12
89 #define DAC_CHANNEL_ID 0
90
91 #define ADC_DEVICE_NODE DT_NODELABEL(adc0)
92 #define ADC_RESOLUTION 12
93 #define ADC_GAIN ADC_GAIN_1
94 #define ADC_REFERENCE ADC_REF_INTERNAL
95 #define ADC_ACQUISITION_TIME ADC_ACQ_TIME_DEFAULT
96 #define ADC_CHANNEL_ID 23
97
98 #elif defined(CONFIG_BOARD_FRDM_K64F)
99
100 /* DAC0 output is internally available on ADC0_SE23 */
101
102 #define DAC_DEVICE_NODE DT_NODELABEL(dac0)
103 #define DAC_RESOLUTION 12
104 #define DAC_CHANNEL_ID 0
105
106 #define ADC_DEVICE_NODE DT_NODELABEL(adc0)
107 #define ADC_RESOLUTION 12
108 #define ADC_GAIN ADC_GAIN_1
109 #define ADC_REFERENCE ADC_REF_INTERNAL
110 #define ADC_ACQUISITION_TIME ADC_ACQ_TIME_DEFAULT
111 #define ADC_CHANNEL_ID 23
112
113 #elif defined(CONFIG_BOARD_FRDM_K22F)
114
115 /* DAC0 output is internally available on ADC0_SE23 */
116
117 #define DAC_DEVICE_NODE DT_NODELABEL(dac0)
118 #define DAC_RESOLUTION 12
119 #define DAC_CHANNEL_ID 0
120
121 #define ADC_DEVICE_NODE DT_NODELABEL(adc0)
122 #define ADC_RESOLUTION 12
123 #define ADC_GAIN ADC_GAIN_1
124 #define ADC_REFERENCE ADC_REF_INTERNAL
125 #define ADC_ACQUISITION_TIME ADC_ACQ_TIME_DEFAULT
126 #define ADC_CHANNEL_ID 23
127
128 #elif defined(CONFIG_BOARD_LPCXPRESSO55S36)
129
130 /* DAC0 output is internally available on ADC0_SE4 */
131
132 #define DAC_DEVICE_NODE DT_NODELABEL(dac0)
133 #define DAC_RESOLUTION 12
134 #define DAC_CHANNEL_ID 0
135
136 #define ADC_DEVICE_NODE DT_NODELABEL(adc0)
137 #define ADC_RESOLUTION 12
138 #define ADC_GAIN ADC_GAIN_1
139 #define ADC_REFERENCE ADC_REF_EXTERNAL0
140 #define ADC_ACQUISITION_TIME ADC_ACQ_TIME_DEFAULT
141 #define ADC_CHANNEL_ID 0
142 #define ADC_1ST_CHANNEL_INPUT 4
143
144 #elif defined(CONFIG_BOARD_BL652_DVK) || \
145 defined(CONFIG_BOARD_BL653_DVK) || \
146 defined(CONFIG_BOARD_BL654_DVK) || \
147 defined(CONFIG_BOARD_BL5340_DVK)
148 #include <hal/nrf_saadc.h>
149 /* DAC output from MCP4725 pin 1
150 * On BL65x ADC_1 input is read from pin SIO_3
151 * On BL5340 ADC_1 input is read from pin SIO_5
152 * Note external DAC MCP4725 is not populated on BL652_DVK, BL653_DVK and
153 * BL654_DVK at factory
154 */
155
156 #define DAC_DEVICE_NODE DT_NODELABEL(dac0)
157 #define DAC_RESOLUTION 12
158 #define DAC_CHANNEL_ID 0
159
160 #define ADC_DEVICE_NODE DT_NODELABEL(adc)
161 #define ADC_RESOLUTION 12
162 #define ADC_GAIN ADC_GAIN_1_4
163 #define ADC_REFERENCE ADC_REF_VDD_1_4
164 #define ADC_ACQUISITION_TIME ADC_ACQ_TIME_DEFAULT
165 #define ADC_CHANNEL_ID 1
166 #define ADC_1ST_CHANNEL_INPUT NRF_SAADC_INPUT_AIN1
167
168 #else
169 #error "Unsupported board."
170 #endif
171
172 static const struct dac_channel_cfg dac_ch_cfg = {
173 .channel_id = DAC_CHANNEL_ID,
174 .resolution = DAC_RESOLUTION,
175 .buffered = true
176 };
177
178 static const struct adc_channel_cfg adc_ch_cfg = {
179 .gain = ADC_GAIN,
180 .reference = ADC_REFERENCE,
181 .acquisition_time = ADC_ACQUISITION_TIME,
182 .channel_id = ADC_CHANNEL_ID,
183
184 #if defined(CONFIG_BOARD_BL652_DVK) || \
185 defined(CONFIG_BOARD_BL653_DVK) || \
186 defined(CONFIG_BOARD_BL654_DVK) || \
187 defined(CONFIG_BOARD_BL5340_DVK) || \
188 defined(CONFIG_BOARD_LPCXPRESSO55S36)
189 .input_positive = ADC_1ST_CHANNEL_INPUT,
190 #endif
191 };
192
init_dac(void)193 static const struct device *init_dac(void)
194 {
195 int ret;
196 const struct device *const dac_dev = DEVICE_DT_GET(DAC_DEVICE_NODE);
197
198 zassert_true(device_is_ready(dac_dev), "DAC device is not ready");
199
200 ret = dac_channel_setup(dac_dev, &dac_ch_cfg);
201 zassert_ok(ret, "Setting up of the first channel failed with code %d", ret);
202
203 return dac_dev;
204 }
205
206 /* ADC necessary to read back the value from DAC */
init_adc(void)207 static const struct device *init_adc(void)
208 {
209 int ret;
210 const struct device *const adc_dev = DEVICE_DT_GET(ADC_DEVICE_NODE);
211
212 zassert_true(device_is_ready(adc_dev), "ADC device is not ready");
213
214 ret = adc_channel_setup(adc_dev, &adc_ch_cfg);
215 zassert_ok(ret, "Setting up of the ADC channel failed with code %d", ret);
216
217 return adc_dev;
218 }
219
220 /*
221 * test_dac_loopback
222 */
test_task_loopback(void)223 static int test_task_loopback(void)
224 {
225 int ret;
226
227 const struct device *dac_dev = init_dac();
228 const struct device *adc_dev = init_adc();
229
230 if (!dac_dev || !adc_dev) {
231 return TC_FAIL;
232 }
233
234 /* write a value of half the full scale resolution */
235 ret = dac_write_value(dac_dev, DAC_CHANNEL_ID,
236 (1U << DAC_RESOLUTION) / 2);
237 zassert_ok(ret, "dac_write_value() failed with code %d", ret);
238
239 /* wait to let DAC output settle */
240 k_sleep(K_MSEC(10));
241
242 static int16_t m_sample_buffer[1];
243 static const struct adc_sequence sequence = {
244 .channels = BIT(ADC_CHANNEL_ID),
245 .buffer = m_sample_buffer,
246 .buffer_size = sizeof(m_sample_buffer),
247 .resolution = ADC_RESOLUTION,
248 };
249
250 ret = adc_read(adc_dev, &sequence);
251 zassert_ok(ret, "adc_read() failed with code %d", ret);
252 zassert_within(m_sample_buffer[0],
253 (1U << ADC_RESOLUTION) / 2, 32,
254 "Value %d read from ADC does not match expected range.",
255 m_sample_buffer[0]);
256
257 return TC_PASS;
258 }
259
ZTEST(dac_loopback,test_dac_loopback)260 ZTEST(dac_loopback, test_dac_loopback)
261 {
262 zassert_true(test_task_loopback() == TC_PASS);
263 }
264
265 ZTEST_SUITE(dac_loopback, NULL, NULL, NULL, NULL, NULL);
266