1 /* Copyright (C) 2011 by Jacob Alexander
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:
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
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
22 // ----- Includes -----
26 #include <util/delay.h>
32 #include "matrix_scan.h"
34 // Matrix Configuration
41 // -- pinSetup Macros --
42 #define REG_SET(reg) reg |= (1 << ( matrix[row*(MAX_ROW_SIZE+1)+col] % 10 ) ) // Modulo 10 for the define offset for each pin set 12 or 32 -> shift of 2
43 #define REG_UNSET(reg) reg &= ~(1 << ( matrix[row*(MAX_ROW_SIZE+1)+col] % 10 ) )
45 #define PIN_SET(pin,scan,direction) \
46 switch ( direction ) { \
47 case columnSet: PIN_SET_COL(pin,scan); \
48 case rowSet: PIN_SET_ROW(pin,scan); \
52 // TODO Only scanCol_powrRow Tested (and powrRow)
53 #define PIN_SET_COL(pin,scan) \
56 case scanRow_powrCol: \
58 REG_SET(port##pin); break; \
59 case scanCol_powrRow: REG_UNSET(ddr##pin); REG_UNSET(DDR##pin); \
60 REG_SET(port##pin); REG_SET(PORT##pin); break; \
61 case powrRow: break; \
62 case powrCol: REG_SET(ddr##pin); REG_SET(DDR##pin); \
63 REG_SET(port##pin); REG_SET(PORT##pin); break; \
67 // TODO Only scanCol_powrRow Tested (and powrRow)
68 #define PIN_SET_ROW(pin,scan) \
70 case scanRow_powrCol: REG_UNSET(ddr##pin); REG_SET(port##pin); break; \
73 REG_SET(port##pin); break; \
74 case scanCol_powrRow: REG_SET(ddr##pin); REG_SET(DDR##pin); \
75 REG_UNSET(port##pin); REG_UNSET(PORT##pin); break; \
76 case powrRow: REG_SET(ddr##pin); REG_SET(DDR##pin); \
77 REG_SET(port##pin); REG_SET(PORT##pin); break; \
78 case powrCol: break; \
82 #define PIN_CASE(pinLetter) \
83 case pin##pinLetter##0: \
84 case pin##pinLetter##1: \
85 case pin##pinLetter##2: \
86 case pin##pinLetter##3: \
87 case pin##pinLetter##4: \
88 case pin##pinLetter##5: \
89 case pin##pinLetter##6: \
90 case pin##pinLetter##7
92 // -- Column Scan Macros --
93 #define PIN_TEST_COL(pin) \
94 scanCode = matrix[row*(MAX_ROW_SIZE+1)+col]; \
95 if ( scanCode && !( pin & ( 1 << ( matrix[0*(MAX_ROW_SIZE+1)+col] % 10 ) ) ) ) \
97 detectArray[scanCode]++; \
101 // -- Row Scan Macros --
102 #define PIN_TEST_ROW(pin) \
103 scanCode = matrix[row*(MAX_ROW_SIZE+1)+col]; \
104 if ( scanCode && !( pin & ( 1 << ( matrix[row*(MAX_ROW_SIZE+1)+0] % 10 ) ) ) ) \
106 detectArray[scanCode]++; \
110 // -- Scan Dual Macros --
111 #define PIN_DUALTEST_ROW(pin) \
112 scanCode = matrix[row*(MAX_ROW_SIZE+1)+col]; \
114 && !( pin & ( 1 << ( matrix[row*(MAX_ROW_SIZE+1)+0] % 10 ) ) ) \
115 && detectArray[scanCode] & 0x01 ) \
117 detectArray[scanCode]++; \
121 if ( detectArray[scanCode] & 0x01 ) \
122 detectArray[scanCode]--; \
128 // ----- Variables -----
129 uint8_t showDebug = 0;
131 // Debug Variables for GPIO setting
132 uint8_t portA = 0x00;
133 uint8_t portB = 0x00;
134 uint8_t portC = 0x00;
135 uint8_t portD = 0x00;
136 uint8_t portE = 0x00;
137 uint8_t portF = 0x00;
147 // ----- Functions -----
149 inline void matrix_debugPins()
152 info_print("Initial Matrix Pin Setup");
153 info_print(" ddrA ddrB ddrC ddrD ddrE ddrF");
155 hexToStr_op( ddrA, tmpStr, 2 ); dPrintStrs( " 0x", tmpStr );
156 hexToStr_op( ddrB, tmpStr, 2 ); dPrintStrs( " 0x", tmpStr );
157 hexToStr_op( ddrC, tmpStr, 2 ); dPrintStrs( " 0x", tmpStr );
158 hexToStr_op( ddrD, tmpStr, 2 ); dPrintStrs( " 0x", tmpStr );
159 hexToStr_op( ddrE, tmpStr, 2 ); dPrintStrs( " 0x", tmpStr );
160 hexToStr_op( ddrF, tmpStr, 2 ); dPrintStrs( " 0x", tmpStr );
162 info_print("portA portB portC portD portE portF");
164 hexToStr_op( portA, tmpStr, 2 ); dPrintStrs( " 0x", tmpStr );
165 hexToStr_op( portB, tmpStr, 2 ); dPrintStrs( " 0x", tmpStr );
166 hexToStr_op( portC, tmpStr, 2 ); dPrintStrs( " 0x", tmpStr );
167 hexToStr_op( portD, tmpStr, 2 ); dPrintStrs( " 0x", tmpStr );
168 hexToStr_op( portE, tmpStr, 2 ); dPrintStrs( " 0x", tmpStr );
169 hexToStr_op( portF, tmpStr, 2 ); dPrintStrs( " 0x", tmpStr );
177 inline void matrix_columnSet( uint8_t *matrix, uint8_t scanType, uint16_t startIndex, uint16_t colsToIterate )
179 // Calculate the number of pins to iterate over
180 uint8_t maxColumns = startIndex + colsToIterate - 1;
181 if ( maxColumns > MAX_COL_SIZE )
182 maxColumns = MAX_COL_SIZE;
187 for ( col = startIndex, row = 0; col <= maxColumns; col++ )
189 // We can't pass 2D arrays, so just point to the first element and calculate directly
190 switch ( matrix[row*(MAX_ROW_SIZE+1)+col] )
192 #if defined(__AVR_AT90USB1286__)
194 PIN_SET(A, scanType, columnSet);
197 PIN_SET(B, scanType, columnSet);
199 PIN_SET(C, scanType, columnSet);
201 PIN_SET(D, scanType, columnSet);
203 PIN_SET(E, scanType, columnSet);
205 PIN_SET(F, scanType, columnSet);
214 inline void matrix_rowSet( uint8_t *matrix, uint8_t scanType, uint16_t startIndex, uint8_t rowsToIterate )
216 // Calculate the number of pins to iterate over
217 uint16_t maxRows = startIndex + rowsToIterate - 1;
218 if ( maxRows > MAX_ROW_SIZE )
219 maxRows = MAX_ROW_SIZE;
224 for ( col = 0, row = startIndex; row <= maxRows; row++ )
226 // We can't pass 2D arrays, so just point to the first element and calculate directly
227 switch ( matrix[row*(MAX_ROW_SIZE+1)+col] )
229 #if defined(__AVR_AT90USB1286__)
231 PIN_SET(A, scanType, rowSet);
234 PIN_SET(B, scanType, rowSet);
236 PIN_SET(C, scanType, rowSet);
238 PIN_SET(D, scanType, rowSet);
240 PIN_SET(E, scanType, rowSet);
242 PIN_SET(F, scanType, rowSet);
251 // Goes through the defined matrix and matrix mode, and sets the initial state of all of the available pins
252 void matrix_pinSetup( uint8_t *matrix, uint8_t scanType )
254 // Loop through all the pin assignments, for the initial pin settings
255 matrix_rowSet ( matrix, scanType, 1, MAX_ROW_SIZE );
256 matrix_columnSet( matrix, scanType, 1, MAX_COL_SIZE );
259 if ( showDebug == 0 ) // Only show once
265 // Scans the given matrix determined by the scanMode method
266 inline void matrix_scan( uint8_t *matrix, uint8_t *detectArray )
268 // Loop variables for all modes
271 uint16_t scanCode = 0;
274 // TODO Only scanCol_powrRow tested
275 // Column Scan and Column Scan, Power Row
276 #if scanMode == scanCol || scanMode == scanCol_powrRow
277 for ( ; row <= MAX_ROW_SIZE; row++ )
279 // Power each row separately
280 matrix_rowSet( matrix, powrRow, row, 1 );
282 for ( col = 1; col <= MAX_COL_SIZE; col++ )
284 // Scan over the pins for each of the columns, and using the pin alias to determine which pin to set
285 // (e.g. / 10 is for the pin name (A,B,C,etc.) and % 10 is for the position of the pin (A1,A2,etc.))
286 switch ( matrix[0*(MAX_ROW_SIZE+1)+col] / 10 )
288 #if defined(__AVR_AT90USB1286__)
305 // Unset the row power
306 matrix_rowSet( matrix, scanMode, row, 1 );
311 // Row Scan and Row Scan, Power Row
312 #if scanMode == scanRow || scanMode == scanRow_powrCol
313 for ( ; col <= MAX_COL_SIZE; col++ )
315 // Power each column separately
316 matrix_columnSet( matrix, powrCol, col, 1 );
318 for ( row = 1; row <= MAX_ROW_SIZE; row++ )
320 // Scan over the pins for each of the rows, and using the pin alias to determine which pin to set
321 // (e.g. / 10 is for the pin name (A,B,C,etc.) and % 10 is for the position of the pin (A1,A2,etc.))
322 switch ( matrix[row*(MAX_ROW_SIZE+1)+0] / 10 )
324 #if defined(__AVR_AT90USB1286__)
341 // Unset the column power
342 matrix_columnSet( matrix, scanMode, col, 1 );
348 #if scanMode == scanDual
349 // First do a scan of all of the columns, marking each one
350 matrix_pinSetup( matrix, scanCol_powrRow, 0, MAX_ROW_SIZE, MAX_COL_SIZE );
352 for ( ; row < (MAX_COL_SIZE+1); row++ ) for ( ; col < (MAX_ROW_SIZE+1); col++ )
354 // Scan over the pins for each of the columns, and using the pin alias to determine which pin to set
355 // (e.g. / 10 is for the pin name (A,B,C,etc.) and % 10 is for the position of the pin (A1,A2,etc.))
356 switch ( matrix[0*(MAX_ROW_SIZE+1)+col] / 10 )
358 #if defined(__AVR_AT90USB1286__)
375 // Next, do a scan of all of the rows, clearing any "vague" keys (only detected on row, but not column, or vice-versa)
376 // And marking any keys that are detected on the row and column
377 matrix_pinSetup( matrix, scanRow_powrCol, 0, MAX_ROW_SIZE, MAX_COL_SIZE );
381 for ( ; col < (MAX_ROW_SIZE+1); col++ ) for ( ; row < (MAX_COL_SIZE+1); row++ )
383 // Scan over the pins for each of the rows, and using the pin alias to determine which pin to set
384 // (e.g. / 10 is for the pin name (A,B,C,etc.) and % 10 is for the position of the pin (A1,A2,etc.))
385 switch ( matrix[row*(MAX_ROW_SIZE+1)+0] / 10 )
387 #if defined(__AVR_AT90USB1286__)
389 PIN_DUALTEST_ROW(PINA);
392 PIN_DUALTEST_ROW(PINB);
394 PIN_DUALTEST_ROW(PINC);
396 PIN_DUALTEST_ROW(PIND);
398 PIN_DUALTEST_ROW(PINE);
400 PIN_DUALTEST_ROW(PINF);