changeset 187:b250056298df

Matrix scanning for ARM now functional. - CLI Debugging options added - Various bug fixes for the matrix scanning algorithm - Changed debouncing algorithm
author Jacob Alexander <haata@kiibohd.com>
date Sat, 02 Aug 2014 22:19:33 -0700
parents 50702debf278
children 3b28e5949c80
files Scan/MD1/matrix.h Scan/MD1/scan_loop.c Scan/MD1/scan_loop.h Scan/MatrixARM/matrix_scan.c Scan/MatrixARM/matrix_scan.h main.c
diffstat 6 files changed, 295 insertions(+), 107 deletions(-) [+]
line wrap: on
line diff
--- a/Scan/MD1/matrix.h	Fri Aug 01 01:26:25 2014 -0700
+++ b/Scan/MD1/matrix.h	Sat Aug 02 22:19:33 2014 -0700
@@ -51,15 +51,12 @@
 // Rows (Sense)
 //  PTD1..7
 
-// Debounce threshold
-#define DEBOUNCE_THRESHOLD 32
-
 // Define Rows (Sense) and Columns (Strobes)
-GPIO_Pin Matrix_cols[] = { gpio(B,0), gpio(B,1), gpio(B,2), gpio(B,3), gpio(B,16), gpio(B,17), gpio(C,4), gpio(C,5) };
+GPIO_Pin Matrix_cols[] = { gpio(B,0), gpio(B,1), gpio(B,2), gpio(B,3), gpio(B,16), gpio(B,17), gpio(C,4), gpio(C,5), gpio(D,0) };
 GPIO_Pin Matrix_rows[] = { gpio(D,1), gpio(D,2), gpio(D,3), gpio(D,4), gpio(D,5), gpio(D,6), gpio(D,7) };
 
 // Define type of scan matrix
-Config Matrix_type = Config_Pullup;
+Config Matrix_type = Config_Pulldown;
 
 
 #endif // __MATRIX_H
--- a/Scan/MD1/scan_loop.c	Fri Aug 01 01:26:25 2014 -0700
+++ b/Scan/MD1/scan_loop.c	Sat Aug 02 22:19:33 2014 -0700
@@ -28,6 +28,7 @@
 #include <cli.h>
 #include <led.h>
 #include <print.h>
+#include <matrix_scan.h>
 
 // Local Includes
 #include "scan_loop.h"
@@ -35,10 +36,21 @@
 
 
 
+// ----- Function Declarations -----
+
+// CLI Functions
+void cliFunc_echo( char* args );
+
+
+
 // ----- Variables -----
 
-// Indicates if the next scan is the first after a USB send
-uint8_t Scan_firstScan = 1;
+// Scan Module command dictionary
+char*       scanCLIDictName = "Scan Module Commands";
+CLIDictItem scanCLIDict[] = {
+	{ "echo",        "Example command, echos the arguments.", cliFunc_echo },
+	{ 0, 0, 0 } // Null entry for dictionary end
+};
 
 // Number of scans since the last USB send
 uint16_t Scan_scanCount = 0;
@@ -50,21 +62,21 @@
 // Setup
 inline void Scan_setup()
 {
+	// Register Scan CLI dictionary
+	CLI_registerDictionary( scanCLIDict, scanCLIDictName );
+
 	// Setup GPIO pins for matrix scanning
 	Matrix_setup();
 
-	// First scan is next
-	Scan_firstScan = 1;
+	// Reset scan count
+	Scan_scanCount = 0;
 }
 
 
 // Main Detection Loop
 inline uint8_t Scan_loop()
 {
-	Matrix_scan( Scan_scanCount++, Scan_firstScan );
-
-	// No longer the first scan
-	Scan_firstScan = 0;
+	Matrix_scan( Scan_scanCount++ );
 
 	return 0;
 }
@@ -81,7 +93,33 @@
 {
 	// Reset scan loop indicator (resets each key debounce state)
 	// TODO should this occur after USB send or Macro processing?
-	Scan_firstScan = 1;
 	Scan_scanCount = 0;
 }
 
