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