1 /**************************************************************************//**
2 * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date            Author       Notes
8 * 2020-12-12      Wayne        First version
9 *
10 ******************************************************************************/
11 
12 #include <rtconfig.h>
13 
14 #if defined(BSP_USING_ADC)
15 
16 #include <rtdevice.h>
17 #include "NuMicro.h"
18 #include "drv_sys.h"
19 #include "nu_bitutil.h"
20 #include "drv_adc.h"
21 
22 /* Private define --------------------------------------------------------------- */
23 #define DEF_ADC_TOUCH_SMPL_TICK  40
24 #define TOUCH_MQ_LENGTH      64
25 
26 /* Private Typedef -------------------------------------------------------------- */
27 struct nu_adc
28 {
29     struct rt_adc_device dev;
30     char *name;
31     ADC_T *base;
32     uint32_t bReset;
33     IRQn_Type irqn;
34     E_SYS_IPRST rstidx;
35     E_SYS_IPCLK clkidx;
36     uint32_t chn_mask;
37     rt_sem_t m_psSem;
38 
39 #if defined(BSP_USING_ADC_TOUCH)
40     rt_touch_t psRtTouch;
41     rt_timer_t psRtTouchMenuTimer;
42     rt_mq_t m_pmqTouchXYZ;
43 #endif
44 
45     nu_adc_cb m_isr[eAdc_ISR_CNT];
46     nu_adc_cb m_wkisr[eAdc_WKISR_CNT];
47 };
48 typedef struct nu_adc *nu_adc_t;
49 
50 #if defined(BSP_USING_ADC_TOUCH)
51 struct nu_adc_touch_data
52 {
53     uint32_t    u32X;
54     uint32_t    u32Y;
55     uint32_t    u32Z0;
56     uint32_t    u32Z1;
57 };
58 typedef struct nu_adc_touch_data *nu_adc_touch_data_t;
59 #endif
60 
61 /* Private functions ------------------------------------------------------------ */
62 static rt_err_t nu_adc_enabled(struct rt_adc_device *device, rt_int8_t channel, rt_bool_t enabled);
63 static rt_err_t nu_adc_convert(struct rt_adc_device *device, rt_int8_t channel, rt_uint32_t *value);
64 static rt_err_t _nu_adc_control(rt_device_t dev, int cmd, void *args);
65 
66 /* Public functions ------------------------------------------------------------ */
67 int rt_hw_adc_init(void);
68 
69 /* Private variables ------------------------------------------------------------ */
70 
71 static struct nu_adc g_sNuADC =
72 {
73     .name = "adc",
74     .base = (ADC_T *)ADC_BA,
75     .bReset = 1,
76     .irqn = IRQ_ADC,
77     .rstidx = ADCRST,
78     .clkidx = ADCCKEN,
79     .chn_mask = 0
80 };
81 
nu_adc_isr(int vector,void * param)82 static void nu_adc_isr(int vector, void *param)
83 {
84     volatile rt_int32_t isr, wkisr;
85     nu_adc_t psNuAdc = (nu_adc_t)param;
86     rt_int32_t irqidx;
87     ADC_T  *adc = psNuAdc->base;
88 
89     /* rt_kprintf("[%s %d] CTL: %08x CONF:%08x IER:%08x ISR:%08x\n", __func__, __LINE__, adc->CTL, adc->CONF, adc->IER, adc->ISR); */
90 
91     isr = adc->ISR;
92     wkisr = adc->WKISR;
93 
94     adc->ISR = isr;
95 
96     while ((irqidx = nu_ctz(isr)) < eAdc_ISR_CNT)
97     {
98         uint32_t u32IsrBitMask =  1 << irqidx ;
99 
100         if (psNuAdc->m_isr[irqidx].cbfunc != RT_NULL)
101         {
102             /* rt_kprintf("[%s] %d %x\n", __func__, irqidx, psNuAdc->m_isr[irqidx].cbfunc); */
103             psNuAdc->m_isr[irqidx].cbfunc(isr, psNuAdc->m_isr[irqidx].private_data);
104         }
105 
106         /* Clear sent bit */
107         isr &= ~(u32IsrBitMask);
108     } /* while */
109 
110     while ((irqidx = nu_ctz(wkisr)) < eAdc_WKISR_CNT)
111     {
112         uint32_t u32IsrBitMask = 1 << irqidx ;
113 
114         if (psNuAdc->m_wkisr[irqidx].cbfunc != RT_NULL)
115         {
116             psNuAdc->m_wkisr[irqidx].cbfunc(wkisr, psNuAdc->m_wkisr[irqidx].private_data);
117         }
118 
119         wkisr &= ~(u32IsrBitMask);
120     } /* while */
121 }
122 
123 
124 #define DEF_ADC_SRC_CLOCK_DIV  (12000 / 1000)
_nu_adc_init(rt_device_t dev)125 static rt_err_t _nu_adc_init(rt_device_t dev)
126 {
127     nu_adc_t psNuAdc = (nu_adc_t)dev;
128 
129     /* Set ADC Engine Clock */
130     outpw(REG_CLK_DIVCTL7, inpw(REG_CLK_DIVCTL7) & ~((0x3 << 19) | (0x7 << 16) | (0xFFul << 24)));
131     outpw(REG_CLK_DIVCTL7, (0 << 19) | (0 << 16) | ((DEF_ADC_SRC_CLOCK_DIV - 1) << 24));
132 
133     /* Install interrupt service routine */
134     rt_hw_interrupt_install(psNuAdc->irqn, nu_adc_isr, (void *)psNuAdc, psNuAdc->name);
135 
136     return RT_EOK;
137 }
138 
139 #define ADC_TOUCH_Z0_ACTIVE 20
AdcMenuStartCallback(uint32_t status,uint32_t userData)140 static int32_t AdcMenuStartCallback(uint32_t status, uint32_t userData)
141 {
142     nu_adc_t psNuAdc = (nu_adc_t)userData;
143 
144 #if defined(BSP_USING_ADC_TOUCH)
145     ADC_T  *adc = psNuAdc->base;
146     static struct nu_adc_touch_data point;
147     static rt_bool_t bDrop = RT_FALSE;
148     static uint32_t u32LastZ0 = 0xffffu;
149 
150     if (psNuAdc->psRtTouch != RT_NULL)
151     {
152         point.u32X = ADC_GET_CONVERSION_XDATA(adc);
153         point.u32Y = ADC_GET_CONVERSION_YDATA(adc);
154 
155         point.u32Z0 = ADC_GET_CONVERSION_Z1DATA(adc);
156         point.u32Z1 = ADC_GET_CONVERSION_Z2DATA(adc);
157 
158         /* rt_kprintf("x=%d y=%d z0=%d z1=%d\n", point.u32X, point.u32Y, point.u32Z0, point.u32Z1); */
159         /* Trigger next or not. */
160         if (point.u32Z0 < ADC_TOUCH_Z0_ACTIVE)
161         {
162             /* Stop sampling procedure. */
163             rt_timer_stop(g_sNuADC.psRtTouchMenuTimer);
164 
165             /* Re-start pendown detection */
166             nu_adc_touch_detect(RT_TRUE);
167 
168             psNuAdc->bReset = 1;
169 
170             bDrop = RT_TRUE;
171         }
172         else
173         {
174             bDrop = RT_FALSE;
175         }
176 
177         /* Notify upper layer. */
178         if ((!bDrop || (u32LastZ0 > ADC_TOUCH_Z0_ACTIVE)) && rt_mq_send(psNuAdc->m_pmqTouchXYZ, (const void *)&point, sizeof(struct nu_adc_touch_data)) == RT_EOK)
179         {
180             rt_hw_touch_isr(psNuAdc->psRtTouch);
181         }
182 
183         u32LastZ0 = point.u32Z0;
184     }
185     else
186 #endif
187     {
188         rt_err_t result = rt_sem_release(psNuAdc->m_psSem);
189         RT_ASSERT(result == RT_EOK);
190     }
191 
192     return 0;
193 }
194 
195 #if defined(BSP_USING_ADC_TOUCH)
196 
nu_adc_touch_antiglitch(ADC_T * adc)197 static void nu_adc_touch_antiglitch(ADC_T  *adc)
198 {
199     int count = 10;
200     do
201     {
202         rt_hw_us_delay(1000); /* 1ms */
203         ADC_CLR_INT_FLAG(adc, adc->ISR);
204         if (adc->ISR == 0)
205             break;
206     }
207     while (count-- > 0);
208 }
209 
nu_adc_touch_detect(rt_bool_t bStartDetect)210 void nu_adc_touch_detect(rt_bool_t bStartDetect)
211 {
212     nu_adc_t psNuAdc = (nu_adc_t)&g_sNuADC;
213     ADC_T  *adc = psNuAdc->base;
214 
215     /* Disable interrupt */
216     rt_hw_interrupt_mask(psNuAdc->irqn);
217 
218     ADC_POWER_DOWN(adc);
219 
220     /* Disable interrupt */
221     ADC_DISABLE_INT(adc, ADC_IER_PEDEIEN_Msk | ADC_IER_MIEN_Msk);
222     nu_adc_touch_antiglitch(adc);
223 
224     if (bStartDetect == RT_TRUE)
225     {
226         /* Switch to PenDown detection mode */
227         ADC_DETECT_PD_MODE(adc);
228         nu_adc_touch_antiglitch(adc);
229 
230         /* Enable interrupt */
231         ADC_ENABLE_INT(adc, ADC_IER_PEDEIEN_Msk);
232     }
233     else
234     {
235         /* Switch to XY coordination converting mode */
236         ADC_CONVERT_XY_MODE(adc);
237         nu_adc_touch_antiglitch(adc);
238 
239         /* Enable interrupt */
240         ADC_ENABLE_INT(adc, ADC_IER_MIEN_Msk);
241     }
242 
243     ADC_POWER_ON(adc);
244 
245     /* Enable interrupt */
246     rt_hw_interrupt_umask(psNuAdc->irqn);
247 }
248 
PenDownCallback(uint32_t status,uint32_t userData)249 static int32_t PenDownCallback(uint32_t status, uint32_t userData)
250 {
251     nu_adc_t psNuAdc = (nu_adc_t)userData;
252     return rt_timer_start(psNuAdc->psRtTouchMenuTimer);
253 }
254 
nu_adc_touch_read_xyz(uint32_t * bufX,uint32_t * bufY,uint32_t * bufZ0,uint32_t * bufZ1,int32_t dataCnt)255 int32_t nu_adc_touch_read_xyz(uint32_t *bufX, uint32_t *bufY, uint32_t *bufZ0, uint32_t *bufZ1, int32_t dataCnt)
256 {
257     int i;
258     struct nu_adc_touch_data value;
259 
260     for (i = 0 ; i < dataCnt; i++)
261     {
262         if (rt_mq_recv(g_sNuADC.m_pmqTouchXYZ, (void *)&value, sizeof(struct nu_adc_touch_data), 0) == -RT_ETIMEOUT)
263             break;
264 
265         bufX[i]  = value.u32X;
266         bufY[i]  = value.u32Y;
267         bufZ0[i] = value.u32Z0;
268         bufZ1[i] = value.u32Z1;
269     }
270     return i;
271 }
272 
nu_adc_touch_enable(rt_touch_t psRtTouch)273 rt_err_t nu_adc_touch_enable(rt_touch_t psRtTouch)
274 {
275     nu_adc_t psNuAdc = (nu_adc_t)&g_sNuADC;
276     nu_adc_cb sNuAdcCb;
277     ADC_T  *adc = psNuAdc->base;
278 
279     adc->CONF = 0x0;
280 
281     rt_adc_enable((rt_adc_device_t)psNuAdc, 4);  /* Channel number 4 */
282     rt_adc_enable((rt_adc_device_t)psNuAdc, 5);  /* Channel number 5 */
283     rt_adc_enable((rt_adc_device_t)psNuAdc, 6);  /* Channel number 6 */
284     rt_adc_enable((rt_adc_device_t)psNuAdc, 7);  /* Channel number 7 */
285 
286     /* Register touch device. */
287     psNuAdc->psRtTouch = psRtTouch;
288 
289     /* Register PenDown callback. */
290     sNuAdcCb.cbfunc = PenDownCallback;
291     sNuAdcCb.private_data = (rt_uint32_t)psNuAdc;
292     rt_memcpy(&psNuAdc->m_isr[eAdc_PEDEF], &sNuAdcCb, sizeof(nu_adc_cb));
293 
294     nu_adc_touch_detect(RT_TRUE);
295 
296     return RT_EOK;
297 }
298 
nu_adc_touch_disable(void)299 rt_err_t nu_adc_touch_disable(void)
300 {
301     nu_adc_t psNuAdc = (nu_adc_t)&g_sNuADC;
302 
303     nu_adc_touch_detect(RT_FALSE);
304 
305     _nu_adc_control((rt_device_t)psNuAdc, T_OFF, RT_NULL);
306     _nu_adc_control((rt_device_t)psNuAdc, Z_OFF, RT_NULL);
307     _nu_adc_control((rt_device_t)psNuAdc, PEDEF_OFF, RT_NULL);
308 
309     rt_adc_disable((rt_adc_device_t)psNuAdc, 4);  /* Channel number 4 */
310     rt_adc_disable((rt_adc_device_t)psNuAdc, 5);  /* Channel number 5 */
311     rt_adc_disable((rt_adc_device_t)psNuAdc, 6);  /* Channel number 6 */
312     rt_adc_disable((rt_adc_device_t)psNuAdc, 7);  /* Channel number 7 */
313 
314     return RT_EOK;
315 }
316 
nu_adc_touch_smpl(void * p)317 static void nu_adc_touch_smpl(void *p)
318 {
319     nu_adc_t psNuAdc = (nu_adc_t)p;
320     if (psNuAdc->bReset)
321     {
322         psNuAdc->bReset = 0;
323         nu_adc_touch_detect(RT_FALSE);
324     }
325 
326     /* Start conversion */
327     ADC_START_CONV(psNuAdc->base);
328 }
329 #endif
330 
_nu_adc_control(rt_device_t dev,int cmd,void * args)331 static rt_err_t _nu_adc_control(rt_device_t dev, int cmd, void *args)
332 {
333     rt_err_t ret = -RT_EINVAL ;
334     nu_adc_t psNuAdc = (nu_adc_t)dev;
335     ADC_T  *adc = psNuAdc->base;
336 
337     nu_adc_cb_t psAdcCb = (nu_adc_cb_t)args;
338 
339     switch (cmd)
340     {
341     case START_MST:  /* Menu Start Conversion */
342     {
343         /* Enable interrupt */
344         ADC_ENABLE_INT(adc, ADC_IER_MIEN_Msk);
345 
346         /* Start conversion */
347         ADC_START_CONV(adc);
348 
349         /* Wait it done */
350         ret = rt_sem_take(psNuAdc->m_psSem, RT_WAITING_FOREVER);
351         RT_ASSERT(ret == RT_EOK);
352 
353         /* Get data: valid data is 12-bit */
354         if (args != RT_NULL)
355             *((uint32_t *)args) = ADC_GET_CONVERSION_DATA(adc, 0);
356     }
357     break;
358 
359     case WKT_ON: /* Enable Touch Wake Up */
360     {
361         if (psAdcCb)
362         {
363             rt_memcpy(&psNuAdc->m_wkisr[eAdc_WPEDEF], psAdcCb, sizeof(nu_adc_cb));
364         }
365         adc->CTL |= ADC_CTL_WKTEN_Msk;
366         adc->IER |= ADC_IER_WKTIEN_Msk;
367 
368         /* TODO outpw(REG_SYS_WKUPSER, inpw(REG_SYS_WKUPSER) | (1 << 26)); */
369     }
370     break;
371 
372     case WKT_OFF:  /* Disable Touch Wake Up */
373     {
374         adc->CTL &= ~ADC_CTL_WKTEN_Msk;
375         adc->IER &= ~ADC_IER_WKTIEN_Msk;
376 
377         /* TODO outpw(REG_SYS_WKUPSER, inpw(REG_SYS_WKUPSER) & ~(1 << 26)); */
378     }
379     break;
380 
381     case SWITCH_5WIRE_ON:   /* Wire Mode Switch to 5-Wire */
382     {
383         adc->CTL |= ADC_CTL_WMSWCH_Msk;
384     }
385     break;
386 
387     case SWITCH_5WIRE_OFF:  /* Wire Mode Switch to 4-Wire */
388     {
389         adc->CTL &= ~ADC_CTL_WMSWCH_Msk;
390     }
391     break;
392 
393     case T_ON:   /* Enable Touch detection function */
394     {
395         adc->CONF |= ADC_CONF_TEN_Msk;
396     }
397     break;
398 
399     case T_OFF:   /* Disable Touch detection function */
400     {
401         adc->CONF &= ~ADC_CONF_TEN_Msk;
402     }
403     break;
404 
405     case TAVG_ON:   /* Enable Touch Mean average for X and Y function */
406     {
407         adc->CONF |= ADC_CONF_TMAVDIS_Msk;
408     }
409     break;
410 
411     case TAVG_OFF:   /* Disable Touch Mean average for X and Y function */
412     {
413         adc->CONF &= ~ADC_CONF_TMAVDIS_Msk;
414     }
415     break;
416 
417     case Z_ON:   /* Enable Press measure function */
418     {
419         adc->CONF |= ADC_CONF_ZEN_Msk;
420     }
421     break;
422 
423     case Z_OFF:   /* Disable Press measure function */
424     {
425         adc->CONF &= ~ADC_CONF_ZEN_Msk;
426 #if defined(BSP_USING_ADC_TOUCH)
427         rt_mq_control(psNuAdc->m_pmqTouchXYZ, RT_IPC_CMD_RESET, RT_NULL);
428 #endif
429     }
430     break;
431 
432     case TZAVG_ON:   /* Enable Pressure Mean average for Z1 and Z2 function */
433     {
434         adc->CONF |= ADC_CONF_ZMAVDIS_Msk;
435     }
436     break;
437 
438     case TZAVG_OFF:   /* Disable Pressure Mean average for Z1 and Z2 function */
439     {
440         adc->CONF &= ~ADC_CONF_ZMAVDIS_Msk;
441     }
442     break;
443 
444     case NAC_ON: /* Enable Normal AD Conversion */
445     {
446         adc->CONF |= (ADC_CONF_NACEN_Msk | ADC_CONF_REFSEL_AVDD33);
447     }
448     break;
449 
450     case NAC_OFF: /* Disable Normal AD Conversion */
451     {
452         adc->CONF &= ~ADC_CONF_NACEN_Msk;
453     }
454     break;
455 
456     case SWITCH_CH:
457     {
458         int chn = (int)args;
459         if (chn >= ADC_CH_NUM)
460         {
461             return -ret;
462         }
463         adc->CONF &= ~ADC_CONF_CHSEL_Msk;
464         adc->CONF |= (chn << ADC_CONF_CHSEL_Pos);
465     }
466     break;
467 
468     default:
469         return -(ret);
470     }
471 
472     return RT_EOK;
473 }
474 
_nu_adc_open(rt_device_t dev,rt_uint16_t oflag)475 static rt_err_t _nu_adc_open(rt_device_t dev, rt_uint16_t oflag)
476 {
477     nu_adc_t psNuAdc = (nu_adc_t)dev;
478     ADC_T  *adc = psNuAdc->base;
479 
480     /* Enable ADC engine clock */
481     nu_sys_ipclk_enable(psNuAdc->clkidx);
482 
483     /* Reset the ADC IP */
484     nu_sys_ip_reset(psNuAdc->rstidx);
485 
486     /* Enable ADC Power */
487     ADC_POWER_ON(adc);
488 
489     /* Enable ADC to high speed mode */
490     adc->CONF |= ADC_CONF_SPEED_Msk;
491 
492     /* Enable interrupt */
493     rt_hw_interrupt_umask(psNuAdc->irqn);
494 
495     /* Enable Normal AD Conversion */
496     _nu_adc_control(dev, NAC_ON, RT_NULL);
497 
498     return RT_EOK;
499 }
500 
_nu_adc_close(rt_device_t dev)501 static rt_err_t _nu_adc_close(rt_device_t dev)
502 {
503     nu_adc_t psNuAdc = (nu_adc_t)dev;
504     ADC_T  *adc = psNuAdc->base;
505 
506     /* Disable Normal AD Conversion */
507     _nu_adc_control(dev, NAC_OFF, RT_NULL);
508 
509     /* Disable interrupt */
510     rt_hw_interrupt_mask(psNuAdc->irqn);
511 
512     /* Disable ADC Power */
513     ADC_POWER_DOWN(adc);
514 
515     /* Disable ADC engine clock */
516     nu_sys_ipclk_disable(psNuAdc->clkidx);
517 
518     return RT_EOK;
519 }
520 
521 static const struct rt_adc_ops nu_adc_ops =
522 {
523     nu_adc_enabled,
524     nu_adc_convert,
525 };
526 
527 /* nu_adc_enabled - Enable ADC clock and wait for ready */
nu_adc_enabled(struct rt_adc_device * device,rt_int8_t channel,rt_bool_t enabled)528 static rt_err_t nu_adc_enabled(struct rt_adc_device *device, rt_int8_t channel, rt_bool_t enabled)
529 {
530     nu_adc_t psNuADC = (nu_adc_t)device;
531     RT_ASSERT(device);
532 
533     if (channel >= ADC_CH_NUM)
534         return -(RT_EINVAL);
535 
536     if (enabled)
537     {
538         psNuADC->chn_mask |= (1 << channel);
539     }
540     else
541     {
542         psNuADC->chn_mask &= ~(1 << channel);
543     }
544 
545     if (psNuADC->chn_mask > 0 && ((rt_device_t)device)->ref_count == 0)
546     {
547         _nu_adc_open((rt_device_t)device, 0);
548         ((rt_device_t)device)->ref_count = 1;
549     }
550     else if ((psNuADC->chn_mask == 0) && ((rt_device_t)device)->ref_count == 1)
551     {
552         _nu_adc_close((rt_device_t)device);
553         ((rt_device_t)device)->ref_count = 0;
554     }
555     return RT_EOK;
556 }
557 
nu_adc_convert(struct rt_adc_device * device,rt_int8_t channel,rt_uint32_t * value)558 static rt_err_t nu_adc_convert(struct rt_adc_device *device, rt_int8_t channel, rt_uint32_t *value)
559 {
560     rt_err_t ret = RT_EOK;
561 
562     RT_ASSERT(device);
563     RT_ASSERT(value);
564 
565     if (channel >= ADC_CH_NUM)
566     {
567         ret = -RT_EINVAL;
568         goto exit_nu_adc_convert;
569     }
570     else if ((ret = _nu_adc_control((rt_device_t)device, SWITCH_CH, (void *)(intptr_t)channel)) != RT_EOK)
571     {
572         goto exit_nu_adc_convert;
573     }
574     else if ((ret = _nu_adc_control((rt_device_t)device, START_MST, (void *)value)) != RT_EOK)
575     {
576         goto exit_nu_adc_convert;
577     }
578 
579 exit_nu_adc_convert:
580 
581     return (-ret) ;
582 }
583 
rt_hw_adc_init(void)584 int rt_hw_adc_init(void)
585 {
586     rt_err_t result = -RT_ERROR;
587     rt_device_t psDev = &g_sNuADC.dev.parent;
588 
589     result = rt_hw_adc_register(&g_sNuADC.dev, g_sNuADC.name, &nu_adc_ops, &g_sNuADC);
590     RT_ASSERT(result == RT_EOK);
591 
592     result = _nu_adc_init(psDev);
593     RT_ASSERT(result == RT_EOK);
594 
595     g_sNuADC.m_psSem = rt_sem_create("adc_mst_sem", 0, RT_IPC_FLAG_FIFO);
596     RT_ASSERT(g_sNuADC.m_psSem);
597 
598 #if defined(BSP_USING_ADC_TOUCH)
599     g_sNuADC.m_pmqTouchXYZ = rt_mq_create("ADC_TOUCH_XYZ", sizeof(struct nu_adc_touch_data), TOUCH_MQ_LENGTH, RT_IPC_FLAG_FIFO);
600     RT_ASSERT(g_sNuADC.m_pmqTouchXYZ);
601 
602     g_sNuADC.psRtTouchMenuTimer = rt_timer_create("TOUCH_SMPL_TIMER", nu_adc_touch_smpl, (void *)&g_sNuADC, DEF_ADC_TOUCH_SMPL_TICK, RT_TIMER_FLAG_PERIODIC);
603     RT_ASSERT(g_sNuADC.psRtTouchMenuTimer);
604 #endif
605 
606     rt_memset(&g_sNuADC.m_isr, 0, sizeof(g_sNuADC.m_isr));
607     rt_memset(&g_sNuADC.m_wkisr, 0, sizeof(g_sNuADC.m_wkisr));
608 
609     g_sNuADC.m_isr[eAdc_MF].cbfunc = AdcMenuStartCallback;
610     g_sNuADC.m_isr[eAdc_MF].private_data = (uint32_t)&g_sNuADC;
611 
612     return (int)result;
613 }
614 INIT_BOARD_EXPORT(rt_hw_adc_init);
615 
616 #endif /* #if defined(BSP_USING_ADC) */
617