Help Needed: Communication Issue between Teensy 4.1 and Teensy 3.2

Rafa

Member
Hello forum members,

I hope this message finds you well. I am currently facing a communication issue between two Teensy microcontrollers, and I would greatly appreciate any assistance or insights you can provide.

The setup involves a Teensy 4.1 (connected to Serial1) sending data to a Teensy 3.2 (connected to Serial2), and vice versa. Strangely, only the Teensy 4.1 seems to be successful in sending data, while the Teensy 3.2 encounters difficulties when attempting to send messages, and the other Teensy fails to receive them.

I have thoroughly checked my code and connections, but I haven't been able to identify the root cause of this problem. If anyone has experience with Teensy microcontrollers or has encountered a similar issue, I would be grateful for your guidance.

Here are some details about my setup:

  • Teensy 4.1 (Sender, connected to Serial1) and Teensy 3.2 (Receiver, connected to Serial2)
  • Communication in both directions: Teensy 4.1 (Serial1) to Teensy 3.2 (Serial2) and vice versa
  • Successful data transfer from Teensy 4.1 to Teensy 3.2
  • Unsuccessful data transfer from Teensy 3.2 to Teensy 4.1
If you have any suggestions, recommendations, or if you've experienced a similar problem in the past, please share your insights. I'm eager to resolve this issue and appreciate any assistance you can provide.

Thank you for your time and support!

Best regards,

Teensy 3.2 code

1705357262441.png


1705357306540.png


Teensy 4.1 code

1705357428846.png


1705357495025.png
 
1705365575744.png


Here is my result (serial monitor) that confirms communication with the Teensy 3.6 is working.

1705365869826.png


Every 1 second, I send the message #f through Teensy 4.1. After receiving this data, I need Teensy 3.2 to transmit the data from the "q_encoder" variable.

On Teensy 4.1, I can only read data from the IMU connected to serial port 7. While I can transmit data through serial port 1 to Teensy 3.2, my protocol for reading is not functioning as expected.

1705366303255.png
 
First of all can you post your code as text (rather than a picture) using CODE tags using the </> button.
Your method of putting them in a picture means that someone wanting to help has to type all your code again rather than just copying and pasting if you hade just posted text.
 
Thanks for the tips! Here are my codes.

codeTeensy 3.2 - At each interval, I update the values of the 'q_encoder' variable. After receiving the #f characters from Teensy 4.1, I call the 'q_encoder_leg' function, which writes the current value of the variable to the serial port.

Code:
#define intervalo 20 //milisegundos
unsigned long int timestamp = millis();
boolean output_single_on=false;

void q_encoder_leg();

/*Função Principal*/
void setup()
{
  //configuração portas seriais
  Serial.begin(9600);             //serial monitor
  Serial1.begin(BAUD, SERIAL_8N2);//servomotor 5990 x3
  Serial2.begin(115200);//comunication teensy 4.1
}

void loop()
{
  if (millis() - timestamp >= intervalo)
  {
    timestamp = millis(); //atualiza a variável de última varredura
    if(leg_suporte == true)
    {
      q_encoder[0]=-20.0; q_encoder[1]=-30.0; q_encoder[2]=115.0;
      leg_suporte = false;
    }
    else
    {
      q_encoder[0]=20.0; q_encoder[1]=30.0; q_encoder[2]=-115.0;
      leg_suporte = true;
    }
    if (output_single_on) {q_encoder_leg();}
     output_single_on = false;
    #if DEBUG__PRINT_LOOP_TIME == true
            Serial.print("loop time (ms) = ");
            Serial.println(millis() - timestamp);
    #endif
  }
 
  if (Serial2.available() >= 2)
  {
    char command[2];
    Serial2.readBytes((byte*)command, 2);
    if (command[0] == '#') // Start of new control message
    {
      if (command[1] == 'f')
      {
        output_single_on = true;
        Serial.println(command);
      }
    }
  }
 
}

void q_encoder_leg()
{
  Serial2.write((byte*)q_encoder,sizeof(q_encoder));
}