+
+// ----- CLI Command Functions -----
+
+// XXX Just an example command showing how to parse arguments (more complex than generally needed)
+void cliFunc_echo( char* args )
+{
+	char* curArgs;
+	char* arg1Ptr;
+	char* arg2Ptr = args;
+
+	// Parse args until a \0 is found
+	while ( 1 )
+	{
+		print( NL ); // No \r\n by default after the command is entered
+
+		curArgs = arg2Ptr; // Use the previous 2nd arg pointer to separate the next arg from the list
+		CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
+
+		// Stop processing args if no more are found
+		if ( *arg1Ptr == '\0' )
+			break;
+
+		// Print out the arg
+		dPrint( arg1Ptr );
+	}
+}
+
--- a/Scan/MD1/scan_loop.h	Fri Aug 01 01:26:25 2014 -0700
+++ b/Scan/MD1/scan_loop.h	Sat Aug 02 22:19:33 2014 -0700
@@ -27,16 +27,6 @@
 // Compiler Includes
 #include <stdint.h>
 
-// Local Includes
-
-
-
-// ----- Defines -----
-
-
-
-// ----- Variables -----
-
 
 
 // ----- Functions -----
--- a/Scan/MatrixARM/matrix_scan.c	Fri Aug 01 01:26:25 2014 -0700
+++ b/Scan/MatrixARM/matrix_scan.c	Sat Aug 02 22:19:33 2014 -0700
@@ -38,11 +38,39 @@
 
 
 
+// ----- Function Declarations -----
+
+// CLI Functions
+void cliFunc_matrixDebug( char* args );
+void cliFunc_matrixState( char* args );
+
+
+
 // ----- Variables -----
 
+// Scan Module command dictionary
+char*       matrixCLIDictName = "Matrix Module Commands";
+CLIDictItem matrixCLIDict[] = {
+	{ "matrixDebug",  "Enables matrix debug mode, prints out each scan code." NL "\t\tIf argument \033[35mT\033[0m is given, prints out each scan code state transition.", cliFunc_matrixDebug },
+	{ "matrixState",  "Prints out the current scan table N times." NL "\t\t \033[1mO\033[0m - Off, \033[1;33mP\033[0m - Press, \033[1;32mH\033[0m - Hold, \033[1;35mR\033[0m - Release, \033[1;31mI\033[0m - Invalid", cliFunc_matrixState },
+	{ 0, 0, 0 } // Null entry for dictionary end
+};
+
 // Debounce Array
 KeyState Matrix_scanArray[ Matrix_colsNum * Matrix_rowsNum ];
 
+// Matrix debug flag - If set to 1, for each keypress the scan code is displayed in hex
+//                     If set to 2, for each key state change, the scan code is displayed along with the state
+uint8_t matrixDebugMode = 0;
+
+// Matrix State Table Debug Counter - If non-zero display state table after every matrix scan
+uint16_t matrixDebugStateCounter = 0;
+
+// Matrix Scan Counters
+uint16_t matrixMaxScans  = 0;
+uint16_t matrixCurScans  = 0;
+uint16_t matrixPrevScans = 0;
+
 
 
 // ----- Functions -----
