Bill, thanks for the thought, but I don't think I'm that far down the road yet.
I just looked at my bit-byte to numeric digit map again and came up with a good way to both streamline the ISR using an improved lookup table and reduce the downstream analysis. The ISR only has a single if... move... increment statement, (and 9 out of 10 times the if is not taken) so that ought to be quick enough. The downstream processing just resets the ISR index and immediately starts moving bytes to a safe place.
Here is the entire code:
// Written by Nick Gammon
// April 2011
char sketch[] = "Nick_Gammon_Slave2_dec31x"; // Revisions by Rick Rantilla
// rev x - new raw2work chart - avoids copying strings of bytes for valid digits. This may help ISR timing
// rev w - using 256 member raw2work lookup table
// rev s - master counter "count" added for debugging
// rev p - just capture byte is ISR - everything else outside
// rev n - Added timing counters for debug - Why am I losing about 5% of the valid digits in the ISR?
// Since a valid userID has 8 digits, I'm losing or distorting 40% of them!!!
// Per timing ISR takes only 4 or 8 microsec, however, LCD gets 1 byte every 4 microsec.
// rev m - Ugh! - Serial.print takes hundreds of microseconds per character even at 115200
// rev k - Mega: now using wire 15 from T&A as SS (unfortunately this picks up commands as well)
// Mega SPI pins: 53 SS, 51 MOSI (signal), 52 clock
// Also SPI.setDataMode for inverted clock from the T&A LCD
#include "pins_arduino.h"
#include "SPI.h" // rick k
volatile byte c = 0; // Rick m
volatile byte cp = 0; // Rick n - previous byte needed to distinguish some digits
volatile int g = 0; // Rick d - counter for storing bytes into good_digit array to examine at leisure
volatile int r = 0; // Rick p - counter for raw digits
volatile int rmax = 50; // Rick r
volatile int i = 0; // Rick p
volatile int j = 0; // Rick p
volatile int k = 0; // Rick p
volatile int p = 0; // Rick x - I've made all counters unique and global
volatile int count = 0; // Rick s master counter
byte raw_digit [500]; // Rick p
byte work_digit[500]= "a"; // Rick n
byte good_digit [400]; // Rick d
byte out_digit[100]= "a"; // Rick n
volatile boolean raw2work[] = {0,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,1,0,0,0,0, 0,0,0,0,0,0,0,0, // 0-31 Rick w
0,1,0,1,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,1,0,1,0, // 32-63
0,0,0,1,0,0,0,1, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, // 64-95
1,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,1, // 96-127
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, // 128-159
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, // 160-191
1,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, // 192-223
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0 };// 224-255
// Rick x - only bytes in this table pass thru to the next step of decoding
void setup (void)
{
Serial.begin (115200);
Serial.println (sketch); // Rick c - always start by identifying what's actually in the Arduino
// have to send on master in, *slave out*
pinMode(MISO, OUTPUT);
// turn on SPI in slave mode
SPCR |= _BV(SPE);
// turn on interrupts
SPCR |= _BV(SPIE);
SPI.setDataMode(SPI_MODE2); // Rick k - because of inverted clock in T&A - not used in testing between Arduinos
} // end of setup
ISR (SPI_STC_vect) // SPI interrupt routine
{
//count++;
if (raw2work[SPDR]) {raw_digit[r++] = SPDR; // Rick x - if it is in the table, store it
// Rick w - it is a potential unique digit and is worth storing for further analysis
//Serial.println (raw_digit[r-1]); //Serial.print (" "); Serial.println (r,DEC);// debug
}
} // end of interrupt service routine (ISR) SPI_STC_vect
void loop (void)
{
if (r >= rmax) // Rick w - just be patient, don't get too fancy
{ // Rick m - caution: in a millisec ISR will start overwriting raw_digit[0]
r=0; // Rick n - let interrupt go back to filling raw_digit
for (i=0; i <= rmax; i++){ work_digit[i] = raw_digit[i]; } // Rick n - get these moved in a hurry, most of these are already good_digit
//for (int i=0; i <= rmax; i++){Serial.println(raw_digit[i]); } // Rick v - debug
for (j=0; j <=rmax; j++) { getDigit(); } // Rick x - get only valid digits, requires valid predecessors for 1, 3 and 8
// Rick p - this for loop ends with an array good_digit[ ] with g valid digits
for (k=0; k < g; k++){ // Rick n - process all g good_digits
// A valid userID is 4 zeroes followed by 4 digits. I've never seen a string of 4 zeroes in the command fields
if ( (good_digit[k] == 0) && (good_digit[k+1]==0) && (good_digit[k+2]==0) && (good_digit[k+3]==0) )
{ // got a valid userID - print the 4 least significant digits
for (p=0; p <= 7; p++) { // Rick n - again i is a local variable
out_digit[p] = good_digit[k+p]; // Rick n - userID is the 4 digits after the four zeroes
Serial.print (out_digit[p], DEC); // debug
} // end for p
Serial.println(" ");//Serial.println(count); // debug
// Rick x - here I will insert my cabinet door operation application code using out_digit
k = k+7; // k++ already incremented once - skip past the 8 digits of the UserID
} // end if good_digit - what happens if at the end of work_digit??? - adds trailing zeroes - I need to clean this up later
} // end for k
g=0; // set up for next batch
} // end if r - most of the time loop does nothing but check r
} // end loop
void getDigit() // Rick p
{
cp = c; // Rick n - store previous digit needed to distinguish a 1, 3 or 8
c = work_digit[j]; // still the raw byte as SPI found it, but only those in raw2work lookup table
switch (c) // Rick n - each graphic bitmap has 16 bytes per digit displayed (plus 6 command digits)
// Among the digits, each digit has a unique byte (or byte pair)
// 96, 192, 62, 126 and 127 may also appear in other digits, but unique pairings finalize the selection
// So whenever I find this unique byte (pair) in a field of digits, I've got a good digit
// regardless of what else is in that digit
// I might also get what appears to be a digit in a field of commands or letters or the clock,
// but I will later throw them out unless they are immediately following 4 zeroes in a row
// Increment g only if a valid digit
{
case 71:
good_digit [g++] = 0; // Rick e
break;
case 96: // original 127 remapped to 11 if cp was 0
if (cp == 192) {good_digit [g++] = 1; }// Rick t
break;
case 67:
good_digit [g++] = 2; // Rick d
break;
case 62: // original 32 remapped to 5 if cp was 0
if (cp == 126) {good_digit [g++] = 3; } // Rick t
if (cp == 127) {good_digit [g++] = 8; }// Rick t
// Note: there is a bug where sequence "48" in a valid user ID would register as "488"
// since a "4" ends in "127" and the "8" starts with "62"
// although these bytes are not part of their "unique" byte pairs
break;
case 19:
good_digit [g++] = 4; // Rick d
break;
case 33:
good_digit [g++] = 5; // Rick e
break;
case 60:
good_digit [g++] = 6; // Rick d
break;
case 1:
good_digit [g++] = 7; // Rick d
break;
case 35:
good_digit [g++] = 9; // Rick d
break;
default:
//time = micros() - time; Serial.println (time, DEC); delay(100); // debug
break;
} // end of switch
} // end of getDigit
Here are the results of what should have been 1,1,1,2,2,2,1945,1945,1945,3,3,3 (all with leading 0s):
00000001
00000001
00000008 (could have missed a 0)
00000002
00002114 (could have missed 3 0s)
00000217 (could have missed 2 0s)
(nothing - could have missed a 0)
(nothing - could have missed a 0)
00001945
00000351 (could have missed 2 0s
00000003
00004444 (could have missed 3 0s and the 3)
In this run rmax was set at 50 bytes, so I should have expected "end of buffer" effects 8/50 or about 2/12, not 7/12. If I set rmax at a big number (like 1000) I'd have to wait minutes for a response.
I'm going to see if I can find another Arduino laying around (maybe a newer Uno) before starting on a new venture to clean up the buffer ends or study naked_ISR. What I could do is set my buffer raw_digits to 1000, but only analyze 50 byte segments into work_digit, etc. Hmmm....
Thanks