1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2022-03-04 stevetong459 first version
9 * 2022-07-15 Aligagago add APM32F4 series MCU support
10 * 2022-12-26 luobeihai add APM32F0 series MCU support
11 * 2023-03-27 luobeihai add APM32E1/S1 series MCU support
12 */
13
14 #include <board.h>
15
16 #if defined(BSP_USING_ADC1) || defined(BSP_USING_ADC2) || defined(BSP_USING_ADC3)
17
18 #define DBG_TAG "drv.adc"
19 #define DBG_LVL DBG_INFO
20 #include <rtdbg.h>
21
22 #define DRV_ADC_CHANNEL_MAX_NUM 16
23 #define DRV_ADC_TIME_OUT 0xFFF
24
25 #define APM32_ADC_GET_PORT(pin_num) ((GPIO_T *)(GPIOA_BASE + (0x400u * (((pin_num) >> 4) & 0xFu))))
26 #define APM32_ADC_GET_PIN(pin_num) ((uint16_t)(1u << ((pin_num) & 0xFu)))
27
28 struct apm32_adc
29 {
30 const char *name;
31 ADC_T *adc;
32 ADC_Config_T adc_config;
33 rt_base_t channel_pin[DRV_ADC_CHANNEL_MAX_NUM];
34 struct rt_adc_device adc_dev;
35 };
36
37 #if defined(SOC_SERIES_APM32F1) || defined(SOC_SERIES_APM32E1) || defined(SOC_SERIES_APM32S1)
38 static struct apm32_adc adc_config[] =
39 {
40 #ifdef BSP_USING_ADC1
41 {
42 "adc1",
43 ADC1,
44 {
45 ADC_MODE_INDEPENDENT,
46 DISABLE,
47 DISABLE,
48 ADC_EXT_TRIG_CONV_None,
49 ADC_DATA_ALIGN_RIGHT,
50 1
51 },
52 {
53 GET_PIN(A, 0), GET_PIN(A, 1), GET_PIN(A, 2), GET_PIN(A, 3),
54 GET_PIN(A, 4), GET_PIN(A, 5), GET_PIN(A, 6), GET_PIN(A, 7),
55 GET_PIN(B, 0), GET_PIN(B, 1), GET_PIN(C, 0), GET_PIN(C, 1),
56 GET_PIN(C, 2), GET_PIN(C, 3), GET_PIN(C, 4), GET_PIN(C, 5)
57 },
58 },
59 #endif
60 #ifdef BSP_USING_ADC2
61 {
62 "adc2",
63 ADC2,
64 {
65 ADC_MODE_INDEPENDENT,
66 DISABLE,
67 DISABLE,
68 ADC_EXT_TRIG_CONV_None,
69 ADC_DATA_ALIGN_RIGHT,
70 1
71 },
72 {
73 GET_PIN(A, 0), GET_PIN(A, 1), GET_PIN(A, 2), GET_PIN(A, 3),
74 GET_PIN(A, 4), GET_PIN(A, 5), GET_PIN(A, 6), GET_PIN(A, 7),
75 GET_PIN(B, 0), GET_PIN(B, 1), GET_PIN(C, 0), GET_PIN(C, 1),
76 GET_PIN(C, 2), GET_PIN(C, 3), GET_PIN(C, 4), GET_PIN(C, 5)
77 },
78 },
79 #endif
80 #ifdef BSP_USING_ADC3
81 {
82 "adc3",
83 ADC3,
84 {
85 ADC_MODE_INDEPENDENT,
86 DISABLE,
87 DISABLE,
88 ADC_EXT_TRIG_CONV_None,
89 ADC_DATA_ALIGN_RIGHT,
90 1
91 },
92 {
93 GET_PIN(A, 0), GET_PIN(A, 1), GET_PIN(A, 2), GET_PIN(A, 3),
94 GET_PIN(F, 6), GET_PIN(F, 7), GET_PIN(F, 8), GET_PIN(F, 9),
95 GET_PIN(F, 10)
96 },
97 },
98 #endif
99 };
100 #elif defined(SOC_SERIES_APM32F4)
101 static struct apm32_adc adc_config[] =
102 {
103 #ifdef BSP_USING_ADC1
104 {
105 "adc1",
106 ADC1,
107 {
108 ADC_RESOLUTION_12BIT,
109 DISABLE,
110 DISABLE,
111 ADC_EXT_TRIG_EDGE_NONE,
112 ADC_EXT_TRIG_CONV_TMR1_CC1,
113 ADC_DATA_ALIGN_RIGHT,
114 1
115 },
116 {
117 GET_PIN(A, 0), GET_PIN(A, 1), GET_PIN(A, 2), GET_PIN(A, 3),
118 GET_PIN(A, 4), GET_PIN(A, 5), GET_PIN(A, 6), GET_PIN(A, 7),
119 GET_PIN(B, 0), GET_PIN(B, 1), GET_PIN(C, 0), GET_PIN(C, 1),
120 GET_PIN(C, 2), GET_PIN(C, 3), GET_PIN(C, 4), GET_PIN(C, 5)
121 },
122 },
123 #endif
124 #ifdef BSP_USING_ADC2
125 {
126 "adc2",
127 ADC2,
128 {
129 ADC_RESOLUTION_12BIT,
130 DISABLE,
131 DISABLE,
132 ADC_EXT_TRIG_EDGE_NONE,
133 ADC_EXT_TRIG_CONV_TMR1_CC1,
134 ADC_DATA_ALIGN_RIGHT,
135 1
136 },
137 {
138 GET_PIN(A, 0), GET_PIN(A, 1), GET_PIN(A, 2), GET_PIN(A, 3),
139 GET_PIN(A, 4), GET_PIN(A, 5), GET_PIN(A, 6), GET_PIN(A, 7),
140 GET_PIN(B, 0), GET_PIN(B, 1), GET_PIN(C, 0), GET_PIN(C, 1),
141 GET_PIN(C, 2), GET_PIN(C, 3), GET_PIN(C, 4), GET_PIN(C, 5)
142 },
143 },
144 #endif
145 #ifdef BSP_USING_ADC3
146 {
147 "adc3",
148 ADC3,
149 {
150 ADC_RESOLUTION_12BIT,
151 DISABLE,
152 DISABLE,
153 ADC_EXT_TRIG_EDGE_NONE,
154 ADC_EXT_TRIG_CONV_TMR1_CC1,
155 ADC_DATA_ALIGN_RIGHT,
156 1
157 },
158 {
159 GET_PIN(A, 0), GET_PIN(A, 1), GET_PIN(A, 2), GET_PIN(A, 3),
160 GET_PIN(F, 6), GET_PIN(F, 7), GET_PIN(F, 8), GET_PIN(F, 9),
161 GET_PIN(F, 10), GET_PIN(F, 3), GET_PIN(C, 0), GET_PIN(C, 1),
162 GET_PIN(C, 2), GET_PIN(C, 3)
163 },
164 },
165 #endif
166 };
167 #elif defined(SOC_SERIES_APM32F0)
168 static struct apm32_adc adc_config[] =
169 {
170 #ifdef BSP_USING_ADC1
171 {
172 "adc1",
173 ADC,
174 {
175 ADC_RESOLUTION_12B,
176 ADC_DATA_ALIGN_RIGHT,
177 ADC_SCAN_DIR_UPWARD,
178 ADC_CONVERSION_SINGLE,
179 ADC_EXT_TRIG_CONV_TRG0,
180 ADC_EXT_TRIG_EDGE_NONE
181 },
182 {
183 GET_PIN(A, 0), GET_PIN(A, 1), GET_PIN(A, 2), GET_PIN(A, 3),
184 GET_PIN(A, 4), GET_PIN(A, 5), GET_PIN(A, 6), GET_PIN(A, 7),
185 GET_PIN(B, 0), GET_PIN(B, 1), GET_PIN(C, 0), GET_PIN(C, 1),
186 GET_PIN(C, 2), GET_PIN(C, 3), GET_PIN(C, 4), GET_PIN(C, 5)
187 },
188 },
189 #endif
190 };
191 #endif
192
apm32_adc_channel_check(struct rt_adc_device * device,rt_uint32_t channel)193 static rt_err_t apm32_adc_channel_check(struct rt_adc_device *device, rt_uint32_t channel)
194 {
195 struct apm32_adc *adc_cfg = ((struct apm32_adc *)device->parent.user_data);
196
197 if ((adc_cfg->adc == ADC1) || (adc_cfg->adc == ADC2))
198 {
199 if (channel <= 15)
200 {
201 return RT_EOK;
202 }
203 }
204
205 #if defined(SOC_SERIES_APM32F1) || defined(SOC_SERIES_APM32E1)
206 if (adc_cfg->adc == ADC3)
207 {
208 if (channel <= 8)
209 {
210 return RT_EOK;
211 }
212 }
213 #endif
214
215 #if defined(SOC_SERIES_APM32F4)
216 if (adc_cfg->adc == ADC3)
217 {
218 if (channel <= 13)
219 {
220 return RT_EOK;
221 }
222 }
223 #endif
224
225 LOG_E("channel %d of %s is not supported.", channel, adc_cfg->name);
226
227 return -RT_ERROR;
228 }
229
apm32_adc_gpio_init(struct rt_adc_device * device,rt_uint32_t channel)230 static rt_err_t apm32_adc_gpio_init(struct rt_adc_device *device, rt_uint32_t channel)
231 {
232 struct apm32_adc *adc_cfg = ((struct apm32_adc *)device->parent.user_data);
233 GPIO_Config_T hw_gpio_config;
234
235 if (apm32_adc_channel_check(device, channel) != RT_EOK)
236 {
237 return -RT_ERROR;
238 }
239 #if defined(SOC_SERIES_APM32F1) || defined(SOC_SERIES_APM32E1) || defined(SOC_SERIES_APM32S1)
240 RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOA << ((adc_cfg->channel_pin[channel] >> 4) & 0xFu));
241 hw_gpio_config.mode = GPIO_MODE_ANALOG;
242 #elif defined(SOC_SERIES_APM32F4)
243 RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOA << ((adc_cfg->channel_pin[channel] >> 4) & 0xFu));
244 hw_gpio_config.mode = GPIO_MODE_AN;
245 #elif defined(SOC_SERIES_APM32F0)
246 RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOA << ((adc_cfg->channel_pin[channel] >> 4) & 0xFu));
247 hw_gpio_config.mode = GPIO_MODE_AN;
248 #endif
249 hw_gpio_config.pin = APM32_ADC_GET_PIN(adc_cfg->channel_pin[channel]);
250 GPIO_Config(APM32_ADC_GET_PORT(adc_cfg->channel_pin[channel]), &hw_gpio_config);
251
252 return RT_EOK;
253 }
254
255 /**
256 * @brief This function will control the adc to enable or disable.
257 *
258 * @param device is a pointer to adc device.
259 *
260 * @param channel is the adc channel.
261 *
262 * @param enabled is the status to indicate enable or disable.
263 *
264 * @return RT_EOK indicates successful enable or disable adc, other value indicates failed.
265 */
apm32_adc_enabled(struct rt_adc_device * device,rt_uint32_t channel,rt_bool_t enabled)266 static rt_err_t apm32_adc_enabled(struct rt_adc_device *device, rt_uint32_t channel, rt_bool_t enabled)
267 {
268 struct apm32_adc *adc_cfg = ((struct apm32_adc *)device->parent.user_data);
269
270 RT_ASSERT(device != RT_NULL);
271
272 #if defined(SOC_SERIES_APM32F0)
273 if (enabled)
274 {
275 RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_ADC1);
276 if (apm32_adc_gpio_init(device, channel) != RT_EOK)
277 {
278 return -RT_ERROR;
279 }
280 ADC_Config(&adc_cfg->adc_config);
281 ADC_Enable();
282 }
283 else
284 {
285 ADC_Disable();
286 }
287 #elif defined(SOC_SERIES_APM32F1) || defined(SOC_SERIES_APM32E1) || defined(SOC_SERIES_APM32S1) \
288 || defined(SOC_SERIES_APM32F4)
289 if (enabled)
290 {
291 if (adc_cfg->adc == ADC1)
292 {
293 RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_ADC1);
294 }
295 else if (adc_cfg->adc == ADC2)
296 {
297 RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_ADC2);
298 }
299 #ifdef BSP_USING_ADC3
300 else if (adc_cfg->adc == ADC3)
301 {
302 RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_ADC3);
303 }
304 #endif /* BSP_USING_ADC3 */
305 if (apm32_adc_gpio_init(device, channel) != RT_EOK)
306 {
307 return -RT_ERROR;
308 }
309
310 ADC_Config(adc_cfg->adc, &adc_cfg->adc_config);
311
312 ADC_Enable(adc_cfg->adc);
313 }
314 else
315 {
316 ADC_Disable(adc_cfg->adc);
317 }
318 #endif /* SOC_SERIES_APM32F0 */
319
320 return RT_EOK;
321 }
322
323 /**
324 * @brief This function will get the adc conversion value.
325 *
326 * @param device is a pointer to adc device.
327 *
328 * @param channel is the adc channel.
329 *
330 * @param value is a pointer to the adc conversion value.
331 *
332 * @return RT_EOK indicates successful get adc value, other value indicates failed.
333 */
apm32_adc_get_value(struct rt_adc_device * device,rt_uint32_t channel,rt_uint32_t * value)334 static rt_err_t apm32_adc_get_value(struct rt_adc_device *device, rt_uint32_t channel, rt_uint32_t *value)
335 {
336 #if !defined(SOC_SERIES_APM32F0)
337 struct apm32_adc *adc_cfg = ((struct apm32_adc *)device->parent.user_data);
338 #endif
339 volatile rt_uint32_t counter = 0;
340
341 RT_ASSERT(device != RT_NULL);
342 RT_ASSERT(value != RT_NULL);
343
344 if (apm32_adc_channel_check(device, channel) != RT_EOK)
345 {
346 return -RT_ERROR;
347 }
348
349 #if defined(SOC_SERIES_APM32F1) || defined(SOC_SERIES_APM32E1) || defined(SOC_SERIES_APM32S1)
350 ADC_ConfigRegularChannel(adc_cfg->adc, channel, 1, ADC_SAMPLETIME_13CYCLES5);
351
352 ADC_StartCalibration(adc_cfg->adc);
353 /* Check the end of ADC calibration */
354 while (ADC_ReadCalibrationStartFlag(adc_cfg->adc))
355 {
356 if (++counter > DRV_ADC_TIME_OUT)
357 {
358 return -RT_ETIMEOUT;
359 }
360 }
361
362 ADC_EnableSoftwareStartConv(adc_cfg->adc);
363
364 while (!ADC_ReadStatusFlag(adc_cfg->adc, ADC_FLAG_EOC))
365 {
366 if (++counter > DRV_ADC_TIME_OUT)
367 {
368 return -RT_ETIMEOUT;
369 }
370 }
371 *value = ADC_ReadConversionValue(adc_cfg->adc);
372 #elif defined(SOC_SERIES_APM32F4)
373 ADC_ConfigRegularChannel(adc_cfg->adc, channel, 1, ADC_SAMPLETIME_15CYCLES);
374 ADC_SoftwareStartConv(adc_cfg->adc);
375
376 while (!ADC_ReadStatusFlag(adc_cfg->adc, ADC_FLAG_EOC))
377 {
378 if (++counter > DRV_ADC_TIME_OUT)
379 {
380 return -RT_ETIMEOUT;
381 }
382 }
383 *value = ADC_ReadConversionValue(adc_cfg->adc);
384 #elif defined(SOC_SERIES_APM32F0)
385 ADC_ConfigChannel((uint16_t)(1u << ((channel) & 0xFu)), ADC_SAMPLE_TIME_239_5);
386
387 ADC_StartConversion();
388
389 while (!ADC_ReadStatusFlag(ADC_FLAG_CC))
390 {
391 if (++counter > DRV_ADC_TIME_OUT)
392 {
393 return -RT_ETIMEOUT;
394 }
395 }
396 *value = ADC_ReadConversionValue();
397 #endif
398
399 return RT_EOK;
400 }
401
402 static const struct rt_adc_ops apm32_adc_ops =
403 {
404 .enabled = apm32_adc_enabled,
405 .convert = apm32_adc_get_value,
406 };
407
408 /**
409 * @brief ADC initialization function.
410 *
411 * @return RT_EOK indicates successful initialization, other value indicates failed;
412 */
rt_hw_adc_init(void)413 static int rt_hw_adc_init(void)
414 {
415 rt_err_t result = RT_EOK;
416 rt_size_t obj_num = sizeof(adc_config) / sizeof(struct apm32_adc);
417 rt_uint32_t i = 0;
418
419 for (i = 0; i < obj_num; i++)
420 {
421 /* register ADC device */
422 if (rt_hw_adc_register(&adc_config[i].adc_dev, adc_config[i].name, &apm32_adc_ops, &adc_config[i]) == RT_EOK)
423 {
424 LOG_D("%s init success", adc_config[i].name);
425 }
426 else
427 {
428 LOG_D("%s init failed", adc_config[i].name);
429 result = -RT_ERROR;
430 }
431 }
432
433 return result;
434 }
435 INIT_BOARD_EXPORT(rt_hw_adc_init);
436
437 #endif /* BSP_USING_ADCX */
438