1 /**************************************************************************//**
2 *
3 * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Change Logs:
8 * Date            Author       Notes
9 * 2021-10-21      Wayne        First version
10 *
11 ******************************************************************************/
12 
13 #include <rtconfig.h>
14 
15 #if defined(BSP_USING_QEI)
16 
17 #include <rtdevice.h>
18 #include "drv_sys.h"
19 #include "drv_common.h"
20 
21 /* Private define ---------------------------------------------------------------*/
22 enum
23 {
24     QEI_START = -1,
25 #if defined(BSP_USING_QEI0)
26     QEI0_START,
27 #endif
28 #if defined(BSP_USING_QEI1)
29     QEI1_START,
30 #endif
31 #if defined(BSP_USING_QEI2)
32     QEI2_START,
33 #endif
34     QEI_CNT
35 };
36 
37 /* Private typedef --------------------------------------------------------------*/
38 struct nu_qei
39 {
40     struct rt_pulse_encoder_device dev;
41     char *name;
42     QEI_T *base;
43     IRQn_Type   irqn;
44     uint32_t    rstidx;
45     uint32_t    modid;
46 
47     rt_uint32_t max_cntval;
48     rt_uint32_t cmp_val;
49     rt_uint8_t  qei_flag;
50 };
51 typedef struct nu_qei *nu_qei_t;
52 
53 /* Private functions ------------------------------------------------------------*/
54 static rt_uint32_t nu_qei_type(struct rt_pulse_encoder_device *pulse_encoder);
55 static rt_err_t nu_qei_init(struct rt_pulse_encoder_device *pulse_encoder);
56 static rt_int32_t nu_qei_get_count(struct rt_pulse_encoder_device *pulse_encoder);
57 static rt_err_t nu_qei_clear_count(struct rt_pulse_encoder_device *pulse_encoder);
58 static rt_err_t nu_qei_control(struct rt_pulse_encoder_device *pulse_encoder, rt_uint32_t cmd, void *args);
59 
60 /* Public functions -------------------------------------------------------------*/
61 rt_int32_t nu_qei_get_maxval(struct rt_pulse_encoder_device *pulse_encoder);
62 rt_int32_t nu_qei_get_cmpval(struct rt_pulse_encoder_device *pulse_encoder);
63 rt_int32_t nu_qei_get_type(struct rt_pulse_encoder_device *pulse_encoder);
64 void nu_qei_set_maxval_type(struct rt_pulse_encoder_device *pulse_encoder, rt_uint32_t u32val, rt_uint8_t u8type);
65 void nu_qei_set_cmpval(struct rt_pulse_encoder_device *pulse_encoder, rt_uint32_t u32val);
66 
67 /* Private variables ------------------------------------------------------------*/
68 static struct nu_qei nu_qei_arr [] =
69 {
70 #if defined(BSP_USING_QEI0)
71     {
72         .name = "qei0",
73         .base = QEI0,
74         .irqn = QEI0_IRQn,
75         .rstidx = QEI0_RST,
76         .modid  = QEI0_MODULE,
77 
78         .max_cntval = 1000,
79         .cmp_val = 100,
80     },
81 #endif
82 
83 #if defined(BSP_USING_QEI1)
84     {
85         .name = "qei1",
86         .base = QEI1,
87         .irqn = QEI1_IRQn,
88         .rstidx = QEI1_RST,
89         .modid  = QEI1_MODULE,
90 
91         .max_cntval = 1000,
92         .cmp_val = 100,
93     },
94 #endif
95 
96 #if defined(BSP_USING_QEI2)
97     {
98         .name = "qei2",
99         .base = QEI2,
100         .irqn = QEI2_IRQn,
101         .rstidx = QEI2_RST,
102         .modid  = QEI2_MODULE,
103 
104         .max_cntval = 1000,
105         .cmp_val = 100,
106     },
107 #endif
108 };
109 
110 static const struct rt_pulse_encoder_ops nu_qei_ops =
111 {
112     .init = nu_qei_init,
113     .get_count = nu_qei_get_count,
114     .clear_count = nu_qei_clear_count,
115     .control = nu_qei_control,
116 };
117 
118 /* Public variables -------------------------------------------------------------*/
nu_qei_type(struct rt_pulse_encoder_device * pulse_encoder)119 static rt_uint32_t nu_qei_type(struct rt_pulse_encoder_device *pulse_encoder)
120 {
121     rt_uint32_t u32type;
122     nu_qei_t psNuQei = (nu_qei_t)pulse_encoder;
123 
124     RT_ASSERT(pulse_encoder != RT_NULL);
125 
126     switch (pulse_encoder->type)
127     {
128     case SINGLE_PHASE_PULSE_ENCODER:
129         u32type = (psNuQei->cmp_val) ? QEI_CTL_X2_COMPARE_COUNTING_MODE : QEI_CTL_X2_FREE_COUNTING_MODE;
130         break;
131 
132     case UNKNOWN_PULSE_ENCODER_TYPE:
133     case AB_PHASE_PULSE_ENCODER:
134     default:
135         u32type = (psNuQei->cmp_val) ? QEI_CTL_X4_COMPARE_COUNTING_MODE : QEI_CTL_X4_FREE_COUNTING_MODE;
136         break;
137     }
138 
139     return u32type;
140 }
141 
nu_qei_set_cmpval(struct rt_pulse_encoder_device * pulse_encoder,rt_uint32_t u32val)142 void nu_qei_set_cmpval(struct rt_pulse_encoder_device *pulse_encoder, rt_uint32_t u32val)
143 {
144     nu_qei_t psNuQei = (nu_qei_t)pulse_encoder;
145 
146     RT_ASSERT(pulse_encoder != RT_NULL);
147 
148     QEI_SET_CNT_CMP(psNuQei->base, u32val);
149     if (u32val > 0)
150     {
151         QEI_EnableInt(psNuQei->base, QEI_CTL_CMPIEN_Msk);
152         QEI_ENABLE_CNT_CMP(psNuQei->base);
153         rt_hw_interrupt_umask(psNuQei->irqn);
154     }
155     else
156     {
157         QEI_DisableInt(psNuQei->base, QEI_CTL_CMPIEN_Msk);
158         QEI_DISABLE_CNT_CMP(psNuQei->base);
159         rt_hw_interrupt_mask(psNuQei->irqn);
160     }
161 }
162 
nu_qei_init(struct rt_pulse_encoder_device * pulse_encoder)163 static rt_err_t nu_qei_init(struct rt_pulse_encoder_device *pulse_encoder)
164 {
165     nu_qei_t psNuQei = (nu_qei_t)pulse_encoder;
166 
167     RT_ASSERT(pulse_encoder != RT_NULL);
168 
169     /* enable noise filter */
170     QEI_ENABLE_NOISE_FILTER(psNuQei->base, QEI_CTL_NFCLKSEL_DIV2);
171 
172     /* set compare value and interrupt */
173     nu_qei_set_cmpval(pulse_encoder, psNuQei->cmp_val);
174 
175     /* set qei mode */
176     QEI_Open(psNuQei->base, nu_qei_type(pulse_encoder), psNuQei->max_cntval);
177 
178     return RT_EOK;
179 }
180 
nu_qei_get_count(struct rt_pulse_encoder_device * pulse_encoder)181 static rt_int32_t nu_qei_get_count(struct rt_pulse_encoder_device *pulse_encoder)
182 {
183     nu_qei_t psNuQei = (nu_qei_t)pulse_encoder;
184     RT_ASSERT(pulse_encoder != RT_NULL);
185     return (rt_int32_t)QEI_GET_CNT_VALUE(psNuQei->base);
186 }
187 
nu_qei_clear_count(struct rt_pulse_encoder_device * pulse_encoder)188 static rt_err_t nu_qei_clear_count(struct rt_pulse_encoder_device *pulse_encoder)
189 {
190     nu_qei_t psNuQei = (nu_qei_t)pulse_encoder;
191     RT_ASSERT(pulse_encoder != RT_NULL);
192 
193     QEI_Stop(psNuQei->base);
194     QEI_SET_CNT_VALUE(psNuQei->base, 0);
195     QEI_Start(psNuQei->base);
196 
197     return RT_EOK;
198 }
199 
nu_qei_control(struct rt_pulse_encoder_device * pulse_encoder,rt_uint32_t cmd,void * args)200 static rt_err_t nu_qei_control(struct rt_pulse_encoder_device *pulse_encoder, rt_uint32_t cmd, void *args)
201 {
202     rt_err_t result = RT_EOK;
203     nu_qei_t psNuQei = (nu_qei_t)pulse_encoder;
204 
205     RT_ASSERT(pulse_encoder != RT_NULL);
206 
207     switch (cmd)
208     {
209     case PULSE_ENCODER_CMD_ENABLE:
210         /* set compare value and interrupt */
211         QEI_Start(psNuQei->base);
212         nu_qei_set_cmpval(pulse_encoder, psNuQei->cmp_val);
213         break;
214     case PULSE_ENCODER_CMD_DISABLE:
215         QEI_Stop(psNuQei->base);
216         nu_qei_set_cmpval(pulse_encoder, 0);
217         break;
218     default:
219         result = -RT_ENOSYS;
220         break;
221     }
222 
223     return result;
224 }
225 
nu_qei_isr(int vector,void * param)226 static void nu_qei_isr(int vector, void *param)
227 {
228     nu_qei_t psNuQei = (nu_qei_t)param;
229 
230     if (QEI_GET_INT_FLAG(psNuQei->base, QEI_STATUS_CMPF_Msk))
231     {
232         QEI_CLR_INT_FLAG(psNuQei->base, QEI_STATUS_CMPF_Msk);
233         rt_kprintf("%s: CMP flag rising\n", psNuQei->name) ;
234     }
235 }
236 
nu_qei_get_maxval(struct rt_pulse_encoder_device * pulse_encoder)237 rt_int32_t nu_qei_get_maxval(struct rt_pulse_encoder_device *pulse_encoder)
238 {
239     nu_qei_t psNuQei = (nu_qei_t)pulse_encoder;
240     RT_ASSERT(pulse_encoder != RT_NULL);
241 
242     return psNuQei->max_cntval;
243 }
244 
nu_qei_get_cmpval(struct rt_pulse_encoder_device * pulse_encoder)245 rt_int32_t nu_qei_get_cmpval(struct rt_pulse_encoder_device *pulse_encoder)
246 {
247     nu_qei_t psNuQei = (nu_qei_t)pulse_encoder;
248     RT_ASSERT(pulse_encoder != RT_NULL);
249 
250     return psNuQei->cmp_val;
251 }
252 
nu_qei_get_type(struct rt_pulse_encoder_device * pulse_encoder)253 rt_int32_t nu_qei_get_type(struct rt_pulse_encoder_device *pulse_encoder)
254 {
255     RT_ASSERT(pulse_encoder != RT_NULL);
256     return nu_qei_type(pulse_encoder);
257 }
258 
nu_qei_set_maxval_type(struct rt_pulse_encoder_device * pulse_encoder,rt_uint32_t u32val,enum rt_pulse_encoder_type eType)259 void nu_qei_set_maxval_type(struct rt_pulse_encoder_device *pulse_encoder, rt_uint32_t u32val, enum rt_pulse_encoder_type eType)
260 {
261     nu_qei_t psNuQei = (nu_qei_t)pulse_encoder;
262 
263     RT_ASSERT(pulse_encoder != RT_NULL);
264     RT_ASSERT(eType <= AB_PHASE_PULSE_ENCODER);
265 
266     psNuQei->dev.type = eType;
267     psNuQei->max_cntval = u32val;
268     QEI_Open(psNuQei->base, nu_qei_type(&psNuQei->dev), u32val);
269 }
270 
rt_hw_qei_init(void)271 int rt_hw_qei_init(void)
272 {
273     int i;
274     rt_err_t result = RT_EOK;
275 
276     for (i = (QEI_START + 1); i < QEI_CNT; i++)
277     {
278         nu_qei_t psNuQei = &nu_qei_arr[i];
279 
280         psNuQei->dev.type = AB_PHASE_PULSE_ENCODER;
281         psNuQei->dev.ops = &nu_qei_ops;
282 
283         /* Enable QEI module */
284         CLK_EnableModuleClock(psNuQei->modid);
285         SYS_ResetModule(psNuQei->rstidx);
286 
287         /* register isr */
288         rt_hw_interrupt_install(psNuQei->irqn, nu_qei_isr, psNuQei, psNuQei->name);
289 
290         result = rt_device_pulse_encoder_register((struct rt_pulse_encoder_device *)&nu_qei_arr[i].dev, nu_qei_arr[i].name, RT_NULL);
291         RT_ASSERT(result == RT_EOK);
292     }
293 
294     return (int)result;
295 }
296 INIT_APP_EXPORT(rt_hw_qei_init);
297 
298 #endif /* BSP_USING_QEI */
299