Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 8 of 8

Thread: UART + I2C display --> not working over 1200 baud rate for UART

  1. #1
    Junior Member
    Join Date
    Jun 2021
    Posts
    4

    UART + I2C display --> not working over 1200 baud rate for UART

    Hello everyone, please help me wandering lost in dark
    I am trying to use two teensy 4.0 and communicate with each other by UART.
    Thing is, UART communication works fine,
    but whenever I try to show the communication result through the I2C display (by adafruit)
    error occurs over the baudrate 1200 of UART.
    1200 baudrate seems to be too slow to use, so I need higher baudrate

    here is the code and the wiring

    // Serial Sender
    Code:
    int pin0 = A0;
    int pin1 = A1;
    unsigned long my_time;
    int reset_switch = 16;
    int reset_pin = 0;
    
    void setup() {
      // put your setup code here, to run once:
      pinMode(reset_switch, INPUT_PULLUP);
    Serial.begin(9600);
    Serial1.begin(9600);
    Serial.println("Start Send");
    if(Serial.available()>0){
      Serial.flush();
      delay(50);
      }
    if(Serial1.available()>0){
    Serial1.flush();
    delay(50);
    }
    }
    
    void loop() {
      reset_pin = digitalRead(reset_switch);
      if(reset_pin == LOW){
        do_reset();
      }
      int val0 = map(analogRead(pin0), 0, 1023, 0, 1100); 
      int val1 = map(analogRead(pin1), 0, 1023, 0, 200);
      
      my_time = millis();
      Serial1.print("<");
      Serial1.print(val0);
      Serial1.print(",");
      Serial1.print(val1);  
      Serial1.print(">");
    
      Serial.print(reset_pin);
      Serial.print("\t");
      Serial.print(my_time);
      Serial.print("\t");
      Serial.print(val0);
      Serial.print("\t");
      Serial.println(val1);
    
    }
    
    void do_reset() {
      // send reboot command -----
      SCB_AIRCR = 0x05FA0004;
    }
    //receiver
    Code:
    //Receiver Code
    
    const byte numChars = 32;
    char receivedChars[numChars];
    char tempChars[numChars];        // temporary array for use when parsing
    
    int integerFromPC = 0;
    float floatFromPC = 0.0;
    
    boolean newData = false;
    
    int reset_switch = 16;
    int reset_pin = 0;
    
    void setup() {
      // put your setup code here, to run once:
      pinMode(reset_switch, INPUT_PULLUP);
      Serial.begin(9600);
      Serial1.begin(9600);
      
      Serial.println("Start Receive");
      
      if(Serial.available()>0){
      Serial.flush();
      delay(50);
      }
      if(Serial1.available()>0){
      Serial1.flush();
      delay(50);
      }
    
      Serial.println("start");
      
    }
    
    void loop() {
      
      reset_pin = digitalRead(reset_switch);
      if(reset_pin == LOW){
        do_reset();
      }  
      
        recvWithStartEndMarkers();
        if (newData == true) {
            strcpy(tempChars, receivedChars);
                // this temporary copy is necessary to protect the original data
                //   because strtok() used in parseData() replaces the commas with \0
            parseData();
            showParsedData();
            newData = false;
        }
    }
    
    
    void recvWithStartEndMarkers() {
        static boolean recvInProgress = false;
        static byte ndx = 0;
        char startMarker = '<';
        char endMarker = '>';
        char rc;
    
        while (Serial1.available() > 0 && newData == false) {
            rc = Serial1.read();
    
            if (recvInProgress == true) {
                if (rc != endMarker) {
                    receivedChars[ndx] = rc;
                    ndx++;
                    if (ndx >= numChars) {
                        ndx = numChars - 1;
                    }
                }
                else {
                    receivedChars[ndx] = '\0'; // terminate the string
                    recvInProgress = false;
                    ndx = 0;
                    newData = true;
                }
            }
    
            else if (rc == startMarker) {
                recvInProgress = true;
            }
        }
    }
    
    //============
    
    void parseData() {      // split the data into its parts
    
        char * strtokIndx; // this is used by strtok() as an index
    
        strtokIndx = strtok(tempChars,",");      // get the first part - the string
        integerFromPC = atoi(strtokIndx);     // convert this part to an integer
    
        strtokIndx = strtok(NULL, ",");
        floatFromPC = atof(strtokIndx);     // convert this part to a float
    
    }
    
    //============
    
    void showParsedData() {
        Serial.print("Integer ");
        Serial.println(integerFromPC);
        Serial.print("Float ");
        Serial.println(floatFromPC);
    }
    
    void do_reset() {
      // send reboot command -----
      SCB_AIRCR = 0x05FA0004;
    }
    Click image for larger version. 

