Synchronous signal reading with interruption - ARDUINO UNO

Hello everyone!

Please, I need suggested to my problem!

I have a communication radio model KENWOOD TR-7950. The LCD burned! The radio have a LCD driver to receive the serial message from microcontroller of radio, process the code and print in the LCD.
I trying get this serial message and decode with arduino and than plot in the OLED display, for example.
I have all information I need to do that from a LCD driver datasheet. I have a clock signal, serial signal and I have a "load" signal indicating when the message finish.

I'm using external interrupt to read the message.
I connect the CLOCK SIGNAL in the PORT 0 (2 arduino board) and the LOAD SIGNAL in the PORT 1 (3 arduino board). The SERIAL signal I put in the digital pin as input.
I'm configure external interrupt for CLOCK signal in PORT 0 in rising mode, because I need read the SERIAL data in rising of clock.
I also configured external interrupt for LOAD signal in PORT 1 in rising mode, because when have HIGH level in this signal, just finish the message.

When have the interruption in CLOCK signal I'm read the SERIAL digital port. When have the interrupt in LOAD signal, I'm process all the data receive to try work and plot in the LCD.

The problem is:

sometimes the digital read of serial signal in the clock interruption is wrong. I have a wrong read and plot random number in the display. When I'm compare with oscilloscope I can confirm this wrong read

The signal of CLOCK is 32 bits in four times of 8 bits. For each 8 bits I have the SERIAL signal.

The time between each rising edge is approximately 100kHz

For example: in this case, the data is 10100010. I can receive wrong like 10000010.. A bit wrong...

The code is very simple...

#define CLOCK 2   // CLOCK IN I/O 2
#define SERIAL 4  // SERIAL IN I/O 4
#define LOAD 3    // LOAD IN I/O 3

volatile int SerialData[32];
volatile int i = 0;


ISR (INT0_vect) // CLOCK INTERRUPT
{
  SerialData[i] = digitalRead(SERIAL);
  i++;
    
} //end ISR

ISR (INT1_vect){ // LOAD INTERRUPT
     for(int z=0; z<32; z++){
     Serial.print(SerialData[z]); // PLOT BITS TO DEBUG IN SERIAL MONITOR - 32 BITS,
     Serial.print('\n');
     Serial.println(i);           // PLOT NUMBER OF INTERACTION TO CHECK IF IS ACCORDING TO 32 BITS RECEIVE AND READ
  }


void setup() {
  Serial.begin(115200); // SERIAL IN 11520
  pinMode(CLOCK, INPUT);  // CLOCK AS INPUT - HAVE PULLDOWN IN HARDWARE
  pinMode(SERIAL, INPUT); // SERIAL AS INPUT - HAVE PULLUP IN HARDWARE
  pinMode(LOAD, INPUT); // LOAD AS INPUT - HAVE PULLUP IN HARDWARE
 
    EICRA |= (1 << ISC01) | (1 << ISC00);     //EXTERNAL INTERRUPT PORT 0 IN RISING
    EICRA |= (1 << ISC10) | (1 << ISC11);     //EXTERNAL INTERRUPT PORT 1 IN RISING
    EIMSK |= (1 << INT0);                     
    EIMSK |= (1 << INT1);                     
    sei();                                    //TURN ON THE INTERRUPTS
    //interrupts ();
}
void loop() {


}

Check the LOAD signal in the scope. When I have the rising in LOAD input. The message finish.

How can I improove the signal read to can not have a wrong bit?
The time of instructions of Arduino UNO is too low?

Thanks for ALL SUGGESTION

Your scope shots suggest that you should read the data at the rising edge of the clock.

Hi friend! Yes, I'm do that! Like the oscilloscope and LCD driver datasheet.
When I have a rising edge I have the interrupt to read the data.

Hi @delgadobr ,

The print routine is time consuming and you are using it in the interrupt routine.

try this code:
I have changed the interrupt ports.

#define CLOCK 2   // CLOCK IN I/O 2
#define SERIAL 3  // SERIAL IN I/O 3  // Changed
#define LOAD 4    // LOAD IN I/O 4    // Changed

volatile int SerialData[48];
volatile bool LendoDado = false;
bool startFlag = false;
bool clockHigh = LOW;
bool SerialBit = LOW;
int bitCnt = 0;
//---------------------------------------------------------------------------------------------------
void clockCHG() {
  clockHigh = !clockHigh;
}
//---------------------------------------------------------------------------------------------------
void serialUp() {
  SerialBit = !SerialBit;
}
//---------------------------------------------------------------------------------------------------
void setup() {
  Serial.begin(115200);     // SERIAL IN 11520
  pinMode(CLOCK, INPUT);    // CLOCK AS INPUT - HAVE PULLDOWN IN HARDWARE
  pinMode(SERIAL, INPUT);   // SERIAL AS INPUT - HAVE PULLUP IN HARDWARE
  pinMode(LOAD, INPUT);     // LOAD AS INPUT - HAVE PULLUP IN HARDWARE

  attachInterrupt(digitalPinToInterrupt(CLOCK), clockCHG, CHANGE);    //  Clock CHANGE dettected
  attachInterrupt(digitalPinToInterrupt(SERIAL), serialUp, CHANGE);    //  Serial up dettected
}
//---------------------------------------------------------------------------------------------------
void loop() {
  if (digitalRead(LOAD) == HIGH)
  {
    for (int i = 0; i < 48; i++)
    {
      SerialData[i] = 0;                     // Clear Serial data received array
      LendoDado = false;
      clockHigh = LOW;
      SerialBit = LOW;
      bitCnt = 0;
    }
  }
  if (LendoDado == true)
  {
    if (clockHigh == HIGH)
    {
      if (SerialBit == HIGH)
      {
        SerialData[bitCnt] = 1;
      }
      else
      {
        SerialData[bitCnt] = 0;
      }
      bitCnt++;
      if (bitCnt >= 32)
      {
        bitCnt = 0;
        LendoDado = false;
        for (int z = 0; z < 32; z++)
        {
          Serial.print(SerialData[z]); // PLOT BITS TO DEBUG IN SERIAL MONITOR - 32 BITS,
          Serial.print('\n');
        }
      }
    }
  }
}

@ruilviana thanks!!

I'm try and in this way I never have serial port output...

I think it is not possible put the LOAD read in the loop. Because, the signal is too fast when finish the message. I need take in interrupt process.

The pulse of load is 43us. I have time to check the data. I think is better I put a boolean in HIGH and check the data in a while in loop and not in the interrupt... I will try this.

Why did you use interrupt in CHANGE if I need read only in RISING edge? i need read serial input only in rising edge of CLOCK

In this case when the SERIAL is 00 or 11 I will not have the interrupt in PIN 1.

Thanks!!

Hi everyone!

The solution was to program interrupt, pin configuration and mainly reading the SERIAL port by registers.

I believe that this way, the reading became more accurate and faster.

ISR (INT0_vect)
{
  SerialData[i] = (PIND & (1 << PIND4));
 i++;
} 

Thanks!