How to reduce the data refresh delay caused by the code?

Hi everyone,
I have been playing (a lot) with a piece of code to read some serial data from an external device wirelessly using a Xbee module. The code puts the incoming serial data bytes into an array and then calculates the CRC-32 bytes for that array and compares it with the CRC-32 values sent from the external device. If the calculated CRC bytes agreed and three header bytes were detected, some byte manipulation takes place and some data are displayed. The code works fine in terms of functionality, however it is when a reading of one of the sensors attached to the external device changes, there is a consistent 4 sec delay for the data readings displayed to be refreshed. In other words the code produces some unwanted delay. I used to think that the delay may be caused by the wireless hardware, but interestingly enough when I remove the parts of the code that checks for the header bytes and handles the CRC comparison, the code executed really fast, even though it throws out a lot of junk data at a fast rate.

/*
In "Working_wireless_on_the_car_with_Processing_V2" , it is intended to increase performance speed of the 
 Microcontroller by improving the coding structure
 */
#include <stdlib> // Standard library
#include <avr/pgmspace.h>
/*
The data bytes are defined below as constants
 */

const int THROT_POS1 = 6;
const int THROT_POS2 = 7;
const int ENG_TMP1 = 12;
const int ENG_TMP2 = 13;
const int AIR_TMP1 = 18;
const int AIR_TMP2 = 19;
const int BAT_VOL1 = 10;
const int BAT_VOL2 = 11;
const int OIL_PRS1 = 34;
const int OIL_PRS2 = 35;

/*
End of data byte definition
 */

const unsigned int MAX_INPUT = 104; // The maximum number of bytes to be received over the Serial connection from ECU

void setup ()
{
  Serial.begin (19200);
  Serial1.begin(19200);  // If using a Mega
} // end of setup

/*
The block of code that calculates the CRC-32 starts here
 */

static PROGMEM prog_uint32_t crc_table[16] = {
  0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
  0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
  0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
  0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
};

unsigned long crc_update(unsigned long crc, byte data)
{
  byte tbl_idx;
  tbl_idx = crc ^ (data >> (0 * 4));
  crc = pgm_read_dword_near(crc_table + (tbl_idx & 0x0f)) ^ (crc >> 4);
  tbl_idx = crc ^ (data >> (1 * 4));
  crc = pgm_read_dword_near(crc_table + (tbl_idx & 0x0f)) ^ (crc >> 4);
  return crc;
}

unsigned long crc_string( unsigned char *s, unsigned int length)
{
  unsigned long crc = ~0L;
  unsigned int i;
  //while (*s)
  for(i = 0; i<length;i++){
    crc = crc_update(crc, *s++);
  }
  crc = ~crc;
  return crc;
}

/*
The end of CRC-32 block
 */


// Here to process incoming serial data after a terminator received

void process_data (unsigned char *data)
{
  static unsigned long whole_four = 0; // This variable holds the last four bytes of the received bytes which are the CRC bytes


  if (data[0] == 0x82 && data[1] == 0x81 && data[2] == 0x80)  //Checking for the starting 3 header bytes
  {

    whole_four = ((unsigned long)(data[MAX_INPUT-4])<< 24)  | ((unsigned long)(data[MAX_INPUT-3])<< 16) | ((unsigned long)(data[MAX_INPUT-2])<< 8) | ((unsigned long)(data[MAX_INPUT-1])); // Forming a Hexadecimal value from the four CRC bytes
    if (crc_string(data,(MAX_INPUT-4))==whole_four) // Checking if the calculated CRC bytes match the received CRC bytes
    {
      //Calculating and formatting air temperature for dispalying
      float l = ((data[AIR_TMP1] << 8)+ data[AIR_TMP2])/10; 
      Serial.print("Air Temp ");
      Serial.print(l);
      Serial.print("C[ ");

      //Calculating and formatting Throttle position for dispalying
      float a = (((data[THROT_POS1]) << 8)+ (data[THROT_POS2]))/10; 
      Serial.print("Throttle position ");
      Serial.print(a);
      Serial.print("%? ");


      //Calculating and formatting Engine temperature for dispalying
      float o = (((data[ENG_TMP1]) << 8)+ (data[ENG_TMP2]))/10;
      Serial.print("Engine Temp ");
      Serial.print(o);
      Serial.print("C, ");

      //Calculating and formatting Battery voltage for dispalying
      float y = (((data[BAT_VOL1]) << 8)+ (data[BAT_VOL2]))/100;
      Serial.print("Battery voltage ");
      Serial.print(y);
      Serial.print("V; ");

      //Calculating and formatting Oil pressure for dispalying
      float k = (((data[OIL_PRS1]) << 8)+ (data[OIL_PRS2]))/10;
      Serial.print("Oil pressure ");
      Serial.print(k);
      Serial.print("Kpa: ");
    }


  }

}  // end of process_data

/*
This function processes data as they come to the serial buffer
 */

