baudrate problem with teensy to teensy byte package communication

Status
Not open for further replies.

Lorenzo

Well-known member
Good evening forum!

I am trying to send data from a Teensy 3.2 to a Teensy 3.5 through Serial communication.
I am sending a 34 bytes package on Serial1 (to Serial1).
The code for the T3.2 and the T3.5 are implemented inside an IntervalTimer.

In particular if I am using a baudrate of 115200 for the communication and 1000 ms as the interval time, the communication blocks.
Also with 2000ms it does not work properly. (It works properly with 333 Hz - 3000ms, but I need at least 500 Hz for my project).
I have tried to increase the baud rate to 230400 but, after some seconds, the communication is blocked again with both 2000 and 1000ms of interval timer.

I just would like to understand what is the maximum baud rate for a Teensy to Teensy communication and what are the best configurations (baudrate and time interval) to make the communication works at at least 500Hz with a package of 30 bytes.

Thank you very much for any suggestion! :rolleyes:
 
Last edited:
if you want high speed, faster than uart, check out SPI_MSTransfer
you can transfer data from master to slave or slave to master at 30mhz, we’re talking microsecond transfer rates
30 bytes transfer could be just under 25uS i would say

the 3.2 can be slave or master, and 3.5 can be either as well
its your choice
 
Thank you for the suggestion.
Unfortunately Teensy 3.2 has only one SPI port and I am already using it.
I need to use a serial communication... Any suggestion on how to improve it?
If you have any hint about the interval time and the baudrate I would be grateful :)
 
you could do 2 mbits, maybe more, 115200 is too slow, just serup your protocol in loop AND in serialevent so u get the data as soon as it comes asap, otherwise you need to use RTS/CTS, i was able to do 3mbit testing on teensy just RX/TX only ( only because the crystal on the ESP supported a max baudrate of 3megabaud, otherwise it could have went higher

i believe you can run up to 6 mbits
 
It shouldn't block, since 34 bytes fits in the transmit buffer and takes only 2.95 ms to transmit at 115200 baud.

To specifically answer your question, the maximum baud rate is 6 MBit/sec. With short messages sent infrequently, you shouldn't need flow control, which often is needed for such speeds when larger data is used.

Why it's not working, I don't know. Maybe something in your code isn't quite right?
 
There could be something wrong in the code :)

I have implemented the sending and receiving function inside an interval timer because I really need to send data at a specific frequency.


This is the interval timer function that sends the data:

Code:
void functionSERIALTimer()
{
  unsigned long timer_local = timer;
  unsigned long counter_local = counter;
  
  noInterrupts();
  float ENC_1_pos_local = ENC_1_pos;
  float ENC_2_pos_local = ENC_2_pos;
  float ENC_1_omega_local = ENC_1_omega_f; // FILTRATO
  float ENC_2_omega_local = ENC_2_omega_f; // FILTRATO
  float LC_1_local = LC_1;
  float LC_2_local = LC_2;
  float POT_pos_local = POT_pos;
  float POT_punto_local = POT_punto;
  interrupts();
  
  uint8_t* pointer;
  int16_t val;

  // START
  dataPacket[0] = 0x01;
  dataPacket[1] = 0x02;
  dataPacket[2] = 0x03;

  //Timestamp
  pointer = (uint8_t*)&timer_local;
  dataPacket[3] = pointer[0];
  dataPacket[4] = pointer[1];
  dataPacket[5] = pointer[2];
  dataPacket[6] = pointer[3];

  //Cycles
  pointer = (uint8_t*)&counter_local;
  dataPacket[7] = pointer[0];
  dataPacket[8] = pointer[1];
  dataPacket[9] = pointer[2];
  dataPacket[10] = pointer[3];

  //Encoder 1 POS
  val = int16_t(ENC_1_pos_local * 100);
  pointer = (uint8_t*)&val;
  dataPacket[11] = pointer[0];
  dataPacket[12] = pointer[1];

  //Encoder 2 POS
  val = int16_t(ENC_2_pos_local * 100);
  pointer = (uint8_t*)&val;
  dataPacket[13] = pointer[0];
  dataPacket[14] = pointer[1];

  //Encoder 1 OMEGA
  val = int16_t(ENC_1_omega_local * 100);
  pointer = (uint8_t*)&val;
  dataPacket[15] = pointer[0];
  dataPacket[16] = pointer[1];

  //Encoder 2 OMEGA
  val = int16_t(ENC_2_omega_local * 100);
  pointer = (uint8_t*)&val;
  dataPacket[17] = pointer[0];
  dataPacket[18] = pointer[1];

  //Load cell 1
  val = int16_t(LC_1_local * 100);
  pointer = (uint8_t*)&val;
  dataPacket[19] = pointer[0];
  dataPacket[20] = pointer[1];

  //Load cell 2
  val = int16_t(LC_2_local * 100);
  pointer = (uint8_t*)&val;
  dataPacket[21] = pointer[0];
  dataPacket[22] = pointer[1];

  //Potentiometer_pos
  val = int16_t(POT_pos_local * 100);
  pointer = (uint8_t*)&val;
  dataPacket[23] = pointer[0];
  dataPacket[24] = pointer[1];

  //Potentiometer_punto
  val = int16_t(POT_punto_local * 100);
  pointer = (uint8_t*)&val;
  dataPacket[25] = pointer[0];
  dataPacket[26] = pointer[1];

  // STOP
  dataPacket[27] = 0x04;
  dataPacket[28] = 0x05;
  dataPacket[29] = 0x06;

  SERIAL_OUT.write(dataPacket, BYTE_DATA_PACKET);

  counter++;
  timer = millis();
  serial_counter++;


}


