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