Code Teensy 4.1 - The Teensy 4.1 requests data from the 'q_encoder' variable from Teensy 3.2 by writing '#f' to the serial port. Teensy 3.2 needs to return this requested information. The serial communication on channel 7 is connected to an IMU, and the data is being read correctly. I believe I am having difficulty configuring the serial port on the Teensy 4.1 correctly. I tried setting it up using interrupt for data reception on the serial port, but couldn't get it configured properly. I am working with Teensyduino in the Arduino IDE, and sometimes, I simulate in VS Code.

Code:
#define intervalo 1000
unsigned long int last = millis();
bool ledState = LOW;

void print_q_encoder1();
void print_q_encoder2();
void print_q_encoder3();
void print_q_encoder4();
void print_q_encoder5();
void print_q_encoder6();

void setup()
{
  Serial.begin(9600);     //Monitor
  Serial1.begin(115200);  //Teesy 3.2 1
  //Serial2.begin(115200); //Teesy 3.2 2
  //Serial3.begin(115200); //Teesy 3.2 3
  //Serial4.begin(115200); //Teesy 3.2 4
  //Serial5.begin(115200); //Teesy 3.2 5
  //Serial6.begin(115200); //Teesy 3.2 6
  //Serial7.begin(57600);   //IMU
  //Serial8.begin(57600);  //Nano
  pinMode(ledPin, OUTPUT);
}

void loop()
{
  if (millis() - last >= intervalo)
  {
    last = millis(); //atualiza a variável de última varredura
    Serial1.print("#f"); if (Serial1.available() > 0) {Serial1.readBytes((byte*)q_encoder_1, sizeof(q_encoder_1)); print_q_encoder1();}
    //Serial2.print("#f"); if (Serial2.available() > 0) {Serial2.readBytes((byte*)q_encoder_2, sizeof(q_encoder_2)); print_q_encoder2();}
    //Serial3.print("#f"); if (Serial3.available() > 0) {Serial3.readBytes((byte*)q_encoder_3, sizeof(q_encoder_3)); print_q_encoder3();}
    //Serial4.print("#f"); if (Serial4.available() > 0) {Serial4.readBytes((byte*)q_encoder_4, sizeof(q_encoder_4)); print_q_encoder4();}
    //Serial5.print("#f"); if (Serial5.available() > 0) {Serial5.readBytes((byte*)q_encoder_5, sizeof(q_encoder_5)); print_q_encoder5();}
    //Serial6.print("#f"); if (Serial6.available() > 0) {Serial6.readBytes((byte*)q_encoder_6, sizeof(q_encoder_6)); print_q_encoder6();}
    read_imu();
    //print_q_encoder();

  }
}
 
void print_q_encoder1()
{
  for (int i = 0; i < n_q; i++)
  {
    Serial.print(q_encoder_1[i]); Serial.print(" ");
  } Serial.print("\n");
}

void print_q_encoder2()
{
  for (int i = 0; i < n_q; i++)
  {
    Serial.print(q_encoder_2[i]); Serial.print(" ");
  } Serial.print("\n");
}

void print_q_encoder3()
{
  for (int i = 0; i < n_q; i++)
  {
    Serial.print(q_encoder_3[i]); Serial.print(" ");
  } Serial.print("\n");
}

void print_q_encoder4()
{
  for (int i = 0; i < n_q; i++)
  {
    Serial.print(q_encoder_4[i]); Serial.print(" ");
  } Serial.print("\n");
}

void print_q_encoder5()
{
  for (int i = 0; i < n_q; i++)
  {
    Serial.print(q_encoder_5[i]); Serial.print(" ");
  } Serial.print("\n");
}

void print_q_encoder6()
{
  for (int i = 0; i < n_q; i++)
  {
    Serial.print(q_encoder_6[i]); Serial.print(" ");
  } Serial.print("\n");
}

I am trying to communicate with six Teensy 3.2 boards through the hardware serial ports of Teensy 4.1
 
That’s not the full source code yet i think. What is q_encoder_1, sizeof(q_encoder_1) and where is it declared?

