]> git.donarmstrong.com Git - kiibohd-controller.git/blob - Scan/MatrixARM/matrix_scan.c
Initial MatrixARM implementation
[kiibohd-controller.git] / Scan / MatrixARM / matrix_scan.c
1 /* Copyright (C) 2014 by Jacob Alexander
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a copy
4  * of this software and associated documentation files (the "Software"), to deal
5  * in the Software without restriction, including without limitation the rights
6  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7  * copies of the Software, and to permit persons to whom the Software is
8  * furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19  * THE SOFTWARE.
20  */
21
22 // ----- Includes -----
23
24 // Compiler Includes
25 #include <Lib/ScanLib.h>
26
27 // Project Includes
28 #include <cli.h>
29 #include <led.h>
30 #include <print.h>
31 #include <macro.h>
32
33 // Local Includes
34 #include "matrix_scan.h"
35
36 // Matrix Configuration
37 #include <matrix.h>
38
39
40
41 // ----- Variables -----
42
43 // Debounce Array
44 KeyState Matrix_scanArray[ Matrix_colsNum * Matrix_rowsNum ];
45
46
47
48 // ----- Functions -----
49
50 // Pin action (Strobe, Sense, Strobe Setup, Sense Setup)
51 // NOTE: This function is highly dependent upon the organization of the register map
52 //       Only guaranteed to work with Freescale MK20 series uCs
53 uint8_t Matrix_pin( GPIO_Pin gpio, Type type )
54 {
55         // Register width is defined as size of a pointer
56         uint8_t port_offset = (uint8_t)gpio.port * sizeof(unsigned int*);
57
58         // Assumes 6 registers between GPIO Port registers
59         volatile unsigned int GPIO_PDDR = *(&GPIOA_PDDR + port_offset * 6);
60         volatile unsigned int GPIO_PSOR = *(&GPIOA_PSOR + port_offset * 6);
61         volatile unsigned int GPIO_PCOR = *(&GPIOA_PCOR + port_offset * 6);
62         volatile unsigned int GPIO_PDIR = *(&GPIOA_PDIR + port_offset * 6);
63
64         // Assumes 35 registers between PORT pin registers
65         volatile unsigned int PORT_PCR = *(&PORTA_PCR0 + port_offset * 35);
66
67         // Operation depends on Type
68         switch ( type )
69         {
70         case Type_StrobeOn:
71                 GPIO_PSOR |= (1 << gpio.pin);
72                 break;
73
74         case Type_StrobeOff:
75                 GPIO_PCOR |= (1 << gpio.pin);
76                 break;
77
78         case Type_StrobeSetup:
79                 // Set as output pin
80                 GPIO_PDDR |= (1 << gpio.pin);
81
82                 // Configure pin with slow slew, high drive strength and GPIO mux
83                 PORT_PCR = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1);
84
85                 // Enabling open-drain if specified
86                 switch ( Matrix_type )
87                 {
88                 case Config_Opendrain:
89                         PORT_PCR |= PORT_PCR_ODE;
90                         break;
91
92                 // Do nothing otherwise
93                 default:
94                         break;
95                 }
96                 break;
97
98         case Type_Sense:
99                 return GPIO_PDIR & (1 << gpio.pin) ? 1 : 0;
100
101         case Type_SenseSetup:
102                 // Set as input pin
103                 GPIO_PDDR &= ~(1 << gpio.pin);
104
105                 // Configure pin with passive filter and GPIO mux
106                 PORT_PCR = PORT_PCR_PFE | PORT_PCR_MUX(1);
107
108                 // Pull resistor config
109                 switch ( Matrix_type )
110                 {
111                 case Config_Pullup:
112                         PORT_PCR |= PORT_PCR_PE | PORT_PCR_PS;
113                         break;
114
115                 case Config_Pulldown:
116                         PORT_PCR |= PORT_PCR_PE;
117                         break;
118
119                 // Do nothing otherwise
120                 default:
121                         break;
122                 }
123                 break;
124         }
125
126         return 0;
127 }
128
129 // Setup GPIO pins for matrix scanning
130 void Matrix_setup()
131 {
132         // Setup Strobe Pins
133         for ( uint8_t pin = 0; pin < Matrix_colsNum; pin++ )
134         {
135                 Matrix_pin( Matrix_cols[ pin ], Type_StrobeSetup );
136         }
137
138         // Setup Sense Pins
139         for ( uint8_t pin = 0; pin < Matrix_rowsNum; pin++ )
140         {
141                 Matrix_pin( Matrix_rows[ pin ], Type_SenseSetup );
142         }
143
144         // Clear out Debounce Array
145         for ( uint8_t item = 0; item < Matrix_maxKeys; item++ )
146         {
147                 Matrix_scanArray[ item ].prevState     = KeyState_Off;
148                 Matrix_scanArray[ item ].curState      = KeyState_Off;
149                 Matrix_scanArray[ item ].activeCount   = 0;
150                 Matrix_scanArray[ item ].inactiveCount = 0;
151         }
152 }
153
154 // Scan the matrix for keypresses
155 // NOTE: firstScan should be set on the first scan after a USB send (to reset all the counters)
156 void Matrix_scan( uint16_t scanNum, uint8_t firstScan )
157 {
158         // For each strobe, scan each of the sense pins
159         for ( uint8_t strobe = 0; strobe < Matrix_colsNum; strobe++ )
160         {
161                 // Strobe Pin
162                 Matrix_pin( Matrix_cols[ strobe ], Type_StrobeOn );
163
164                 // Scan each of the sense pins
165                 for ( uint8_t sense = 0; sense < Matrix_rowsNum; sense++ )
166                 {
167                         // Key position
168                         uint8_t key = Matrix_rowsNum * strobe + sense;
169                         KeyState *state = &Matrix_scanArray[ key ];
170
171                         // If first scan, reset state
172                         if ( firstScan )
173                         {
174                                 // Set previous state, and reset current state
175                                 state->prevState = state->curState;
176                                 state->curState  = KeyState_Invalid;
177                         }
178
179                         // Signal Detected
180                         if ( Matrix_pin( Matrix_rows[ sense ], Type_Sense ) )
181                         {
182                                 // Only update if not going to wrap around
183                                 state->activeCount   += state->activeCount   < 255 ? 1 : 0;
184                                 state->inactiveCount -= state->inactiveCount > 0   ? 1 : 0;
185                         }
186                         // Signal Not Detected
187                         else
188                         {
189                                 // Only update if not going to wrap around
190                                 state->inactiveCount += state->inactiveCount < 255 ? 1 : 0;
191                                 state->activeCount   -= state->activeCount   > 0   ? 1 : 0;
192                         }
193
194                         // Check for state change if it hasn't been set
195                         // Only check if the minimum number of scans has been met
196                         //   the current state is invalid
197                         //   and either active or inactive count is over the debounce threshold
198                         if ( scanNum > DEBOUNCE_THRESHOLD
199                           && state->curState != KeyState_Invalid
200                           && ( state->activeCount > DEBOUNCE_THRESHOLD || state->inactiveCount > DEBOUNCE_THRESHOLD ) )
201                         {
202                                 switch ( state->prevState )
203                                 {
204                                 case KeyState_Press:
205                                 case KeyState_Hold:
206                                         if ( state->activeCount > DEBOUNCE_THRESHOLD )
207                                         {
208                                                 state->curState = KeyState_Hold;
209                                         }
210                                         else
211                                         {
212                                                 state->curState = KeyState_Release;
213                                         }
214                                         break;
215
216                                 case KeyState_Release:
217                                 case KeyState_Off:
218                                         if ( state->activeCount > DEBOUNCE_THRESHOLD )
219                                         {
220                                                 state->curState = KeyState_Press;
221                                         }
222                                         else if ( state->inactiveCount > DEBOUNCE_THRESHOLD )
223                                         {
224                                                 state->curState = KeyState_Off;
225                                         }
226                                         break;
227
228                                 case KeyState_Invalid:
229                                         erro_print("Matrix scan bug!! Report me!");
230                                         break;
231                                 }
232
233                                 // Send keystate to macro module
234                                 Macro_keyState( key, state->curState );
235                         }
236                 }
237
238                 // Unstrobe Pin
239                 Matrix_pin( Matrix_cols[ strobe ], Type_StrobeOff );
240         }
241 }
242