Name:	teensy.jpg 
Views:	8 
Size:	97.3 KB 
ID:	25014

  2. #2
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    8,325
    What exactly means "Not working" and what errors do you see?
    Missing data? corrupted data? No data?

  3. #3
    Junior Member
    Join Date
    Jun 2021
    Posts
    4
    Thank you for the prompt reply!
    I meant that UART communication goes complete failure at over 1200 baud rate.
    However, after changing the board with Teensy 3.2, UART communication seems to work fine but there are quite lots of noise.

    So there are now two questions.
    Is Teensy 4.0 not good for UART with I2C display over 1200 baud rate or would this be simply the soldering problems?
    and, would there be any methods to reduce noises in the UART communication?

    Thank you!

  4. #4
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    24,252
    It's not noise or soldering. (or at least probably is not those issues)

    You're running into somewhat obscure limitation of serial communication where the receiver can't sync to the 8 bit words when it starts "in the middle" of certain bitstreams which use 100% of the serial bandwidth. The more capable the transmitter is of sending without any extra gaps, the worst this problem gets.

    I ran your programs on a breadboard. This is the hardware I used for testing.

    Click image for larger version. 

Name:	img.jpg 
Views:	1 
Size:	43.8 KB 
ID:	25015

    Here is the waveform you're transmitting on pin 1.

    Click image for larger version. 

