changeset 100:a4fca67ec75d

Added the averaged initial average as well as problem key rejection - Any keys that exceed the high average are temporarily disabled - If the sense value goes below the initial average sense, it is re-enabled - Even works if *many* keys are pressed initially - Still needs a bit of detection of consistent high keys that sometimes sneak below the threshold (May be able to have an elastic threshold that could deal with this) - Removed dead code (and redundant calculations)
author Jacob Alexander <triplehaata@gmail.com>
date Sun, 01 Dec 2013 23:07:38 -0500
parents 6cdbd3f73785
children d952a1171917
files Scan/avr-capsense/scan_loop.c
diffstat 1 files changed, 151 insertions(+), 69 deletions(-) [+]
line wrap: on
line diff
--- a/Scan/avr-capsense/scan_loop.c	Sun Dec 01 17:13:42 2013 -0500
+++ b/Scan/avr-capsense/scan_loop.c	Sun Dec 01 23:07:38 2013 -0500
@@ -39,7 +39,6 @@
 #define THRESHOLD (THRESHOLD_MV / MV_PER_ADC)
 
 #define STROBE_SETTLE 1
-#define MUX_SETTLE 1
 
 #define TEST_KEY_STROBE (0x05)
 #define TEST_KEY_MASK (1 << 0)
@@ -88,15 +87,8 @@
 #define WARMUP_LOOPS ( 1024 )
 #define WARMUP_STOP (WARMUP_LOOPS - 1)
 
-#define SAMPLES 10
-#define SAMPLE_OFFSET ((SAMPLES) - MUXES_COUNT)
 #define SAMPLE_CONTROL 3
 
-// Starting average for keys, per key will adjust during runtime
-// XXX - A better method is needed to choose this value (i.e. not experimental)
-//       The ideal average is not always found for weak keys if this is set too high...
-#define DEFAULT_KEY_BASE 0xB0
-
 #define KEY_COUNT ((MAX_STROBES) * (MUXES_COUNT))
 
 #define RECOVERY_CONTROL 1
@@ -140,11 +132,19 @@
 
 
 // TODO dfj variables...needs cleaning up and commenting
-volatile uint16_t full_av = 0;
+
+// Variables used to calculate the starting sense value (averaging)
+uint32_t full_avg = 0;
+uint32_t high_avg = 0;
+uint32_t  low_avg = 0;
+
+uint8_t  high_count = 0;
+uint8_t   low_count = 0;
+
 
 uint8_t ze_strober = 0;
 
-uint16_t samples [SAMPLES];
+uint16_t samples[MUXES_COUNT];
 
 uint8_t cur_keymap[MAX_STROBES];
 
@@ -156,7 +156,8 @@
 
 uint16_t keys_averages_acc[KEY_COUNT];
 uint16_t keys_averages    [KEY_COUNT];
-uint8_t  keys_debounce    [KEY_COUNT];
+uint8_t  keys_debounce    [KEY_COUNT]; // Contains debounce statistics
+uint8_t  keys_problem     [KEY_COUNT]; // Marks keys that should be ignored (determined by averaging at startup)
 
 uint8_t full_samples[KEY_COUNT];
 
@@ -174,10 +175,6 @@
 
 uint8_t dump_count = 0;
 
-uint16_t db_delta = 0;
-uint8_t  db_sample = 0;
-uint16_t db_threshold = 0;
-
 
 
 // ----- Function Declarations -----
@@ -221,7 +218,6 @@
 //#define UNSAVER_STROBE
 #ifdef KISHSAVER_STROBE
 	total_strobes = 8;
-	//total_strobes = 9;
 
 	strobe_map[0] = 2; // Kishsaver doesn't use strobe 0 and 1
 	strobe_map[1] = 3;
@@ -232,7 +228,8 @@
 	strobe_map[6] = 8;
 	strobe_map[7] = 9;
 	// XXX - Disabling for now, not sure how to deal with test points yet (without spamming the debug)
-	//strobe_map[8] = 15; // Test point strobe (3 test points, sense 1, 4, 5)
+	total_strobes = 9;
+	strobe_map[8] = 15; // Test point strobe (3 test points, sense 1, 4, 5)
 #elif defined(TERMINAL_6110668_STROBE)
 	total_strobes = 16;
 
@@ -280,16 +277,13 @@
 		cur_keymap[i] = 0;
 	}
 
+	// Reset debounce table
 	for ( int i = 0; i < KEY_COUNT; ++i )
 	{
-		keys_averages[i] = DEFAULT_KEY_BASE;
-		keys_averages_acc[i] = (DEFAULT_KEY_BASE);
-
-		// Reset debounce table
 		keys_debounce[i] = 0;
 	}
 