void processIncomingByte (unsigned char inByte)
{
  static unsigned char input_line [MAX_INPUT]; //Self-defined buffer for data
  static unsigned int input_pos = 0; //To determine the index of data in self-defined buffer



  switch (input_pos)
  {

  case MAX_INPUT:   // When arrive to the end of self-defined buffer, process and format data

    process_data (input_line);

    // reset buffer for next time
    input_pos = 0;  
    break;

    //case '\r':   // discard carriage return
    // break;

  default:
    // keep adding if not full 
    if (input_pos < (MAX_INPUT))
      input_line [input_pos++] = inByte;

    break;

  }  // end of switch

} // end of processIncomingByte  


void loop()
{
  // if serial data available, process it
  if (Serial1.available () > 0)
    processIncomingByte (Serial1.read ());

  // do other stuff here like testing digital input (button presses) ...

}  // end of loop

The Xbee which is receiving the data from the external device wirelessly is connected to the Serial port 1 of a Mega board. I was wondering could you guys think of any modifications to the code to make it faster. Personally, I would assume that the RAM usage is the main culprit in slowing the process down and I was thinking maybe if I use EEPROM, somehow the code might run faster. What do you guys think?

Personally, I would assume that the RAM usage is the main culprit in slowing the process down

You think that access to data at one edge of RAM is faster than access to data at the other end? There is not a crippled little odl man fetching data, who has to hobble farther to get to the far end.

and I was thinking maybe if I use EEPROM, somehow the code might run faster.

Use it for what? Storing data in EEPROM is slower than storing it in SRAM. Access data from EEPROM is slower than accessing data from SRAM.

The time is takes to execute the code is a function of how many calculations are needed and where data is stored. Moving stuff to EEPROM is not going to help.

Sending data only as it changes, sending smaller packets, some other algorithm for determining data integrity, etc. are more useful avenues of exploration.

What is the purpose of the function processIncomingByte() ? It looks like it just save the data into an array. Why make that process so complex? The Arduino has very little SRAM. Why not read the data into a global array and save the bother of passing anything to the processData() function?

How long does it take to receive MAX_INPUT characters? You might make better use of the CPU time by waiting until all the characters are in the Serial input buffer before trying to copy them to your own array. That way the input can continue in background.

Do you have any special characters that mark the start and end of a sequence of data? If not how do you know when the data starts?

...R

Hi guys thanks for your replies. First I would like to apologize for the great deal of delay that has been caused in replying. I was very preoccupied and you have my sincere apologies.

What is the purpose of the function processIncomingByte() ? Why not read the data into a global array and save the bother of passing anything to the processData() function?

You are correct. This function reads 104 bytes into the “input_line” array. Then it checks whether all the 104 bytes have been stored. If yes it starts doing stuff to the data bytes through the “process_data()” function. If no it continues storing the bytes until 104 bytes have been stored. I did not consider making the input_line array global. The reason for having “process_data()”to sort things is just having a function to sort and process data. It does not put data into an array, but “processIncomingByte()” does.

How long does it take to receive MAX_INPUT characters? You might make better use of the CPU time by waiting until all the characters are in the Serial input buffer before trying to copy them to your own array. That way the input can continue in background.

I am not exactly how long. I know that the serial buffer can only store 64 bytes and I am storing 104 bytes, so I cannot wait for all data to arrive into serial buffer and then copy them. Actually I thought the fact that this code is not bound by the serial buffer limit was its advantage, but now you are making a good point. I still am not sure how to address this issue and reach a compromise though.

Do you have any special characters that mark the start and end of a sequence of data? If not how do you know when the data starts?

There are three header bytes (0x82,0x81,0x80) that mark the beginning of the data sequence that I am interested in and I check for them in the “process_data()”. The last four bytes of the data are the CRC-32 error checking bytes. I know that there will be 104 bytes and I am checking for storage in “input_line” array in the “processIncomingByte()” function.

Also thanks to PaulS for clarifying my misconception.

Sending data only as it changes, sending smaller packets, some other algorithm for determining data integrity, etc. are more useful avenues of exploration.

I was wondering if you have any particularly good resources or examples showing some of these avenues in use. In terms of the error checking (data integrity) I do not think that I have any other choice as the device that is sending me data uses CRC-32 only and I thought that I am going to have to cope with it.

Many thanks again. :)

JimboJohn: I know that the serial buffer can only store 64 bytes and I am storing 104 bytes, so I cannot wait for all data to arrive into serial buffer and then copy them.

If performance is really an issue I would modify the Hardware Serial code to increase the buffer size so it can take all your data. And if you go that far you might modify it so it writes straight to a buffer that you specify (perhaps have two arrays for incoming data and alternate them). That would save the overhead of copying the data.

Alternatively I would modify the transmitting code so it sends less than 64 bytes.

...R

Cheers :)

I will have a go at it and let you know of the results.