1 /**************************************************************************//**
2 * @file kpi.c
3 * @version V3.00
4 * @brief KPI driver source file
5 *
6 * @copyright SPDX-License-Identifier: Apache-2.0
7 * @copyright (C) 2021 Nuvoton Technology Corp. All rights reserved.
8 *****************************************************************************/
9
10 #include <stdio.h>
11 #include "NuMicro.h"
12
13 /** @addtogroup Standard_Driver Standard Driver
14 @{
15 */
16
17 /** @addtogroup KPI_Driver KPI Driver
18 @{
19 */
20
21 /** @addtogroup KPI_EXPORTED_FUNCTIONS KPI Exported Functions
22 @{
23 */
24
25 static KPI_KEY_T *s_pKeyQueue = 0;
26 static volatile uint32_t s_u32MaxKeyCnt = 0;
27 static volatile uint32_t s_u32FirstKey = 0;
28 static volatile uint32_t s_u32LastKey = 0;
29
KPI_KeyHandler(KPI_KEY_T key)30 __WEAK void KPI_KeyHandler(KPI_KEY_T key)
31
32 {
33 uint32_t u32Next;
34
35 /* Move last to next available space */
36 u32Next = s_u32LastKey + 1;
37 if(u32Next >= s_u32MaxKeyCnt)
38 u32Next = 0; // buffer wrap
39 if(u32Next == s_u32FirstKey)
40 return; // Queue full
41
42 /* Push key to the queue */
43 s_pKeyQueue[s_u32LastKey] = key;
44 s_u32LastKey = u32Next;
45
46 }
47
48
KPI_IRQHandler()49 void KPI_IRQHandler()
50 {
51 int32_t i,j, idx, r;
52 uint32_t u32KeyPress[2], u32KeyRelease[2], status;
53 uint32_t row, col, mask;
54 KPI_KEY_T key;
55
56 /* cache key events ASAP */
57 status = KPI->STATUS;
58 u32KeyPress[0] = KPI->KPF[0];
59 u32KeyPress[1] = KPI->KPF[1];
60 u32KeyRelease[0] = KPI->KRF[0];
61 u32KeyRelease[1] = KPI->KRF[1];
62
63 if(status & KPI_STATUS_KIF_Msk)
64 {
65 /* Get current row/column setting */
66 row = ((KPI->CTL & KPI_CTL_KROW_Msk) >> KPI_CTL_KROW_Pos) + 1;
67 col = ((KPI->CTL & KPI_CTL_KCOL_Msk) >> KPI_CTL_KCOL_Pos) + 1;
68
69 /* Deal with the key evernts */
70 for(i=0;i<row;i++)
71 {
72 for(j=0;j<col;j++)
73 {
74 /* Identify the specified key bit */
75 idx = (i < 4)?0:1;
76 r = i - idx * 4;
77 mask = 1ul << (r*8+j);
78
79 /* Key Release */
80 if(status & KPI_STATUS_KRIF_Msk)
81 {
82 if(u32KeyRelease[idx] & mask)
83 {
84 /* Clean event */
85 KPI->KRF[idx] = mask;
86
87 /* Record the key */
88 key.x = i;
89 key.y = j;
90 key.st= KPI_RELEASE;
91
92 /* call handler */
93 KPI_KeyHandler(key);
94 }
95 }
96 }
97 }
98
99 /* Deal with the key evernts */
100 for(i=0;i<row;i++)
101 {
102 for(j=0;j<col;j++)
103 {
104 /* Identify the specified key bit */
105 idx = (i < 4)?0:1;
106 r = i - idx * 4;
107 mask = 1ul << (r*8+j);
108
109
110 /* Key Press */
111 if(status & KPI_STATUS_KPIF_Msk)
112 {
113 if(u32KeyPress[idx] & mask)
114 {
115 /* Clean event */
116 KPI->KPF[idx] = mask;
117
118 /* Record the key */
119 key.x = i;
120 key.y = j;
121 key.st= KPI_PRESS;
122
123 /* call handler */
124 KPI_KeyHandler(key);
125 }
126 }
127 }
128 }
129 }
130
131 if(status & KPI_STATUS_TKRIF_Msk)
132 {
133 /* Clear flag */
134 KPI->STATUS = KPI_STATUS_TKRIF_Msk;
135
136 printf("Three key press!!\n");
137
138 }
139
140 }
141
142
143
144 /**
145 * @brief Open Keypad interface
146 *
147 * @param[in] u32Rows The number of key rows for key scan. it could be 2 ~ 6.
148 * @param[in] u32Columns The number of key columns for key scan. it could be 1 ~ 8.
149 * @param[in] pkeyQueue The FIFO queue of the key press/release status.
150 * @param[in] u32MaxKeyCnt Maximum key counts in the key queue.
151 *
152 * @retval 0 Sucessful
153 * @retval -1 Failure
154 *
155 * @details The function is used to set row and column of keypad and start to key scan.
156 */
KPI_Open(uint32_t u32Rows,uint32_t u32Columns,KPI_KEY_T * pkeyQueue,uint32_t u32MaxKeyCnt)157 int32_t KPI_Open(uint32_t u32Rows, uint32_t u32Columns, KPI_KEY_T *pkeyQueue, uint32_t u32MaxKeyCnt)
158 {
159 /* Key ROW limitation */
160 if((u32Rows < 2) || (u32Rows > 6))
161 return -1;
162
163 /* Key COLUMN limitation */
164 if(u32Columns > 8)
165 return -1;
166
167 /* Reset KPI */
168 SYS->IPRST3 |= SYS_IPRST3_KPIRST_Msk;
169 SYS->IPRST3 ^= SYS_IPRST3_KPIRST_Msk;
170
171 /* Set KPI */
172 KPI->CTL = ((u32Rows-1) << KPI_CTL_KROW_Pos) | ((u32Columns-1) << KPI_CTL_KCOL_Pos) |
173 KPI_CTL_KIEN_Msk | KPI_CTL_KPIEN_Msk | KPI_CTL_KRIEN_Msk |
174 (3 << KPI_CTL_DBCLKSEL_Pos) |
175 KPI_CTL_KPEN_Msk;
176
177 NVIC_EnableIRQ(KPI_IRQn);
178
179 /* Set up the queue of key */
180 s_pKeyQueue = pkeyQueue;
181 s_u32MaxKeyCnt = u32MaxKeyCnt;
182 s_u32FirstKey = 0;
183 s_u32LastKey = 0;
184
185 return 0;
186 }
187
188 /**
189 * @brief Close Keypad interface
190 *
191 * @details The function is used to stop and close key pad.
192 */
193
KPI_Close()194 void KPI_Close()
195 {
196 /* Disable Keypad */
197 KPI->CTL = 0;
198 }
199
200
201 /**
202 * @brief Detect any key press
203 *
204 *
205 * @retval 1 Key pressed
206 * @retval 0 No key pressed
207 *
208 * @details The function is used to check if any key pressed.
209 */
KPI_kbhit()210 int32_t KPI_kbhit()
211 {
212 if(s_u32FirstKey != s_u32LastKey)
213 return 1;
214 return 0;
215 }
216
217
218 /**
219 * @brief Get pressed/released key
220 *
221 * @return return the pressed key information. If no key pressed, return key index is 0xff, 0xff.
222 *
223 * @details The function is get the key pressed or key released.
224 */
KPI_GetKey()225 KPI_KEY_T KPI_GetKey()
226 {
227 KPI_KEY_T key = {0xff,0xff,0xffff};
228
229 /* Check if queue is empty */
230 if(s_u32FirstKey != s_u32LastKey)
231 {
232 /* Pop the key from queue */
233 key = s_pKeyQueue[s_u32FirstKey++];
234
235 /* Wrap around check */
236 if(s_u32FirstKey >= s_u32MaxKeyCnt)
237 s_u32FirstKey = 0;
238 }
239
240 return key;
241 }
242
243
244 /**
245 * @brief Set key sample time
246 *
247 * @param[in] ms The key sample time in milliseconds.
248 *
249 * @details The function is used to set key sample time. The maximum time is 1398 milliseconds.
250 */
KPI_SetSampleTime(uint32_t ms)251 void KPI_SetSampleTime(uint32_t ms)
252 {
253 uint32_t freq[] = {__HXT, __LIRC, __HIRC, 0};
254
255 if(ms >= 1398)
256 ms = 1398;
257
258 KPI->DLYCTL = 0x1F | ((freq[(CLK->CLKSEL3 & CLK_CLKSEL3_KPISEL_Msk) >> CLK_CLKSEL3_KPISEL_Pos] / 1000)*ms << 8);
259 }
260
261
262 /**
263 * @brief Set key scan timing for internal pull-up
264 *
265 * @details The internal pull-up is weak and slow. To use it, the key scan timing need to slow down.
266 */
KPI_EnableSlowScan()267 void KPI_EnableSlowScan()
268 {
269 /* It is slow enough when using LIRC clock source */
270 if((CLK->CLKSEL3 & CLK_CLKSEL3_KPISEL_Msk) == CLK_CLKSEL3_KPISEL_LIRC)
271 return;
272
273 KPI->CTL = (KPI->CTL & (~KPI_CTL_DBCLKSEL_Msk)) | (5 << KPI_CTL_DBCLKSEL_Pos);
274 KPI->DLYCTL = (KPI->DLYCTL & (~0xff)) | 127;
275 }
276
277
278
279
280 /*@}*/ /* end of group KPI_EXPORTED_FUNCTIONS */
281
282 /*@}*/ /* end of group KPI_Driver */
283
284 /*@}*/ /* end of group Standard_Driver */
285