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