serial reciever routines - which is any good ?

Hi,

I'm messing with some code that was supposed to run an ISR (takes 50% of cpu time) for my led matrix project, and communicate with a PC and read data from an RFID board via NewSoftSerial V7.

I had to abandon the idea to run all of this on just one arduino, as the PWM code ist just to resource intensive. Driving the matrix and receiving some bytes with the hardware UART works though.

The common part of the sketch:

#define __RFID_enable_pin 6
#define __RFID_rx_pin 7 /* not used but necessary */
#define __RFID_tx_pin 8 /* the RFID board TX pin goes to here */
#define __RFID_start_byte 0x0A
#define __RFID_stop_byte 0x0D
#define __RFID_rx_length 12
#define __RFID_rx_data_length 10
#define __RFID_rx_buffer_length 13

#include <NewSoftSerial.h> /* talk to RFID board */
NewSoftSerial RFID(__RFID_tx_pin,__RFID_rx_pin); /* talk to RFID board */


void setup(void) {
  pinMode(__RFID_enable_pin,OUTPUT);
  digitalWrite(__RFID_enable_pin,LOW); /* activate RFID board */
  Serial.begin(9600); /* talk to PC */
  RFID.begin(2400); /* start listening for RFID board */
}

So here are the 2 routines:

void loop(void) {

 static byte RFID_rx_buffer[__RFID_rx_buffer_length]; /* buffer stores 12 bytes. DATA format: start-byte, 10x data byte, stop-byte */
 byte ctr = 0;
   
  if ( RFID.available() ) {
  if ( RFID.read() == __RFID_start_byte ) {  /* start byte received */
    /* Serial.println("start byte !"); */
    while ( ctr <= (__RFID_rx_length-2) ) { /* read 11 bytes: data0-9, stop-byte */
      if ( RFID.available() ) {
        RFID_rx_buffer[ctr] = RFID.read();
        ctr++; /* increase buffer position by 1 */
      }
    }
    if (RFID_rx_buffer[RFID_rx_data_length] == __RFID_stop_byte) { /* stop byte found */
      /* Serial.println("stop byte !"); */
      for (ctr=0; ctr <= (__RFID_rx_data_length-1); ctr++) { /* send data to PC */
        Serial.print(RFID_rx_buffer[ctr],HEX);
      }
      Serial.println("\n"); /* print empty line */
    }
    else { /* Serial.println("no stop byte"); */ }
  }
}

}

or

void loop(void) {

  static byte RFID_rx_buffer[__RFID_rx_buffer_length]; /* buffer stores 12 bytes. DATA format: start-byte, 10x data byte, stop-byte */
  static byte RFID_rx_ctr = 0;
  static byte start_byte_received = 0;
  static byte data = 0;
  /* static unsigned int transactions = 0; */
  byte ctr;
   
  if ( RFID.available() ) {
    data = RFID.read();
    /* Serial.println(data,HEX); */
    if ( start_byte_received == 1) {
      RFID_rx_buffer[RFID_rx_ctr] = data;
      RFID_rx_ctr++; 
    }
    if ( data == __RFID_start_byte) {
      start_byte_received = 1;
    }
    if ( RFID_rx_ctr == __RFID_rx_data_length + 1 ) {
      RFID_rx_ctr = 0;
      start_byte_received = 0;
      if ( RFID_rx_buffer[__RFID_rx_data_length] == __RFID_stop_byte ) {
        /* transactions++; */
        /* Serial.println(transactions); */
        for (ctr=0; ctr <= (__RFID_rx_data_length-1); ctr++) { /* send data to PC */
          Serial.print(RFID_rx_buffer[ctr],HEX);
        }
        Serial.println("\n"); /* print empty line */
        /* Serial.println(RFID_rx_ctr,DEC); */
        /* Serial.println(start_byte_received,DEC); */
        /* Serial.println("\n\n"); */
      }  
    }
  }

}

The one advantage of the 2nd routine I immediately see is that it doesn't trap in the while loop as long as not all of the data has been received. What I'm looking for is some code that can cope with being interrupted by an ISR quite often, if that can be done at all.

Edit:

I've just found an interesting thing in avrlibc about interruptible interrupts. Maybe I'll be stepping into pits of hell here (endless recursions and so on), but I'll give it a try anyway :slight_smile:

void XXX_vect(void) __attribute__ ((interrupt));
void XXX_vect(void) {
  ...
}

According to the avrlibc guide, defining an interrupt vector like above behaves somewhat similar to this:

ISR(-name-) {

sei();

/* some code */

}

Edit 2:

Well... using attribute ((interrupt)) leaves out quite a bit that is necessary to make interrupts work properly. Apparently there is no preservation of SREG and the usual pushs/pops and most importantly no RETI added when using this! I'm not into this deep enough to go that path. So I'll just use sei(); as the first line of code in the usual ISR(...) {} construct. Seems to work so far. Next thing is to test what happens if another interrupt fires...