And this is the function that receives the package on Teency 3.5:

Code:
void functionSerialINCOMINGTimer()
{



  uint8_t bSERIAL_IN;
  if (SERIAL_IN.available() > 0)
  {
    bSERIAL_IN = 0;
    while (!(bSERIAL_IN >= BYTE_SERIAL_INCOMING_PACKET))
    {
      if ((SERIAL_IN.available() > 0) && (bSERIAL_IN < BYTE_SERIAL_INCOMING_PACKET))
      {
        SERIAL_Incoming_Data.vData[bSERIAL_IN] = SERIAL_IN.read();
        bSERIAL_IN++;
      }
    }

    if (checkPacket(SERIAL_Incoming_Data.vData))
    {
      extractData(SERIAL_Incoming_Data.Raw);
     }

If I implement the serial communication in the void loop I will not be sure about the timing, right?

Thank you
 
What is the other SPI device?

SPI is a multi drop bus solution - each device gets a unique CS - chip select - when activated only that device responds.

If the other device is properly behaved - you can use the same SPI bus to the T_3.5 with a unique CS - pick the T_3.2 to run the Master code and then run a Slave sketch on the T_3.5.

Ideally it will run faster but even at 12 MHz SPI the transfer will be under 100 micros - and if it can run at 30 MHz as it should it would transfer in under 40 micros with a CRC checked transfer.

We've done some intense testing - usually with T_3.5 or T_3.6 as Master and T_3.x as Slave - but no reason it shouldn't work based on the Master being more standard SPI, and the Slave being the 'manually done one' that the T_3.5 has run.

If you give details tonton81 and I would be happy to help see if it works to get more test coverage on what is a very cool library he has created.
 
you could do 2 mbits, maybe more, 115200 is too slow, just serup your protocol in loop AND in serialevent so u get the data as soon as it comes asap, otherwise you need to use RTS/CTS, i was able to do 3mbit testing on teensy just RX/TX only ( only because the crystal on the ESP supported a max baudrate of 3megabaud, otherwise it could have went higher

i believe you can run up to 6 mbits

Is the problem due to the fact that the protocol is inside an interval timer?
 
What is the other SPI device?

SPI is a multi drop bus solution - each device gets a unique CS - chip select - when activated only that device responds.

If the other device is properly behaved - you can use the same SPI bus to the T_3.5 with a unique CS - pick the T_3.2 to run the Master code and then run a Slave sketch on the T_3.5.

Ideally it will run faster but even at 12 MHz SPI the transfer will be under 100 micros - and if it can run at 30 MHz as it should it would transfer in under 40 micros with a CRC checked transfer.

We've done some intense testing - usually with T_3.5 or T_3.6 as Master and T_3.x as Slave - but no reason it shouldn't work based on the Master being more standard SPI, and the Slave being the 'manually done one' that the T_3.5 has run.

If you give details tonton81 and I would be happy to help see if it works to get more test coverage on what is a very cool library he has created.

Thank you for the interesting suggestions.
The other SPI device is a Dual Encoder Breakout and I am using it to read two encoders at 2000 Hz (in an interval timer function). Then the encoder data are elaborated and send to Teensy 3.5 with all the other data of the 34-bytes package as fast as possible (500 or 1000 Hz if possible).

If I had another SPI port I would be happy to test your library :)
 
you could do 2 mbits, maybe more, 115200 is too slow, just serup your protocol in loop AND in serialevent so u get the data as soon as it comes asap, otherwise you need to use RTS/CTS, i was able to do 3mbit testing on teensy just RX/TX only ( only because the crystal on the ESP supported a max baudrate of 3megabaud, otherwise it could have went higher

i believe you can run up to 6 mbits

Do you mean setup the transmission in the main loop and the receiving in SerialEvent()?
How can I be sure about the transmission frequency in this case?
Thank you
 
This looks like a busy loop waiting for data, inside an interrupt.

Code:
void functionSerialINCOMINGTimer()
{

  uint8_t bSERIAL_IN;
  if (SERIAL_IN.available() > 0)
  {
    bSERIAL_IN = 0;
    while (!(bSERIAL_IN >= BYTE_SERIAL_INCOMING_PACKET))
    {
      if ((SERIAL_IN.available() > 0) && (bSERIAL_IN < BYTE_SERIAL_INCOMING_PACKET))
      {
        SERIAL_Incoming_Data.vData[bSERIAL_IN] = SERIAL_IN.read();
        bSERIAL_IN++;
      }
    }

    if (checkPacket(SERIAL_Incoming_Data.vData))
    {
      extractData(SERIAL_Incoming_Data.Raw);
     }

Have you considered what happens when that while loop has to wait? Perhaps your interrupt end up getting part of the data from the end of 1 transmission, then sits there waiting and completes reading the first part of the next transmission.

My gut feeling is this is a poor design on at least 2 levels. First, busy looping for an indeterminate amount of time inside an interrupt, which could go on for 1 second or more, is just asking for trouble.

Second, even if this were done from main program context, a while loop which collects a fixed amount of data without any parsing for being-of-message or end-of-message markers is just asking for more trouble. This sort of code inherently gets confused when data doesn't arrive as expected. If any bytes are missed for whatever reason, it can forever remain out of sync with the data stream and never recover, even after thousands of perfectly good messages received.

You really should design this code to look for those 3-byte start and stop sequences you put in the transmit code. Maybe use an elapsedMillis variable to track how long since the previous data too. If it's been too long, discard your partial message. But if your message as a well defined 3 byte start, never just blindly collect a fixed number of bytes. Parse for your start sequence and only begin piling data into the buffer when you know you're at the beginning of a new message. If you only parse the message later, your acquire code can get confused and ruin the whole project.
 
This looks like a busy loop waiting for data, inside an interrupt.



Have you considered what happens when that while loop has to wait? Perhaps your interrupt end up getting part of the data from the end of 1 transmission, then sits there waiting and completes reading the first part of the next transmission.

My gut feeling is this is a poor design on at least 2 levels. First, busy looping for an indeterminate amount of time inside an interrupt, which could go on for 1 second or more, is just asking for trouble.

Second, even if this were done from main program context, a while loop which collects a fixed amount of data without any parsing for being-of-message or end-of-message markers is just asking for more trouble. This sort of code inherently gets confused when data doesn't arrive as expected. If any bytes are missed for whatever reason, it can forever remain out of sync with the data stream and never recover, even after thousands of perfectly good messages received.

You really should design this code to look for those 3-byte start and stop sequences you put in the transmit code. Maybe use an elapsedMillis variable to track how long since the previous data too. If it's been too long, discard your partial message. But if your message as a well defined 3 byte start, never just blindly collect a fixed number of bytes. Parse for your start sequence and only begin piling data into the buffer when you know you're at the beginning of a new message. If you only parse the message later, your acquire code can get confused and ruin the whole project.

Thank you very much for the useful information and suggestions Paul.

I have already implemented the function "checkPacket(SERIAL_Incoming_Data.vData)" that checks the start and the end of the package. I will implement a check on the start bytes before collecting the whole message.

If I move the receiving code in the void loop, how can I be sure it will be executed at the frequency of 1000Hz?
At the end of the project my void loop will be really busy with a lot of computations to do.
Should I leave the sending code (in Teensy 3.2) inside the interrupt or move it to the void loop in the same manner?
I am asking this because I am trying to make the communication as more deterministic as possible. Thank you again!
 
If I move the receiving code in the void loop, how can I be sure it will be executed at the frequency of 1000Hz?

How can you know whether it will execute at all, even using the interrupt? I mean, if you disconnect the data signal it will just wait forever and never execute anything else other than the loop which waits for data.

Even Worse, it will wait within an interrupt, meaning other interrupts at the same and lower priority are blocked. Fortunately Teensy 3.2 has nested priority interrupts and the default priority levels are assigned in a way that allows Serial, Serial1 and millis() / elapsedMillis to still work. Well, at least if you haven't altered the priority of your interrupt. If you give your interrupt top priority, all others will be blocked. Spending a long time within an interrupt routine is risky business. It can be done, but usually should be avoided.

Anyway, regardless of which way you write the code, isn't the receive timing ultimately paced by the arrival of data from the other side?
 
While the loop() is empty it will run as fast there as anywhere without being able to hold up or conflict with the interrupt processing. Push the baud rate to 2 Mbaud or so and get it working reliably with just a flag set in the interrupt perhaps to push the output. While empty - if the SPI processing leaves time loop would generally repeat 100K times /second at a minimum.

Sending out 500 sets of 34 bytes takes at least 170,000 bits per second or the buffers will fill faster than empty even in a perfect world. Servicing the SPI interrupts and the interrupts to feed the outgoing Serial1 FIFO will add overhead even before adding any other loop() processing on either end.

That alone with higher baud rate should be no trouble to perfect on empty loop()'s.

How that changes when code is added on one end or the other will be challenge to work with when that happens.
 
How can you know whether it will execute at all, even using the interrupt? I mean, if you disconnect the data signal it will just wait forever and never execute anything else other than the loop which waits for data.

Even Worse, it will wait within an interrupt, meaning other interrupts at the same and lower priority are blocked. Fortunately Teensy 3.2 has nested priority interrupts and the default priority levels are assigned in a way that allows Serial, Serial1 and millis() / elapsedMillis to still work. Well, at least if you haven't altered the priority of your interrupt. If you give your interrupt top priority, all others will be blocked. Spending a long time within an interrupt routine is risky business. It can be done, but usually should be avoided.

Anyway, regardless of which way you write the code, isn't the receive timing ultimately paced by the arrival of data from the other side?

Thank you Paul.
Following your suggestions, I have moved the receiving part of the code in the void loop and implemented the check for the first three bytes.
Now the baud rate is set to 230400 and I am sending data at 500 Hz.
In the following you can find my code, but It still does not work properly.
(I am printing the couters from the loop and other timers to check the funtionality, see attached picture).

Code:
void loop()
{
  uint8_t bSERIAL_IN;
  if (SERIAL_IN.available() > 0)
  {

    bSERIAL_IN = 0;
    while (!(bSERIAL_IN >= 3))
    {
      if ((SERIAL_IN.available() > 0) && (bSERIAL_IN < 3))
      {
        SERIAL_Incoming_Data.vData[bSERIAL_IN] = SERIAL_IN.read();
        bSERIAL_IN++;
      }
    }
    if (checkPacket_start(SERIAL_Incoming_Data.vData))
    {
      //bSERIAL_IN = 0;
      while (!(bSERIAL_IN >= BYTE_SERIAL_INCOMING_PACKET))
      {
        if ((SERIAL_IN.available() > 0) && (bSERIAL_IN < BYTE_SERIAL_INCOMING_PACKET))
        {
          SERIAL_Incoming_Data.vData[bSERIAL_IN] = SERIAL_IN.read();
          bSERIAL_IN++;
        }
      }
    }
    else
    {
      bSERIAL_IN = 0;
    }
    if (checkPacket_end(SERIAL_Incoming_Data.vData))
    {
      extractData(SERIAL_Incoming_Data.Raw);

      for (uint8_t idx = 3; idx < BYTE_SERIAL_INCOMING_PACKET - 3; idx++)
      {
        dataPacket[idx] = SERIAL_Incoming_Data.vData[idx];
      }

    }
  }

  

  t = millis();
  delta_t = t - t0;

  if (delta_t >= 1000)
  {
    t0 = t;
    noInterrupts();
    unsigned long counter32_local = CYCLES;
    unsigned long motor_control_counter_local = motor_control_counter;
    unsigned long sd_card_counter_local = sd_card_counter;
    interrupts();

    unsigned long delta_counter32 = counter32_local - counter32_old;
    unsigned long delta_motor_control_counter = motor_control_counter_local - motor_control_counter_old;
    unsigned long delta_serial_incoming_counter = serial_incoming_counter - serial_incoming_counter_old;
    unsigned long delta_sd_card_counter = sd_card_counter_local - sd_card_counter_old;

 
    Serial.print(counter32_local);
    Serial.print("; D: ");
    Serial.print(delta_counter32);
    Serial.print("; Ds: ");
    Serial.print(delta_serial_incoming_counter);
    Serial.println();

    counter32_old = counter32_local;
    motor_control_counter_old = motor_control_counter_local;
    serial_incoming_counter_old = serial_incoming_counter;
    sd_card_counter_old = sd_card_counter_local;
  }
  
  serial_incoming_counter++;
  serial_incoming_time = millis();
  
}


boolean checkPacket(uint8_t *buffer)
{
  return (buffer[0] == 0x01 && buffer[1] == 0x02 && buffer[2] == 0x03 && buffer[BYTE_SERIAL_INCOMING_PACKET - 3] == 0x4
          && buffer[BYTE_SERIAL_INCOMING_PACKET - 2] == 0x5 && buffer[BYTE_SERIAL_INCOMING_PACKET - 1] == 0x6);
}

boolean checkPacket_start(uint8_t *buffer)
{
  return (buffer[0] == 0x01 && buffer[1] == 0x02 && buffer[2] == 0x03);
}

boolean checkPacket_end(uint8_t *buffer)
{
  return (buffer[BYTE_SERIAL_INCOMING_PACKET - 3] == 0x4
          && buffer[BYTE_SERIAL_INCOMING_PACKET - 2] == 0x5 && buffer[BYTE_SERIAL_INCOMING_PACKET - 1] == 0x6);
}

serial monitor.png
 
I might look at this later, but I must admit I'm having a hard time reading your code with visually similar variable names SERIAL_IN, bSERIAL_IN, SERIAL_Incoming_Data. This 3rd one appear to be a struct or union, or maybe a C++ class? A code fragment without showing the type info makes this harder than it needs to be...
 
I might look at this later, but I must admit I'm having a hard time reading your code with visually similar variable names SERIAL_IN, bSERIAL_IN, SERIAL_Incoming_Data. This 3rd one appear to be a struct or union, or maybe a C++ class? A code fragment without showing the type info makes this harder than it needs to be...

Thank you very much.
Yes, SERIAL_Incoming_Data. is a union that collects the incoming data.
In the code there are two more timers: one for the control of two motors and one for the writing on SD card. A third one will be added to send data to the laptop via serial at 25 or 50 Hz (just for a check).
Here it is my complete code for Teensy 3.5. The one on T3.2 just send the data inside a timer at 500 Hz and It seems to work properly.
View attachment Teensy35_code.ino
 
Maybe you could trim this a bit and make it a little easier to read, for the sake of those of us who might try to help figure out what's wrong?

As a very first step, the file is 581 lines, but a huge number are commented out code. At the very least you could make a copy without all that extraneous stuff, right?

Surely you can do better than naming a variable "bSERIAL_IN" when you have at least two other "SERIAL_I" things interwoven through the code. Maybe just put "Serial1" in the code, rather than #define SERIAL_IN. If "bSERIAL_IN" is actually doing something like a flag or count of bytes, maybe you could give it a name that indicates what it does (or is meant to do, at least)?

Look, I'm sure you're trying to follow some sort of coding convention or naming scheme, but what I'm trying to say here is your code is nearly unreadable due to these similar names. I can only put so much time & effort into reading your code, and this is just beyond my effort threshold to untangle these confusingly similar names.
 
Note: I have not studied the code in detail, but maybe a few observations and/or questions.

Things like, your data structure you are sending between the two processors needing to be packed...
Code:
#pragma pack(push, 1)
struct structPacket
{
  uint8_t Start_bytes[3];
  unsigned long timestamp;
  unsigned long cycles;
  int16_t encoder_1_pos;
  int16_t encoder_2_pos;
  int16_t encoder_1_omega;
  int16_t encoder_2_omega;
  int16_t load_cell_1;
  int16_t load_cell_2;
  int16_t pot_pos;
  int16_t pot_punto;
  uint8_t Stop_bytes[3];
};
#pragma pack(pop)
If you control both sides of the communications, why not setup the structure in a way that does not need packing. Could simply make your Start Bytes be 4 bytes in length, which would then have timeStamp be aligned properly.

I believe there is more processing required to access variables that are not on their natural boundaries. Maybe not... Been playing with to many different processors lately.

You set the baud rate to: Serial1.begin(230400);

I am not sure what is your CPU speed for the two processors and how close to the baud rate both processors are actually communicating. That is when you call Serial1.begin with 230400 it converts this to a baud rate divisor using: define BAUD2DIV(baud) (((F_CPU * 2) + ((baud) >> 1)) / (baud))

If the two processors are different enough could get some characters that are misread.

Your error detection and recovery might want to be fortified a little. Things that I would do include:
a) Maybe time stamp when I received the first byte of a packet. If I don't receive the rest of it within some logical time frame, I assume garbage and reset.

b) If your check start fails, you may want to do as you currently do and toss everything... But alternatively you may want to check to see if you may be misaligned. You may want to setup a semi state machine to read in the packet... For example in code that I have to read in Dynamixel Servo data, which has packets sort of like: ff ff <id> <length><instruction>[Parameters] <checksum>

There is input code that tries to read in packets, that looks for the first FF if the input byte is not an ff it tosses the character, and waits for the next. If FF then go into state 2ndFF. If the next character is an FF go into ID state, else go back to look for first FF state. if the ID byte is an FF (not valid ID), stay in 2nd ID as we did have two FFs... Else go to length ... until we get to checksum which verify and only then do we process the packet. Note: the code also does as I mention check for timeouts...

Hope that helps some
 
Thank you for the suggestions, I will try to implement both the 4th start byte in the packet and a sort of state machine to read the incoming data.

I am not sure what is your CPU speed for the two processors and how close to the baud rate both processors are actually communicating. That is when you call Serial1.begin with 230400 it converts this to a baud rate divisor using: define BAUD2DIV(baud) (((F_CPU * 2) + ((baud) >> 1)) / (baud))

If the two processors are different enough could get some characters that are misread.

Actually, Teensy 3.2 works at 96 MHz whereas Teensy 3.5 at 120 MHz (by default, I have not changed anything).
I have tryed to modify the Teensy3.5 120 MHz to 96 MHz in order to have the same clock on both microcontrollers but the reading of incoming data stops working as well after some time.

Could it be a problem with the serial buffer?
Should I clear the buffer after some cycles?
 
Last edited:
I have not done the full math to know what actual baud rate is generated for each board. I have done it in the past using baud rate like 2000000 and it works fine as 120000000/2000000 and 96000000/2000000 are both whole numbers so no baud rate error...
I also in the past double checked it with Logic Analyzer.

As I mentioned in previous posting, sometimes it helps to have some reasonable error detection and recovery... As I mentioned I would check to see if the data came in within a prescribed amount of time. If your also expecting that your packets will be sent again at prescribed intervals, I might also either clear buffers or again check if the first byte arrives before I expect it, to then also go into an error recovery mode. Example if I am receiving data on my Robot from the Arbotix Commander (Atmega... XBee sending command packets N times per second). If I get an error in these cases. I clear my buffer and then wait until I get a sufficient gap in time between characters before I return. Example maybe wait for time between characters > 3 or maybe 5 times time it takes to send a character, so I then think I should be aligned with the next character should be the start of a packet.
 
I am curious about the use of noInterrupts () interrupts() block when used in the routines running in interrupt context. If you issue an interrupts() command, does that enable all interrupts right then and subject the program to the possible condition that a 2nd interrupt may enter the same routine? Meaning you could have the processor enter non-reentrant code.
 
I have not done the full math to know what actual baud rate is generated for each board. I have done it in the past using baud rate like 2000000 and it works fine as 120000000/2000000 and 96000000/2000000 are both whole numbers so no baud rate error...
I also in the past double checked it with Logic Analyzer.

As I mentioned in previous posting, sometimes it helps to have some reasonable error detection and recovery... As I mentioned I would check to see if the data came in within a prescribed amount of time. If your also expecting that your packets will be sent again at prescribed intervals, I might also either clear buffers or again check if the first byte arrives before I expect it, to then also go into an error recovery mode. Example if I am receiving data on my Robot from the Arbotix Commander (Atmega... XBee sending command packets N times per second). If I get an error in these cases. I clear my buffer and then wait until I get a sufficient gap in time between characters before I return. Example maybe wait for time between characters > 3 or maybe 5 times time it takes to send a character, so I then think I should be aligned with the next character should be the start of a packet.

Thank you all for the precious suggestions.
I have modified the baud rate to 2000000, both T3.2 and T3.5 are working at 96 MHz, T3.2 sends data at 1 kHz (seems properly) and T3.5 tries to receive data at 1 kHz in the main loop. Then data are saved in the SD card at 1 kHz. The code seems to work properly, but after some time there are some gaps during which no data are received.
Please find attached a plot of the timer (received from T3.2) vs milliseconds. It increments properly for a certain period, then there is an error and the values keeps constant...then it works again. timer32 vs ms.png

This is my current version of the receiving code. I have tried to implement a check on the first three bytes of the packet and the extraction of data only when also the final check is ok. A Serial1.clear(); is executed when the packet check is not ok. time_packet_arrived=millis() is then printed every second on the serial monitor and it shows increments of 1000ms (when the code works) and of lower values (then 0) during the non-working gap.
What else could I try to modify?
Thank you.

Code:
uint8_t flag_save=0;
  uint8_t input_bytes;
  
  if (Serial1.available() > 0)
  {

    input_bytes = 0;
    while (!(input_bytes >= 3))
    {
      if ((Serial1.available() > 0) && (input_bytes < 3))
      {
        SERIAL_Incoming_Data.vData[input_bytes] = Serial1.read();
        input_bytes++;
        
      }
    }
    if (checkPacket_start(SERIAL_Incoming_Data.vData))
    {
      time_packet_arrived=millis();
      flag_save=1;
      //input_bytes = 0;
      while (!(input_bytes >= BYTE_SERIAL_INCOMING_PACKET))
      {
        if ((Serial1.available() > 0) && (input_bytes < BYTE_SERIAL_INCOMING_PACKET))
        {
          SERIAL_Incoming_Data.vData[input_bytes] = Serial1.read();
          input_bytes++;
        }
      }

      
    }
    else
    {
      Serial1.clear();
      input_bytes = 0;
    }
    if ((checkPacket_end(SERIAL_Incoming_Data.vData)) && (flag_save==1))
    {
      serial_incoming_counter++;
      extractData(SERIAL_Incoming_Data.Raw);

      for (uint8_t idx = 3; idx < BYTE_SERIAL_INCOMING_PACKET - 3; idx++)
      {
        dataPacket[idx] = SERIAL_Incoming_Data.vData[idx];
      }

    }
  }
 
Status
Not open for further replies.
Back
Top