Name:	file.png 
Views:	1 
Size:	33.6 KB 
ID:	25016

    Can you tell which bits are the start and stop and which are the 8 data bits? If the receiver starts watching before the transmitter begins sending, it should properly detect the first bit as a start bit and thereafter stay properly in sync. But if the transmitter is already running and the receiver has to begin parsing bits in the middle of this, how can it figure out which bits are meant to be start and stop and which are the intended 8 bit data? It can't.

    If your data pattern happens to have groups of mostly 1 or mostly 0 bits, sometimes receivers can find the start bit and get into sync. But for this sort of bit pattern which uses 100% of the bandwidth, there is never an idle moment of 9 bits where the receiver can reliably know the next high-to-low change in the beginning of a start bit.


    Here is a modified copy of your sender, using 1 Mbit baud rate. I added code which waits for 10 microseconds once every 5000 messages.

    Code:
    int pin0 = A0;
    int pin1 = A1;
    unsigned long my_time;
    int reset_switch = 16;
    int reset_pin = 0;
    
    void setup() {
      // put your setup code here, to run once:
      pinMode(reset_switch, INPUT_PULLUP);
      Serial.begin(9600);
      Serial1.begin(1000000);
      Serial.println("Start Send");
      if (Serial.available() > 0) {
        Serial.clear();
        delay(50);
      }
      if (Serial1.available() > 0) {
        Serial1.clear();
        delay(50);
      }
    }
    
    void loop() {
      static int messageCount=0;
      
      reset_pin = digitalRead(reset_switch);
      if (reset_pin == LOW) {
        do_reset();
      }
      int val0 = map(analogRead(pin0), 0, 1023, 0, 1100);
      int val1 = map(analogRead(pin1), 0, 1023, 0, 200);
    
      my_time = millis();
      Serial1.print("<");
      Serial1.print(val0);
      Serial1.print(",");
      Serial1.print(val1);
      Serial1.print(">");
    
      Serial.print(reset_pin);
      Serial.print("\t");
      Serial.print(my_time);
      Serial.print("\t");
      Serial.print(val0);
      Serial.print("\t");
      Serial.println(val1);
    
      // once every 5000 messages, allow a brief silent time
      // for the receiver to detect line idle and then start bit
      if (++messageCount >= 5000) {  
        Serial1.flush(); // wait for buffered data to transmit
        delayMicroseconds(10); // then wait approx 10 bit times
        messageCount = 0;
      }
    
    }
    
    void do_reset() {
      // send reboot command -----
      SCB_AIRCR = 0x05FA0004;
    }

    And to demonstrate the serial word sync issue, here is a copy of your receiver program also using 1 Mbit baud rate. I added a few lines to your recvWithStartEndMarkers() which print info about any unexpected characters received between valid messages.

    Code:
    //Receiver Code
    
    const byte numChars = 32;
    char receivedChars[numChars];
    char tempChars[numChars];        // temporary array for use when parsing
    
    int integerFromPC = 0;
    float floatFromPC = 0.0;
    
    boolean newData = false;
    
    int reset_switch = 16;
    int reset_pin = 0;
    
    void setup() {
      // put your setup code here, to run once:
      pinMode(reset_switch, INPUT_PULLUP);
      Serial.begin(9600);
      Serial1.begin(1000000);
    
      Serial.println("Start Receive");
    
      if (Serial.available() > 0) {
        Serial.clear();
        delay(50);
      }
      if (Serial1.available() > 0) {
        Serial1.clear();
        delay(50);
      }
    
      Serial.println("start");
    
    }
    
    void loop() {
    
      reset_pin = digitalRead(reset_switch);
      if (reset_pin == LOW) {
        do_reset();
      }
      
      recvWithStartEndMarkers();
      if (newData == true) {
        strcpy(tempChars, receivedChars);
        // this temporary copy is necessary to protect the original data
        //   because strtok() used in parseData() replaces the commas with \0
        parseData();
        showParsedData();
        newData = false;
      }
    }
    
    
    void recvWithStartEndMarkers() {
      static boolean recvInProgress = false;
      static byte ndx = 0;
      char startMarker = '<';
      char endMarker = '>';
      char rc;
    
      while (Serial1.available() > 0 && newData == false) {
        rc = Serial1.read();
        //Serial.println((char)rc);
    
        if (recvInProgress == true) {
          if (rc != endMarker) {
            receivedChars[ndx] = rc;
            ndx++;
            if (ndx >= numChars) {
              ndx = numChars - 1;
            }
          }
          else {
            receivedChars[ndx] = '\0'; // terminate the string
            recvInProgress = false;
            ndx = 0;
            newData = true;
          }
        }
    
        else if (rc == startMarker) {
          recvInProgress = true;
        }
        else {
          Serial.print("Unexpected character: ");
          Serial.println(rc);
        }
      }
    }
    
    //============
    
    void parseData() {      // split the data into its parts
    
      char * strtokIndx; // this is used by strtok() as an index
    
      strtokIndx = strtok(tempChars, ",");     // get the first part - the string
      integerFromPC = atoi(strtokIndx);     // convert this part to an integer
    
      strtokIndx = strtok(NULL, ",");
      floatFromPC = atof(strtokIndx);     // convert this part to a float
    
    }
    
    //============
    
    void showParsedData() {
      Serial.print("Integer ");
      Serial.println(integerFromPC);
      Serial.print("Float ");
      Serial.println(floatFromPC);
    }
    
    void do_reset() {
      // send reboot command -----
      SCB_AIRCR = 0x05FA0004;
    }
    If you run this while the sender is already transmitting, you will see it prints many lines about garbage characters. That is scenario where it can't get in sync. Then when the sender gives that 10 microsecond pause every 5000th message, you'll see the receiver does get into sync and all messages are received properly at 1000000 baud rate.

    Click image for larger version. 

