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 #elif DT_HAS_COMPAT_STATUS_OKAY(renesas_ra_dac)
169 
170 #define DAC_DEVICE_NODE DT_NODELABEL(dac0)
171 #define DAC_RESOLUTION  12
172 #define DAC_CHANNEL_ID  0
173 
174 #define ADC_DEVICE_NODE      DT_NODELABEL(adc0)
175 #define ADC_RESOLUTION       12
176 #define ADC_GAIN             ADC_GAIN_1
177 #define ADC_REFERENCE        ADC_REF_INTERNAL
178 #define ADC_ACQUISITION_TIME ADC_ACQ_TIME_DEFAULT
179 #if defined(CONFIG_BOARD_EK_RA4L1)
180 #define ADC_CHANNEL_ID 1
181 #elif defined(CONFIG_BOARD_EK_RA4W1)
182 #define ADC_CHANNEL_ID 4
183 #else
184 #define ADC_CHANNEL_ID 0
185 #endif
186 
187 #elif defined(CONFIG_SOC_FAMILY_SILABS_S2)
188 
189 /* VDAC0CH0 output is internally available on IADC_INPUT_DAC0 */
190 
191 #include <zephyr/dt-bindings/adc/silabs-adc.h>
192 
193 #define DAC_DEVICE_NODE		DT_NODELABEL(vdac0)
194 #define DAC_RESOLUTION		12
195 #define DAC_CHANNEL_ID		0
196 
197 #define ADC_DEVICE_NODE		DT_NODELABEL(adc0)
198 #define ADC_RESOLUTION		12
199 #define ADC_GAIN		ADC_GAIN_1
200 #define ADC_REFERENCE		ADC_REF_VDD_1
201 #define ADC_ACQUISITION_TIME	ADC_ACQ_TIME_DEFAULT
202 #define ADC_CHANNEL_ID		0
203 #define ADC_1ST_CHANNEL_INPUT	IADC_INPUT_DAC0
204 
205 #else
206 #error "Unsupported board."
207 #endif
208 
209 static const struct dac_channel_cfg dac_ch_cfg = {
210 	.channel_id = DAC_CHANNEL_ID,
211 	.resolution = DAC_RESOLUTION,
212 #if defined(CONFIG_DAC_BUFFER_NOT_SUPPORT)
213 	.buffered = false,
214 #else
215 	.buffered = true,
216 #endif /* CONFIG_DAC_BUFFER_NOT_SUPPORT */
217 };
218 
219 static const struct adc_channel_cfg adc_ch_cfg = {
220 	.gain             = ADC_GAIN,
221 	.reference        = ADC_REFERENCE,
222 	.acquisition_time = ADC_ACQUISITION_TIME,
223 	.channel_id       = ADC_CHANNEL_ID,
224 
225 #if defined(CONFIG_BOARD_BL652_DVK) || \
226 	defined(CONFIG_BOARD_BL653_DVK) || \
227 	defined(CONFIG_BOARD_BL654_DVK) || \
228 	defined(CONFIG_BOARD_BL5340_DVK) || \
229 	defined(CONFIG_BOARD_LPCXPRESSO55S36) || \
230 	defined(CONFIG_SOC_FAMILY_SILABS_S2)
231 	.input_positive   = ADC_1ST_CHANNEL_INPUT,
232 #endif
233 };
234 
init_dac(void)235 static const struct device *init_dac(void)
236 {
237 	int ret;
238 	const struct device *const dac_dev = DEVICE_DT_GET(DAC_DEVICE_NODE);
239 
240 	zassert_true(device_is_ready(dac_dev), "DAC device is not ready");
241 
242 	ret = dac_channel_setup(dac_dev, &dac_ch_cfg);
243 	zassert_ok(ret, "Setting up of the first channel failed with code %d", ret);
244 
245 	return dac_dev;
246 }
247 
248 /* ADC necessary to read back the value from DAC */
init_adc(void)249 static const struct device *init_adc(void)
250 {
251 	int ret;
252 	const struct device *const adc_dev = DEVICE_DT_GET(ADC_DEVICE_NODE);
253 
254 	zassert_true(device_is_ready(adc_dev), "ADC device is not ready");
255 
256 	ret = adc_channel_setup(adc_dev, &adc_ch_cfg);
257 	zassert_ok(ret, "Setting up of the ADC channel failed with code %d", ret);
258 
259 	return adc_dev;
260 }
261 
262 /*
263  * test_dac_loopback
264  */
test_task_loopback(void)265 static int test_task_loopback(void)
266 {
267 	int ret;
268 
269 	const struct device *dac_dev = init_dac();
270 	const struct device *adc_dev = init_adc();
271 
272 	if (!dac_dev || !adc_dev) {
273 		return TC_FAIL;
274 	}
275 
276 	/* write a value of half the full scale resolution */
277 	ret = dac_write_value(dac_dev, DAC_CHANNEL_ID,
278 		(1U << DAC_RESOLUTION) / 2);
279 	zassert_ok(ret, "dac_write_value() failed with code %d", ret);
280 
281 	/* wait to let DAC output settle */
282 	k_sleep(K_MSEC(10));
283 
284 	static int16_t m_sample_buffer[1];
285 	static const struct adc_sequence sequence = {
286 		.channels    = BIT(ADC_CHANNEL_ID),
287 		.buffer      = m_sample_buffer,
288 		.buffer_size = sizeof(m_sample_buffer),
289 		.resolution  = ADC_RESOLUTION,
290 	};
291 
292 	ret = adc_read(adc_dev, &sequence);
293 	zassert_ok(ret, "adc_read() failed with code %d", ret);
294 	zassert_within(m_sample_buffer[0],
295 		(1U << ADC_RESOLUTION) / 2, 32,
296 		"Value %d read from ADC does not match expected range.",
297 		m_sample_buffer[0]);
298 
299 	return TC_PASS;
300 }
301 
ZTEST(dac_loopback,test_dac_loopback)302 ZTEST(dac_loopback, test_dac_loopback)
303 {
304 	zassert_true(test_task_loopback() == TC_PASS);
305 }
306 
307 ZTEST_SUITE(dac_loopback, NULL, NULL, NULL, NULL, NULL);
308