One reason why your T3 fails to see the “#f” could be that it always fetches “f#” instead? This could happen easily if only one extra byte was received say just after a T4 reboot. Better would be sense the incoming stream first for a single ‘#’ and only then read another byte and check if that is ‘f’.
 
Does is behave correctly if you call
Code:
Serial1.flush();
immediately after Serial1.print(...) to ensure that the text has actually been sent?
 
That’s not the full source code yet i think. What is q_encoder_1, sizeof(q_encoder_1) and where is it declared?

One reason why your T3 fails to see the “#f” could be that it always fetches “f#” instead? This could happen easily if only one extra byte was received say just after a T4 reboot. Better would be sense the incoming stream first for a single ‘#’ and only then read another byte and check if that is ‘f’.
It is true what you said. My code is quite extensive. I posted here only the most important part to illustrate that I am not able to establish serial communication between two Teensys with two wires (in full-duplex mode). The variable q_encoder is declared as a global variable in the header like this: float q_encoder[3] = {0.0, 0.0, 0.0}.

Regarding Teensy 3, it can read the two bytes #f sent from Teensy 4 and can change the state of the 'output_single_on' variable (used in the call to the 'q_encoder_leg' function within the 'loop' function). The problem is that after Teensy 3 writes 'q_encoder' through the serial, Teensy 4 is unable to read it
 
Does is behave correctly if you call
Code:
Serial1.flush();
immediately after Serial1.print(...) to ensure that the text has actually been sent?
Does is behave correctly if you call
Code:
Serial1.flush();
immediately after Serial1.print(...) to ensure that the text has actually been sent?
Hello @thebigg! The text from Teensy 4 is reaching Teensy 3. The problem arises when Teensy 3 sends data to Teensy 4. In this case, Teensy 4 is not receiving the information. I believe I'll have to use a hardware serial interrupt on Teensy 4. I am having trouble configuring this.
 
@Rafa the UART code uses interrupts to empty the FIFO's for Rx and fill them for Tx - so that is included.

All that should be needed is the .begin() using a common baud rate and proper wires and connections - and nothing else overriding the pin function - in this case the Tx pin on the T_3.2 - or perhaps that pin having been zapped/broken.

Then any reads or writes to the Serial# UART in use should work - and will be using the underlying interrupt driven data transfer.

If the sketch at hand could be set aside and wiring separated usably - test a simple sketch to drive the Tx pin HIGH and LOW and test the output to be as expected and perhaps set it as input PULLUP to see 3.3V and then touch GND to the pin and see it read showing going from HIGH to LOW.
 
Hello @thebigg! The text from Teensy 4 is reaching Teensy 3. The problem arises when Teensy 3 sends data to Teensy 4. In this case, Teensy 4 is not receiving the information. I believe I'll have to use a hardware serial interrupt on Teensy 4. I am having trouble configuring this.
OK. You surely need to wait for some period between sending the "#f" command and receiving the data. At the moment this code
Code:
Serial1.print("#f"); if (Serial1.available() > 0) {Serial1.readBytes((byte*)q_encoder_1, sizeof(q_encoder_1)); print_q_encoder1();}
sends the command and immediately checks for the response. It is highly unlikely that the message will be transmitted to the T3, processed by the T3 and the response received without some sort of delay. Just as a test try inserting a delay() before checking available() > 0.

Or restrucure the code so you send the command "#f" at regular intervals, but test for the reception of the response unconditionally
 
Try this on the T4 side:

Code:
#define intervalo 1000
#define n_q 3

float q_encoder_1[3] = {0.0, 0.0, 0.0};
float q_encoder_2[3] = {0.0, 0.0, 0.0};
float q_encoder_3[3] = {0.0, 0.0, 0.0};
float q_encoder_4[3] = {0.0, 0.0, 0.0};
float q_encoder_5[3] = {0.0, 0.0, 0.0};
float q_encoder_6[3] = {0.0, 0.0, 0.0};

