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 * 2021-9-23       Wayne        First version
9 *
10 ******************************************************************************/
11 
12 #include <rtconfig.h>
13 
14 #if defined(BSP_USING_EADC)
15 
16 #include <rtdevice.h>
17 #include "NuMicro.h"
18 
19 /* Private define --------------------------------------------------------------- */
20 #define DEF_EADC_MAX_CHANNEL_NUM     8
21 
22 enum
23 {
24     EADC_START = -1,
25 #if defined(BSP_USING_EADC0)
26     EADC0_IDX,
27 #endif
28     EADC_CNT
29 };
30 
31 /* Private Typedef -------------------------------------------------------------- */
32 struct nu_eadc
33 {
34     struct rt_adc_device parent;
35     char                 *name;
36     EADC_T               *base;
37     uint32_t              rstidx;
38     uint32_t              modid;
39     uint32_t              chnmask;
40 };
41 typedef struct nu_eadc *nu_eadc_t;
42 
43 /* Private functions ------------------------------------------------------------ */
44 static rt_err_t nu_eadc_enabled(struct rt_adc_device *device, rt_int8_t channel, rt_bool_t enabled);
45 static rt_err_t nu_get_eadc_value(struct rt_adc_device *device, rt_int8_t channel, rt_uint32_t *value);
46 
47 /* Public functions ------------------------------------------------------------ */
48 int rt_hw_eadc_init(void);
49 
50 /* Private variables ------------------------------------------------------------ */
51 
52 static struct nu_eadc nu_eadc_arr [] =
53 {
54 #if defined(BSP_USING_EADC0)
55     { .name = "eadc0", .base = EADC0, .rstidx = EADC0_RST, .modid = EADC0_MODULE, .chnmask = 0 },
56 #endif
57 };
58 
59 static const struct rt_adc_ops nu_adc_ops =
60 {
61     nu_eadc_enabled,
62     nu_get_eadc_value,
63 };
64 typedef struct rt_adc_ops *rt_adc_ops_t;
65 
66 
67 /* nu_adc_enabled - Enable ADC clock and wait for ready */
nu_eadc_enabled(struct rt_adc_device * device,rt_int8_t channel,rt_bool_t enabled)68 static rt_err_t nu_eadc_enabled(struct rt_adc_device *device, rt_int8_t channel, rt_bool_t enabled)
69 {
70     nu_eadc_t psNuEadc = (nu_eadc_t)device;
71     RT_ASSERT(device != RT_NULL);
72 
73     if (channel >= DEF_EADC_MAX_CHANNEL_NUM)
74         return -(RT_EINVAL);
75 
76     if (enabled)
77     {
78         if (psNuEadc->chnmask == 0)
79         {
80             /* Invoke Open function at first call. */
81             EADC_Open(psNuEadc->base, EADC_CTL_DIFFEN_SINGLE_END);
82         }
83         psNuEadc->chnmask |= (1 << channel);
84     }
85     else
86     {
87         psNuEadc->chnmask &= ~(1 << channel);
88 
89         if (psNuEadc->chnmask == 0)
90         {
91             /* Invoke Open function at last call. */
92             EADC_Close(psNuEadc->base);
93         }
94     }
95 
96     return RT_EOK;
97 }
98 
nu_get_eadc_value(struct rt_adc_device * device,rt_int8_t channel,rt_uint32_t * value)99 static rt_err_t nu_get_eadc_value(struct rt_adc_device *device, rt_int8_t channel, rt_uint32_t *value)
100 {
101     nu_eadc_t psNuEadc = (nu_eadc_t)device;
102 
103     RT_ASSERT(device != RT_NULL);
104     RT_ASSERT(value != RT_NULL);
105 
106     if (channel >= DEF_EADC_MAX_CHANNEL_NUM)
107     {
108         *value = 0xFFFFFFFF;
109         return -(RT_EINVAL);
110     }
111 
112     if ((psNuEadc->chnmask & (1 << channel)) == 0)
113     {
114         *value = 0xFFFFFFFF;
115         return -(RT_EBUSY);
116     }
117 
118     EADC_ConfigSampleModule(psNuEadc->base, 0, EADC_SOFTWARE_TRIGGER, channel);
119 
120     EADC_CLR_INT_FLAG(psNuEadc->base, EADC_STATUS2_ADIF0_Msk);
121 
122     EADC_ENABLE_INT(psNuEadc->base, BIT0);
123 
124     EADC_ENABLE_SAMPLE_MODULE_INT(psNuEadc->base, 0, BIT0);
125 
126     EADC_START_CONV(psNuEadc->base, BIT0);
127 
128     while (EADC_GET_INT_FLAG(psNuEadc->base, BIT0) == 0);
129 
130     *value = EADC_GET_CONV_DATA(psNuEadc->base, 0);
131 
132     return RT_EOK;
133 }
134 
rt_hw_eadc_init(void)135 int rt_hw_eadc_init(void)
136 {
137     int i;
138     rt_err_t ret = RT_EOK;
139 
140     for (i = (EADC_START + 1); i < EADC_CNT; i++)
141     {
142         CLK_EnableModuleClock(nu_eadc_arr[i].modid);
143         SYS_ResetModule(nu_eadc_arr[i].rstidx);
144 
145         ret = rt_hw_adc_register(&nu_eadc_arr[i].parent, nu_eadc_arr[i].name, &nu_adc_ops, &nu_eadc_arr[i]);
146         RT_ASSERT(ret == RT_EOK);
147     }
148 
149     return (int)ret;
150 }
151 INIT_BOARD_EXPORT(rt_hw_eadc_init);
152 
153 #endif /* #if defined(BSP_USING_EADC) */
154