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