Name:	screenshot.png 
Views:	2 
Size:	57.8 KB 
ID:	25017

    Also, you'll probably notice I changed Serial1.flush() to Serial1.clear() in setup. Serial1.flush() waits for output to fully transmit. Serial1.clear() deletes any previously received data. But it only deletes data already in buffers. It can't make the hardware sync in the middle of a 100% bandwidth usages bitstream where there isn't any clear delineation of start bits. No software can do that. It's a fundamental limitation of asynchronous serial communication format. For a receiver to automatically sync, it needs to either start at the first start bit, or occasionally see an idle time between stop and start bits so it can get in sync with the 8 bit words.
    Last edited by PaulStoffregen; 06-10-2021 at 01:29 PM. Reason: added serial monitor screenshot

  5. #5
    Junior Member
    Join Date
    Jun 2021
    Posts
    4
    Thank you for the explanation!
    I tried your method, and the serial communication works totally well.
    However, the display is still under noises...
    And I found out that I did not upload the code for the display, so please find below.

    Code:
    //Receiver Code
    #include <Wire.h>
    #include <Adafruit_GFX.h>       // Include core graphics library for the display
    #include <Adafruit_SSD1306.h>   // Include Adafruit_SSD1306 library to drive the display
    #include <Fonts/FreeMonoBold18pt7b.h>  // Add a custom font
    #include <Fonts/FreeMonoBold12pt7b.h>
    
    //Create display
    Adafruit_SSD1306 display(128, 64);
    
    const byte numChars = 32;
    char receivedChars[numChars];
    char tempChars[numChars];        // temporary array for use when parsing
    
    int integerFromPC = 0;
    float floatFromPC = 0.0;
    
    boolean newData = false;
    
    int reset_switch = 16;
    int reset_pin = 0;
    
    void setup() {
      // put your setup code here, to run once:
      pinMode(reset_switch, INPUT_PULLUP);
      Serial.begin(9600);
      Serial1.begin(1000000);
    
      Serial.println("Start Receive");
    
      if (Serial.available() > 0) {
        Serial.clear();
        delay(50);
      }
      if (Serial1.available() > 0) {
        Serial1.clear();
        delay(50);
      }
    
      Serial.println("start");
        // Display Setting "BRL"g
      delay(100);  // This delay is needed to let the display to initialize
      display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // Initialize display with the I2C address of 0x3C
      display.setTextColor(WHITE);  // Set color of the text
      display.setFont(&FreeMonoBold18pt7b);
      display.clearDisplay();  // Clear the buffer
      display.setCursor(35, 45);
      display.println("BRL");
      display.display();
      delay(1000);
      display.clearDisplay(); 
    }
    
    void loop() {
    
      reset_pin = digitalRead(reset_switch);
      if (reset_pin == LOW) {
        do_reset();
      }
      
      recvWithStartEndMarkers();
      if (newData == true) {
        strcpy(tempChars, receivedChars);
        // this temporary copy is necessary to protect the original data
        //   because strtok() used in parseData() replaces the commas with \0
        parseData();
        showParsedData();
        newData = false;
      }
      display_values();
    }
    
    
    void recvWithStartEndMarkers() {
      static boolean recvInProgress = false;
      static byte ndx = 0;
      char startMarker = '<';
      char endMarker = '>';
      char rc;
    
      while (Serial1.available() > 0 && newData == false) {
        rc = Serial1.read();
        //Serial.println((char)rc);
    
        if (recvInProgress == true) {
          if (rc != endMarker) {
            receivedChars[ndx] = rc;
            ndx++;
            if (ndx >= numChars) {
              ndx = numChars - 1;
            }
          }
          else {
            receivedChars[ndx] = '\0'; // terminate the string
            recvInProgress = false;
            ndx = 0;
            newData = true;
          }
        }
    
        else if (rc == startMarker) {
          recvInProgress = true;
        }
        else {
          Serial.print("Unexpected character: ");
          Serial.println(rc);
        }
      }
    }
    
    //============
    
    void parseData() {      // split the data into its parts
    
      char * strtokIndx; // this is used by strtok() as an index
    
      strtokIndx = strtok(tempChars, ",");     // get the first part - the string
      integerFromPC = atoi(strtokIndx);     // convert this part to an integer
    
      strtokIndx = strtok(NULL, ",");
      floatFromPC = atof(strtokIndx);     // convert this part to a float
    
    }
    
    //============
    
    void showParsedData() {
      Serial.print("Integer ");
      Serial.print(integerFromPC);
      Serial.print("     Float ");
      Serial.println(floatFromPC);
    }
    
    void do_reset() {
      // send reboot command -----
      SCB_AIRCR = 0x05FA0004;
    }
    
    
    void display_values(){
      display.clearDisplay();
      display.setFont(&FreeMonoBold12pt7b);
      display.setCursor(3, 45);
      display.println(integerFromPC);
      display.setCursor(72, 45);
      display.println(floatFromPC);
      display.display();
      display.clearDisplay(); 
    //  delay(1);
    }
    and below is the display result, showing lots of noises
    Click image for larger version. 

Name:	그림3.png 
Views:	5 
Size:	257.4 KB 
ID:	25019

    I am using SSD1309 adafruit 2.42 OLED display with SSD1306 library.
    Before confronting this problem, the library was completely compatible
    and moreover, there seems no adafruit official SSD1309 library so far...

    Would there be anymore solutions that you could give?
    Thank you!

  6. #6
    Senior Member
    Join Date
    Apr 2014
    Location
    Cheltenham, UK
    Posts
    246
    There is some info here which might help.

  7. #7
    Junior Member
    Join Date
    Jun 2021
    Posts
    4
    Thanks! But my display is I2C, thus there might be nothing much to check....
    But will read thoroughly!! Thank you

  8. #8
    Senior Member
    Join Date
    Apr 2014
    Location
    Cheltenham, UK
    Posts
    246
    Sorry, should have read the thread properly.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •