Hack from SPI display to Arduino

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