@@ -53,40 +81,40 @@
 uint8_t Matrix_pin( GPIO_Pin gpio, Type type )
 {
 	// Register width is defined as size of a pointer
-	uint8_t port_offset = (uint8_t)gpio.port * sizeof(unsigned int*);
+	unsigned int gpio_offset = gpio.port * 0x40   / sizeof(unsigned int*);
+	unsigned int port_offset = gpio.port * 0x1000 / sizeof(unsigned int*) + gpio.pin;
 
-	// Assumes 6 registers between GPIO Port registers
-	volatile unsigned int GPIO_PDDR = *(&GPIOA_PDDR + port_offset * 6);
-	volatile unsigned int GPIO_PSOR = *(&GPIOA_PSOR + port_offset * 6);
-	volatile unsigned int GPIO_PCOR = *(&GPIOA_PCOR + port_offset * 6);
-	volatile unsigned int GPIO_PDIR = *(&GPIOA_PDIR + port_offset * 6);
-
-	// Assumes 35 registers between PORT pin registers
-	volatile unsigned int PORT_PCR = *(&PORTA_PCR0 + port_offset * 35);
+	// Assumes 0x40 between GPIO Port registers and 0x1000 between PORT pin registers
+	// See Lib/mk20dx.h
+	volatile unsigned int *GPIO_PDDR = (unsigned int*)(&GPIOA_PDDR) + gpio_offset;
+	volatile unsigned int *GPIO_PSOR = (unsigned int*)(&GPIOA_PSOR) + gpio_offset;
+	volatile unsigned int *GPIO_PCOR = (unsigned int*)(&GPIOA_PCOR) + gpio_offset;
+	volatile unsigned int *GPIO_PDIR = (unsigned int*)(&GPIOA_PDIR) + gpio_offset;
+	volatile unsigned int *PORT_PCR  = (unsigned int*)(&PORTA_PCR0) + port_offset;
 
 	// Operation depends on Type
 	switch ( type )
 	{
 	case Type_StrobeOn:
-		GPIO_PSOR |= (1 << gpio.pin);
+		*GPIO_PSOR |= (1 << gpio.pin);
 		break;
 
 	case Type_StrobeOff:
-		GPIO_PCOR |= (1 << gpio.pin);
+		*GPIO_PCOR |= (1 << gpio.pin);
 		break;
 
 	case Type_StrobeSetup:
 		// Set as output pin
-		GPIO_PDDR |= (1 << gpio.pin);
+		*GPIO_PDDR |= (1 << gpio.pin);
 
 		// Configure pin with slow slew, high drive strength and GPIO mux
-		PORT_PCR = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1);
+		*PORT_PCR = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1);
 
 		// Enabling open-drain if specified
 		switch ( Matrix_type )
 		{
 		case Config_Opendrain:
-			PORT_PCR |= PORT_PCR_ODE;
+			*PORT_PCR |= PORT_PCR_ODE;
 			break;
 
 		// Do nothing otherwise
@@ -96,24 +124,24 @@
 		break;
 
 	case Type_Sense:
-		return GPIO_PDIR & (1 << gpio.pin) ? 1 : 0;
+		return *GPIO_PDIR & (1 << gpio.pin) ? 1 : 0;
 
 	case Type_SenseSetup:
 		// Set as input pin
-		GPIO_PDDR &= ~(1 << gpio.pin);
+		*GPIO_PDDR &= ~(1 << gpio.pin);
 
 		// Configure pin with passive filter and GPIO mux
-		PORT_PCR = PORT_PCR_PFE | PORT_PCR_MUX(1);
+		*PORT_PCR = PORT_PCR_PFE | PORT_PCR_MUX(1);
 
 		// Pull resistor config
 		switch ( Matrix_type )
 		{
 		case Config_Pullup:
-			PORT_PCR |= PORT_PCR_PE | PORT_PCR_PS;
+			*PORT_PCR |= PORT_PCR_PE | PORT_PCR_PS;
 			break;
 
 		case Config_Pulldown:
-			PORT_PCR |= PORT_PCR_PE;
+			*PORT_PCR |= PORT_PCR_PE;
 			break;
 
 		// Do nothing otherwise
@@ -129,32 +157,91 @@
 // Setup GPIO pins for matrix scanning
 void Matrix_setup()
 {
+	// Register Matrix CLI dictionary
+	CLI_registerDictionary( matrixCLIDict, matrixCLIDictName );
+
+	info_msg("Columns:  ");
+	printHex( Matrix_colsNum );
+
 	// Setup Strobe Pins
 	for ( uint8_t pin = 0; pin < Matrix_colsNum; pin++ )
 	{
 		Matrix_pin( Matrix_cols[ pin ], Type_StrobeSetup );
 	}
 
+	print( NL );
+	info_msg("Rows:     ");
+	printHex( Matrix_rowsNum );
+
 	// Setup Sense Pins
 	for ( uint8_t pin = 0; pin < Matrix_rowsNum; pin++ )
 	{
 		Matrix_pin( Matrix_rows[ pin ], Type_SenseSetup );
 	}
 
+	print( NL );
+	info_msg("Max Keys: ");
+	printHex( Matrix_maxKeys );
+
 	// Clear out Debounce Array
 	for ( uint8_t item = 0; item < Matrix_maxKeys; item++ )
 	{
 		Matrix_scanArray[ item ].prevState     = KeyState_Off;
 		Matrix_scanArray[ item ].curState      = KeyState_Off;
 		Matrix_scanArray[ item ].activeCount   = 0;
-		Matrix_scanArray[ item ].inactiveCount = 0;
+		Matrix_scanArray[ item ].inactiveCount = 0xFFFF; // Start at 'off' steady state
+	}
+
+	// Clear scan stats counters
+	matrixMaxScans  = 0;
+	matrixPrevScans = 0;
+}
+
+void Matrix_keyPositionDebug( KeyPosition pos )
+{
+	// Depending on the state, use a different flag + color
+	switch ( pos )
+	{
+	case KeyState_Off:
+		print("\033[1mO\033[0m");
+		break;
+
+	case KeyState_Press:
+		print("\033[1;33mP\033[0m");
+		break;
+
+	case KeyState_Hold:
+		print("\033[1;32mH\033[0m");
+		break;
+
+	case KeyState_Release:
+		print("\033[1;35mR\033[0m");
+		break;
+
+	case KeyState_Invalid:
+	default:
+		print("\033[1;31mI\033[0m");
+		break;
 	}
 }
 
+
 // Scan the matrix for keypresses
-// NOTE: firstScan should be set on the first scan after a USB send (to reset all the counters)
-void Matrix_scan( uint16_t scanNum, uint8_t firstScan )
+// NOTE: scanNum should be reset to 0 after a USB send (to reset all the counters)
+void Matrix_scan( uint16_t scanNum )
 {
+	// Increment stats counters
+	if ( scanNum > matrixMaxScans ) matrixMaxScans = scanNum;
+	if ( scanNum == 0 )
+	{
+		matrixPrevScans = matrixCurScans;
+		matrixCurScans = 0;
+	}
+	else
+	{
+		matrixCurScans++;
+	}
+
 	// For each strobe, scan each of the sense pins
 	for ( uint8_t strobe = 0; strobe < Matrix_colsNum; strobe++ )
 	{
@@ -165,11 +252,11 @@
 		for ( uint8_t sense = 0; sense < Matrix_rowsNum; sense++ )
 		{
 			// Key position
-			uint8_t key = Matrix_rowsNum * strobe + sense;
+			uint8_t key = Matrix_colsNum * sense + strobe;
 			KeyState *state = &Matrix_scanArray[ key ];
 
 			// If first scan, reset state
-			if ( firstScan )
+			if ( scanNum == 0 )
 			{
 				// Set previous state, and reset current state
 				state->prevState = state->curState;
@@ -177,33 +264,37 @@
 			}
 
 			// Signal Detected
+			// Increment count and right shift opposing count
+			// This means there is a maximum of scan 13 cycles on a perfect off to on transition
+			//  (coming from a steady state 0xFFFF off scans)
+			// Somewhat longer with switch bounciness
+			// The advantage of this is that the count is ongoing and never needs to be reset
+			// State still needs to be kept track of to deal with what to send to the Macro module
 			if ( Matrix_pin( Matrix_rows[ sense ], Type_Sense ) )
 			{
 				// Only update if not going to wrap around
-				state->activeCount   += state->activeCount   < 255 ? 1 : 0;
-				state->inactiveCount -= state->inactiveCount > 0   ? 1 : 0;
+				if ( state->activeCount < 0xFFFF ) state->activeCount += 1;
+				state->inactiveCount >>= 1;
 			}
 			// Signal Not Detected
 			else
 			{
 				// Only update if not going to wrap around
-				state->inactiveCount += state->inactiveCount < 255 ? 1 : 0;
-				state->activeCount   -= state->activeCount   > 0   ? 1 : 0;
+				if ( state->inactiveCount < 0xFFFF ) state->inactiveCount += 1;
+				state->activeCount >>= 1;
 			}
 
 			// Check for state change if it hasn't been set
 			// Only check if the minimum number of scans has been met
 			//   the current state is invalid
 			//   and either active or inactive count is over the debounce threshold
-			if ( scanNum > DEBOUNCE_THRESHOLD
-			  && state->curState != KeyState_Invalid
-			  && ( state->activeCount > DEBOUNCE_THRESHOLD || state->inactiveCount > DEBOUNCE_THRESHOLD ) )
+			if ( state->curState == KeyState_Invalid )
 			{
 				switch ( state->prevState )
 				{
 				case KeyState_Press:
 				case KeyState_Hold:
-					if ( state->activeCount > DEBOUNCE_THRESHOLD )
+					if ( state->activeCount > state->inactiveCount )
 					{
 						state->curState = KeyState_Hold;
 					}
@@ -215,28 +306,145 @@
 
 				case KeyState_Release:
 				case KeyState_Off:
-					if ( state->activeCount > DEBOUNCE_THRESHOLD )
+					if ( state->activeCount > state->inactiveCount )
 					{
 						state->curState = KeyState_Press;
 					}
-					else if ( state->inactiveCount > DEBOUNCE_THRESHOLD )
+					else
 					{
 						state->curState = KeyState_Off;
 					}
 					break;
 
 				case KeyState_Invalid:
+				default:
 					erro_print("Matrix scan bug!! Report me!");
 					break;
 				}
 
 				// Send keystate to macro module
 				Macro_keyState( key, state->curState );
+
+				// Matrix Debug, only if there is a state change
+				if ( matrixDebugMode && state->curState != state->prevState )
+				{
+					// Basic debug output
+					if ( matrixDebugMode == 1 && state->curState == KeyState_Press )
+					{
+						printHex( key );
+						print(" ");
+					}
+					// State transition debug output
+					else if ( matrixDebugMode == 2 )
+					{
+						printHex( key );
+						Matrix_keyPositionDebug( state->curState );
+						print(" ");
+					}
+				}
 			}
 		}
 
 		// Unstrobe Pin
 		Matrix_pin( Matrix_cols[ strobe ], Type_StrobeOff );
 	}
+
+	// State Table Output Debug
+	if ( matrixDebugStateCounter > 0 )
+	{
+		// Decrement counter
+		matrixDebugStateCounter--;
+
+		// Output stats on number of scans being done per USB send
+		print( NL );
+		info_msg("Max scans:      ");
+		printHex( matrixMaxScans );
+		print( NL );
+		info_msg("Previous scans: ");
+		printHex( matrixPrevScans );
+		print( NL );
+
+		// Output current scan number
+		info_msg("Scan Number:    ");
+		printHex( scanNum );
+		print( NL );
+
+		// Display the state info for each key
+		print("<key>:<previous state><current state> <active count> <inactive count>");
+		for ( uint8_t key = 0; key < Matrix_maxKeys; key++ )
+		{
+			// Every 4 keys, put a newline
+			if ( key % 4 == 0 )
+				print( NL );
+
+			print("\033[1m0x");
+			printHex_op( key, 2 );
+			print("\033[0m");
+			print(":");
+			Matrix_keyPositionDebug( Matrix_scanArray[ key ].prevState );
+			Matrix_keyPositionDebug( Matrix_scanArray[ key ].curState );
+			print(" 0x");
+			printHex_op( Matrix_scanArray[ key ].activeCount, 4 );
+			print(" 0x");
+			printHex_op( Matrix_scanArray[ key ].inactiveCount, 4 );
+			print(" ");
+		}
+
+		print( NL );
+	}
 }
 
+
+// ----- CLI Command Functions -----
+
+void cliFunc_matrixDebug ( char* args )
+{
+	// Parse number from argument
+	//  NOTE: Only first argument is used
+	char* arg1Ptr;
+	char* arg2Ptr;
+	CLI_argumentIsolation( args, &arg1Ptr, &arg2Ptr );
+
+	// Set the matrix debug flag depending on the argument
+	// If no argument, set to scan code only
+	// If set to T, set to state transition
+	switch ( arg1Ptr[0] )
+	{
+	// T as argument
+	case 'T':
+	case 't':
+		matrixDebugMode = matrixDebugMode != 2 ? 2 : 0;
+		break;
+
+	// No argument
+	case '\0':
+		matrixDebugMode = matrixDebugMode != 1 ? 1 : 0;
+		break;
+
+	// Invalid argument
+	default:
+		return;
+	}
+
+	print( NL );
+	info_msg("Matrix Debug Mode: ");
+	printInt8( matrixDebugMode );
+}
+
+void cliFunc_matrixState ( char* args )
+{
+	// Parse number from argument
+	//  NOTE: Only first argument is used
+	char* arg1Ptr;
+	char* arg2Ptr;
+	CLI_argumentIsolation( args, &arg1Ptr, &arg2Ptr );
+
+	// Default to 1 if no argument is given
+	matrixDebugStateCounter = 1;
+
+	if ( arg1Ptr[0] != '\0' )
+	{
+		matrixDebugStateCounter = (uint16_t)decToInt( arg1Ptr );
+	}
+}
+
--- a/Scan/MatrixARM/matrix_scan.h	Fri Aug 01 01:26:25 2014 -0700
+++ b/Scan/MatrixARM/matrix_scan.h	Sat Aug 02 22:19:33 2014 -0700
@@ -112,8 +112,8 @@
 typedef struct KeyState {
 	KeyPosition prevState;
 	KeyPosition curState;
-	uint8_t activeCount;
-	uint8_t inactiveCount;
+	uint16_t activeCount;
+	uint16_t inactiveCount;
 } KeyState;
 
 
@@ -121,7 +121,7 @@
 // ----- Functions -----
 
 void Matrix_setup();
-void Matrix_scan( uint16_t scanNum, uint8_t firstScan );
+void Matrix_scan( uint16_t scanNum );
 
 
 #endif // __MATRIX_SCAN_H
--- a/main.c	Fri Aug 01 01:26:25 2014 -0700
+++ b/main.c	Sat Aug 02 22:19:33 2014 -0700
@@ -49,10 +49,6 @@
 
 
 
-// ----- Function Declarations -----
-
-
-
 // ----- Variables -----
 
 // Timer Interrupt for flagging a send of the sampled key detection data to the USB host
@@ -65,41 +61,6 @@
 
 // ----- Functions -----
 
-// Initial Pin Setup, make sure they are sane
-inline void pinSetup()
-{
-
-// AVR
-#if defined(_at90usb162_) || defined(_atmega32u4_) || defined(_at90usb646_) || defined(_at90usb1286_)
-
-	// For each pin, 0=input, 1=output
-#if defined(__AVR_AT90USB1286__)
-	DDRA = 0x00;
-#endif
-	DDRB = 0x00;
-	DDRC = 0x00;
-	DDRD = 0x00;
-	DDRE = 0x00;
-	DDRF = 0x00;
-
-
-	// Setting pins to either high or pull-up resistor
-#if defined(__AVR_AT90USB1286__)
-	PORTA = 0x00;
-#endif
-	PORTB = 0x00;
-	PORTC = 0x00;
-	PORTD = 0x00;
-	PORTE = 0x00;
-	PORTF = 0x00;
-
-// ARM
-#elif defined(_mk20dx128_) || defined(_mk20dx128vlf5_) || defined(_mk20dx256_) // ARM
-	// TODO - Should be cleared, but not that necessary due to the pin layout
-#endif
-}
-
-
 inline void usbTimerSetup()
 {
 // AVR
@@ -134,11 +95,9 @@
 #endif
 }
 
+
 int main()
 {
-	// Configuring Pins
-	pinSetup();
-
 	// Enable CLI
 	CLI_init();
 
@@ -199,7 +158,3 @@
 #endif
 }
 
-
-// ----- CLI Command Functions -----
-
-