unsigned long int timestamp_last = millis();
void print_q_encoder1();
void print_q_encoder2();
void print_q_encoder3();
void print_q_encoder4();
void print_q_encoder5();
void print_q_encoder6();

void setup()
{
  Serial.begin(9600);     //Monitor
  Serial1.begin(115200);  //Teesy 3.2 1
  Serial2.begin(115200); //Teesy 3.2 2
  Serial3.begin(115200); //Teesy 3.2 3
  Serial4.begin(115200); //Teesy 3.2 4
  Serial5.begin(115200); //Teesy 3.2 5
  Serial6.begin(115200); //Teesy 3.2 6
//  Serial7.begin(57600);   //IMU
//  Serial8.begin(57600);  //Nano
//  pinMode(ledPin, OUTPUT);
}

void loop()
{
  unsigned long int timestamp_now = millis();
  if ((timestamp_now - timestamp_last) >= intervalo)
  {
    timestamp_last = timestamp_now; //atualiza a variável de última varredura
    Serial1.flush();
    Serial2.flush();
    Serial3.flush();
    Serial4.flush();
    Serial5.flush();
    Serial6.flush();

    Serial1.print("#f");
    Serial2.print("#f");
    Serial3.print("#f");
    Serial4.print("#f");
    Serial5.print("#f");
    Serial6.print("#f");
 //   read_imu();
    //print_q_encoder();

  }

  if (Serial1.available() >= (int)sizeof(q_encoder_1)) {Serial1.readBytes((byte*)q_encoder_1, sizeof(q_encoder_1)); print_q_encoder1();}
  if (Serial2.available() >= (int)sizeof(q_encoder_2)) {Serial1.readBytes((byte*)q_encoder_1, sizeof(q_encoder_2)); print_q_encoder2();}
  if (Serial3.available() >= (int)sizeof(q_encoder_3)) {Serial1.readBytes((byte*)q_encoder_1, sizeof(q_encoder_3)); print_q_encoder3();}
  if (Serial4.available() >= (int)sizeof(q_encoder_4)) {Serial1.readBytes((byte*)q_encoder_1, sizeof(q_encoder_4)); print_q_encoder4();}
  if (Serial5.available() >= (int)sizeof(q_encoder_5)) {Serial1.readBytes((byte*)q_encoder_1, sizeof(q_encoder_5)); print_q_encoder5();}
  if (Serial6.available() >= (int)sizeof(q_encoder_6)) {Serial1.readBytes((byte*)q_encoder_1, sizeof(q_encoder_6)); print_q_encoder6();}
}

void print_q_encoder1()
{
  for (int i = 0; i < n_q; i++)
  {
    Serial.print(q_encoder_1[i]); Serial.print(" ");
  } Serial.print("\n");
}

void print_q_encoder2()
{
  for (int i = 0; i < n_q; i++)
  {
    Serial.print(q_encoder_2[i]); Serial.print(" ");
  } Serial.print("\n");
}

void print_q_encoder3()
{
  for (int i = 0; i < n_q; i++)
  {
    Serial.print(q_encoder_3[i]); Serial.print(" ");
  } Serial.print("\n");
}

void print_q_encoder4()
{
  for (int i = 0; i < n_q; i++)
  {
    Serial.print(q_encoder_4[i]); Serial.print(" ");
  } Serial.print("\n");
}

void print_q_encoder5()
{
  for (int i = 0; i < n_q; i++)
  {
    Serial.print(q_encoder_5[i]); Serial.print(" ");
  } Serial.print("\n");
}

void print_q_encoder6()
{
  for (int i = 0; i < n_q; i++)
  {
    Serial.print(q_encoder_6[i]); Serial.print(" ");
  } Serial.print("\n");
}

What's different here is that:
* The serial receive buffers are all flushed so that whatever may have been received before is ignored.
* Reading the serial buffers will only commence if a full packet has arrived. What you did before was starting to read already if only one byte had arrived. That makes the code 'blocking', it will remain stuck at that point if a byte is missed. And then block all other channels also. And fail to re-issue the next "#f" poll.
* No matter what, the polls will be issued every second.
 
Back
Top