-	/** warm things up a bit before we start collecting data, taking real samples. */
+	// Warm things up a bit before we start collecting data, taking real samples.
 	for ( uint8_t i = 0; i < total_strobes; ++i )
 	{
 		sampleColumn( strobe_map[i] );
@@ -316,8 +310,8 @@
 		// Keymap scan debug
 		for ( uint8_t i = 0; i < total_strobes; ++i )
 		{
-				printHex(cur_keymap[strobe_map[i]]);
-				print(" ");
+			printHex(cur_keymap[strobe_map[i]]);
+			print(" ");
 		}
 
 		print(" : ");
@@ -391,28 +385,41 @@
 
 inline void capsense_scan()
 {
-	// TODO dfj code...needs commenting + cleanup...
-	uint32_t full_av_acc = 0;
+	// Accumulated average used for the next scan
+	uint32_t cur_full_avg = 0;
+	uint32_t cur_high_avg = 0;
 
+	// Reset average counters
+	low_avg = 0;
+	low_count = 0;
+
+	high_count = 0;
+
+	// Scan each of the mapped strobes in the matrix
 	for ( uint8_t strober = 0; strober < total_strobes; ++strober )
 	{
 		uint8_t map_strobe = strobe_map[strober];
 
 		uint8_t tries = 1;
 		while ( tries++ && sampleColumn( map_strobe ) ) { tries &= 0x7; } // don't waste this one just because the last one was poop.
-		column = testColumn( map_strobe );
 
-		idle |= column; // if column has any pressed keys, then we are not idle.
+		// Only process sense data if warmup is finished
+		if ( boot_count >= WARMUP_LOOPS )
+		{
+			column = testColumn( map_strobe );
+
+			idle |= column; // if column has any pressed keys, then we are not idle.
 
-		// TODO Is this needed anymore? Really only helps debug -HaaTa
-		if( column != cur_keymap[map_strobe] && ( boot_count >= WARMUP_LOOPS ) )
-		{
-			cur_keymap[map_strobe] = column;
-			keymap_change = 1;
+			// TODO Is this needed anymore? Really only helps debug -HaaTa
+			if( column != cur_keymap[map_strobe] && ( boot_count >= WARMUP_LOOPS ) )
+			{
+				cur_keymap[map_strobe] = column;
+				keymap_change = 1;
+			}
+
+			idle |= keymap_change; // if any keys have changed inc. released, then we are not idle.
 		}
 
-		idle |= keymap_change; // if any keys have changed inc. released, then we are not idle.
-
 		if ( error == 0x50 )
 		{
 			error_data |= (((uint16_t)map_strobe) << 12);
@@ -422,17 +429,60 @@
 		for ( int i = 0; i < MUXES_COUNT; ++i )
 		{
 			// discard sketchy low bit, and meaningless high bits.
-			uint8_t sample = samples[SAMPLE_OFFSET + i] >> 1;
+			uint8_t sample = samples[i] >> 1;
 			full_samples[strobe_line + i] = sample;
 			keys_averages_acc[strobe_line + i] += sample;
 		}
 
-		for ( uint8_t i = SAMPLE_OFFSET; i < ( SAMPLE_OFFSET + MUXES_COUNT ); ++i )
+		// Accumulate 3 total averages (used for determining starting average during warmup)
+		//     full_avg - Average of all sampled lines on the previous scan set
+		// cur_full_avg - Average of all sampled lines for this scan set
+		//     high_avg - Average of all sampled lines above full_avg on the previous scan set
+		// cur_high_avg - Average of all sampled lines above full_avg
+		//      low_avg - Average of all sampled lines below or equal to full_avg
+		if ( boot_count < WARMUP_LOOPS )
 		{
-			full_av_acc += (samples[i]);
+			for ( uint8_t i = 0; i < MUXES_COUNT; ++i )
+			{
+				uint8_t sample = samples[i] >> 1;
+
+				// Sample is high, add it to high avg
+				if ( sample > full_avg )
+				{
+					high_count++;
+					cur_high_avg += sample;
+				}
+				// Sample is low, add it to low avg
+				else
+				{
+					low_count++;
+					low_avg += sample;
+				}
+
+				// If sample is higher than previous high_avg, then mark as "problem key"
+				keys_problem[strobe_line + i] = sample > high_avg ? sample : 0;
+
+				// Prepare for next average
+				cur_full_avg += sample;
+			}
 		}
 	} // for strober
 
+	// Update total sense average (only during warm-up)
+	if ( boot_count < WARMUP_LOOPS )
+	{
+		full_avg = cur_full_avg / (total_strobes * MUXES_COUNT);
+		high_avg = cur_high_avg / high_count;
+		low_avg /= low_count;
+
+		// Update the base average value using the low_avg (best chance of not ignoring a keypress)
+		for ( int i = 0; i < KEY_COUNT; ++i )
+		{
+			keys_averages[i] = low_avg;
+			keys_averages_acc[i] = low_avg;
+		}
+	}
+
 #ifdef VERIFY_TEST_PAD
 	// verify test key is not down.
 	if ( ( cur_keymap[TEST_KEY_STROBE] & TEST_KEY_MASK ) )
@@ -475,6 +525,38 @@
 			info_msg("Warmup finished using ");
 			printInt16( WARMUP_LOOPS );
 			print(" iterations\n");
+
+			// Display the final calculated averages of all the sensed strobes
+			info_msg("Full average (");
+			printInt8( total_strobes * MUXES_COUNT );
+			print("): ");
+			printHex( full_avg );
+
+			print("  High average (");
+			printInt8( high_count );
+			print("): ");
+			printHex( high_avg );
+
+			print("  Low average (");
+			printInt8( low_count );
+			print("): ");
+			printHex( low_avg );
+			print("\n");
+
+			// Display problem keys, and the sense value at the time
+			for ( uint8_t key = 0; key < KEY_COUNT; key++ )
+			{
+				if ( keys_problem[key] )
+				{
+					warn_msg("Problem key detected: ");
+					printHex( key );
+					print(" (");
+					printHex( keys_problem[key] );
+					print(")\n");
+				}
+			}
+
+			info_print("If problem keys were detected, and were being held down, they will be reset as soon as let go");
 			break;
 		}
 	}
@@ -670,20 +752,6 @@
 
 	hold_sample(ON);
 
-#undef MUX_SETTLE
-
-#if (MUX_SETTLE)
-	for ( uint8_t mux = 0; mux < 8; ++mux )
-	{
-		SET_FULL_MUX(mux); // our sample will use this
-
-		// wait for mux to settle.
-		for ( uint8_t i = 0; i < MUX_SETTLE; ++i ) { getADC(); }
-
-		// retrieve current read.
-		buffer[mux] = getADC();
-	}
-#else
 	uint8_t mux = 0;
 	SET_FULL_MUX(mux);
 	getADC(); // throw away; unknown mux.
@@ -695,7 +763,6 @@
 		mux++;
 
 	} while (mux < 8);
-#endif
 
 	hold_sample(OFF);
 	recovery(ON);
@@ -720,7 +787,7 @@
 {
 	int rval = 0;
 
-	rval = sampleColumn_8x( column, samples + SAMPLE_OFFSET );
+	rval = sampleColumn_8x( column, samples );
 
 	return rval;
 }
@@ -728,27 +795,53 @@
 
 uint8_t testColumn( uint8_t strobe )
 {
+	uint16_t db_delta = 0;
+	uint8_t  db_sample = 0;
+	uint16_t db_threshold = 0;
+
 	uint8_t column = 0;
 	uint8_t bit = 1;
+
 	for ( uint8_t mux = 0; mux < MUXES_COUNT; ++mux )
 	{
 		uint16_t delta = keys_averages[(strobe << MUXES_COUNT_XSHIFT) + mux];
 
 		uint8_t key = (strobe << MUXES_COUNT_XSHIFT) + mux;
 
+		// Check if this is a bad key (e.g. test point, or non-existent key)
+		if ( keys_problem[key] )
+		{
+			// If the sample value of the problem key goes below full_avg (overall initial average)
+			//  re-enable the key
+			if ( (db_sample = samples[mux] >> 1) < full_avg )
+			{
+				info_msg("Re-enabling problem key: ");
+				printHex( key );
+				print("\n");
+
+				keys_problem[key] = 0;
+			}
+			// Otherwise, don't waste any more cycles processing the problem key
+			else
+			{
+				continue;
+			}
+		}
+
 		// Keypress detected
-		if ( (db_sample = samples[SAMPLE_OFFSET + mux] >> 1) > (db_threshold = threshold) + (db_delta = delta) )
+		//  db_sample (uint8_t), discard meaningless high bit, and garbage low bit
+		if ( (db_sample = samples[mux] >> 1) > (db_threshold = threshold) + (db_delta = delta) )
 		{
 			column |= bit;
 
 			// Only register keypresses once the warmup is complete, or not enough debounce info
-			if ( boot_count >= WARMUP_LOOPS && keys_debounce[key] <= DEBOUNCE_THRESHOLD )
+			if ( keys_debounce[key] <= DEBOUNCE_THRESHOLD )
 			{
 				// Add to the Macro processing buffer if debounce criteria met
 				// Automatically handles converting to a USB code and sending off to the PC
 				if ( keys_debounce[key] == DEBOUNCE_THRESHOLD )
 				{
-#define KEYSCAN_DEBOUNCE_DEBUG
+//#define KEYSCAN_DEBOUNCE_DEBUG
 #ifdef KEYSCAN_DEBOUNCE_DEBUG
 					// Debug message
 					print("0x");
@@ -764,7 +857,7 @@
 
 				keys_debounce[key]++;
 
-//#define KEYSCAN_THRESHOLD_DEBUG
+#define KEYSCAN_THRESHOLD_DEBUG
 #ifdef KEYSCAN_THRESHOLD_DEBUG
 				// Debug message
 				// <key> [<strobe>:<mux>] : <sense val> : <delta + threshold> : <margin>
@@ -887,17 +980,6 @@
 
 #endif
 
-#ifdef DEBUG_DELTA_SAMPLE_THRESHOLD
-	print("\n");
-	printHex( db_delta );
-	print(" ");
-	printHex( db_sample );
-	print(" ");
-	printHex( db_threshold );
-	print(" ");
-	printHex( column );
-#endif
-
 #ifdef DEBUG_USB_KEYMAP
 	print("\n      ");