SPI read question..

I'm a newbie here and I'm working on a keypad project. I'm using a shift register(74hc595) scanning columns and a other one reading rows(74hc165) through SPI comm.

I got a question: why I have to use a for loop to analyze every bit in a serial data. Why I cannot read it directly or I got nothing?

for (Col = 0; Col < EIBIT; Col++){ 
      if(bitRead(input,Col)==HIGH && Row > 0){
          bitWrite(RowOut, Row-1, 1);
          bitWrite(ColOut, Col+4, 1);
          ledOutput = RowOut | ColOut;

       Serial.print(Row);
        Serial.println(Col);

      }else{

          ledOutput = RowOut | ColOut;

      }
     } //end of Col

Why this is working and

    if(digitalRead(interruptPin)==HIGH && Row > 0){
   // or:  if(input > 0 && Row > 0){
      bitWrite(RowOut, Row+3, 1);
      Serial.println(input);
   }
    ledOutput =  input | RowOut;

and this is not? When I run this code even the interruption won't triggered.

Here is my full code:

/*  
 *  ))()ButtBox Proto.Ver t6)()(SPI)(
 *   
 *       comes with USB and Midi ports.
 *       74HC595 as the row Scanner
 *       74hc165 sa the col Receiver
 *       16 bits write and 8 bits read
 *       ****This Version is a*******
 *       ****test cod for bread board***
 */

#include <SPI.h>

# define ROW_SIZE 4
# define COL_SIZE 4
# define EIBIT 8

const int latchPin = 10; // 595:ST_CP 
const int PLPin = 4;// 165 latch
const int interruptPin = 2;
byte input = B11111111;
byte check = B00000001;
byte RowOut, ColOut;
byte ledOutput= B01010010;
int Row, Col, counter;

void setup() {
  // Setup Mode for data pins
  pinMode(13,OUTPUT);// SCK pin
  pinMode(interruptPin,INPUT);// button trigger
  pinMode(latchPin,OUTPUT);// latch 
  pinMode(PLPin,OUTPUT);

  // Initializing chips'SPI communication.

  SPI.beginTransaction(SPISettings(800000,// Reduced for 165
                                   MSBFIRST,SPI_MODE0));
  SPI.usingInterrupt(digitalPinToInterrupt(interruptPin)); 
  SPI.begin();

  // *** NEW: 16 bits in total
  SPI.transfer(B11111111);//0xFF = 11111111 in binary
  SPI.transfer(ledOutput);  
  // Latch the 595 foward one bit
  digitalWrite(latchPin,HIGH); 
  digitalWrite(latchPin,LOW);
  
  Serial.begin(9600);
 
  // ***** TEST setup ******
  attachInterrupt(digitalPinToInterrupt(interruptPin),
                  pin_read, RISING);
  Serial.println("Serial OK & Setup done!");
}

void loop(){
  
}  

void pin_read(){
  // pause for make sure
  for(int j = 0; j < 25; j++){
    delayMicroseconds(1000);
  }
  ColOut = 0;
  RowOut = 0;
  input = 0;
  check = B00000001;
  for(Row = 0; Row < EIBIT; Row++){
    /* Stage 1
     *  595: send a bit to keypad 
     *  165: setup and latch the data
     */
    // ***NEW: 16 bits in total
    digitalWrite(PLPin,LOW); //165
    SPI.transfer(check);
    digitalWrite(PLPin,HIGH); //165
    input = SPI.transfer(ledOutput);
    
    digitalWrite(latchPin,HIGH); //595:ST_CP 
    digitalWrite(latchPin,LOW); //595:ST_CP 
    /* Stage 2
     *  165 comm: read
     *  deal with the flickr
     *  when Multi triggered
     */
    for (Col = 0; Col < EIBIT; Col++){ 
      if(bitRead(input,Col)==HIGH && Row > 0){
          bitWrite(RowOut, Row-1, 1);
          bitWrite(ColOut, Col+4, 1);
          ledOutput = RowOut | ColOut;

       Serial.print(Row);
        Serial.println(Col);

      }else{

          ledOutput = RowOut | ColOut;
      }
     } //end of Col
    /*
     * Wrong Code: 
     * 
    if(digitalRead(interruptPin)==HIGH && Row > 0){
      bitWrite(RowOut, Row+3, 1);
      Serial.println(input);
   }
    ledOutput =  input | RowOut;
    *
    * but why?
    */
    check = check<< 1;
  } //`end of Row
  

  /* ***NEW: 16 bits in total
   *  Lid the led
   */
  SPI.transfer(255);
  SPI.transfer(ledOutput);
  // Latch the 595 foward one bit
  digitalWrite(latchPin,HIGH);
  digitalWrite(latchPin,LOW);
  
} //`pin_read

You have a lot of stuff in your interrupt handler that relies on interrupts being enabled. They are NOT when an ISR is running.

You need to re-write your interrupt handler to do nothing more than note that an interrupt happened.

The loop() function should do all the work, when it sees that an interrupt happened.

SPI.begin should be called before any other method of that Obect.

If you call SPI.beginTransaction() you should also call SPI.endTransaction().

 for(int j = 0; j < 25; j++){
    delayMicroseconds(1000);
  }

This is a very bad idea inside an interrupt service routine. You shouldn't wait 25ms busy loop in the ISR as interrupts are blocked there.

Another no-go in the ISR:

      Serial.print(Row);
        Serial.println(Col);

Sending something over the serial interface needs interrupts and these are deactivated inside the ISR.

I got the impression that you use SPI and interrupts although a classic polling and shift-out is a better fit. I miss the wiring schemata, so maybe there is a reason for your choice.

But my code do works with all flaws you guys mentioned. I didn't saw any issue during the ISR both my serial and my data output.

My question here is why I have to use a for loop to grab the data from a byte data type.

The reason why I use SPI instead of the traditional one is I want to make a fast responsive and expandable keypad. I found this method in this link How to Control a Ton of Inputs using Shift Registers! - YouTube. So what would happen if I keep my old way?

But my code do works with all flaws you guys mentioned. I didn't saw any issue during the ISR both my serial and my data output.

It can work for a long time and suddenly begin to freeze. The problem is that the serial interface relies on interrupts to send out what's in the buffer. As long as the buffer never gets full during such an interrupt triggered by the keyboard it probably works. But if you have a buffer overflow your Arduino will freeze as it waits for an interrupt to clear the buffer but that interrupt never happens because you're in an interrupt service routine and interrupts are disabled there. This is called "dead lock".

My question here is why I have to use a for loop to grab the data from a byte data type.

Because you get a byte and you want to know which bit in that byte is set.

The reason why I use SPI instead of the traditional one is I want to make a fast responsive and expandable keypad.

A keypad is made for human input. Believe me, no human is fast enough to generate a miss if the check is done by polling in the main loop.

So what would happen if I keep my old way?

As long as your Arduino does nothing else you could keep your old way. But the more tasks you give it the more likely you will run into conditions that show a strange behavior (race conditions). For example you may experience that the Arduino timing (millies()) is unusable.