Multiple UARTs not working simultaneously on Rpi PICO

I am working with Rpi Pico using arduino IDE:

I am facing issues with different uarts of pico ( UART 1 & UART 0) not working simultaneously in the integrated code of whole system.

Basically I have used a GPS module at another UART and radio module at different UART. I tried using separately GPS and it worked, but with integrated code both uarts ( UART 1 & UART 0) not working simultaneously. I also tried different ways for debugging like checking GPIO pins of UART with actual physical pins on the Rpi Pico. I have indicated the block which has problem using this comment : /This UART block -->/

My reference of Rpi Pico UARTs : Rpi Pico UARTs

The code:

// MAIN BALLOON TESTING CODE - By Vivek Samani
// Send b or B to trigger the burn wire from GS
// Serial transmit string format: Read_Count, gps_Altd, Lat, Lng, Sats, Hf, T, Po

/* ************ PROJECT DESCRIPTION ************ 

  HOT AIR BALLOON - MODEL SATELLITE DROP TEST

  Hardware description:
  MCU : Rpi Pico
  Burn wire triggering: MOSFET Module
  LOCATION: L89 GPS module
  Temp / Absolute Altitude / Pressure: BMP 280
  For Burnner valve control: Servo SG90
  Radio Module: LORA EBYTE E22 400T30D

  GS : Ground station occupied with LORA With (viaz TTL to USB) laptop and monitoring data on CUTECOM Software)
*/

// Including necessary libraries

#include <Wire.h>
#include <Servo.h>
#include <TinyGPS++.h>
#include <Adafruit_BMP280.h>
#include <SimpleKalmanFilter.h>

// LORA Rx & Tx pins declaration
#define LORA_Tx 16
#define LORA_Rx 17

// GPS @ Rx & Tx pins declaration
#define Tx_UART1 8
#define Rx_UART1 9

#define burn_pin 15

// Servo pin
#define svr_pin 22

bool newData;
float incoming_serial_pressure, Po, Pf;

SimpleKalmanFilter pressureKalmanFilter(1, 1, 1);

// Instance and object declaration6h
Servo svr;
TinyGPSPlus gps;
Adafruit_BMP280 bmp;

// Serial output refresh time
unsigned long refresh_time;
const long SERIAL_REFRESH_TIME = 100;

volatile float gps_Altd, Lat, Long, Hf, T, P, H;
volatile signed int Sats, svr_pos = 0, Read_Count = 1;

void setup() {
  // GPS Baud Rates and UART declaration
  Serial2.setTX(Tx_UART1);
  Serial2.setRX(Rx_UART1);
  Serial2.begin(9600);

  // LORA Baud Rates and UART declaration
  Serial1.setTX(LORA_Tx);
  Serial1.setRX(LORA_Rx);
  Serial1.begin(9600);

  // Serial monitor baud rate
  Serial.begin(9600);

  // Attach & Set servo to initial position
  svr.attach(svr_pin);
  svr.write(svr_pos);

  // Check the status of sensor
  unsigned status;
  status = bmp.begin(0x76);
  if (!status) {
    Serial.println(F("Could not find a valid BMP280 sensor, check wiring or "
                     "try a different address!"));
  }

  // Defining sampling rates for BMP280
  bmp.setSampling(Adafruit_BMP280::MODE_NORMAL,   /* Operating Mode. */
                  Adafruit_BMP280::SAMPLING_X2,   /* Temp. oversampling */
                  Adafruit_BMP280::SAMPLING_X16,  /* Pressure oversampling */
                  Adafruit_BMP280::FILTER_X16,    /* Filtering. */
                  Adafruit_BMP280::STANDBY_MS_1); /* Standby time. */

  // Set reference pressure
  for (int i = 0; i < 10; i++) {
    incoming_serial_pressure += bmp.readPressure();
    // wait for next reading
    delay(200);
  }

  // Reference pressure
  Po = incoming_serial_pressure / 10;
  P = Po;
}

void loop() {
  // send to Serial output every 100ms
  if (millis() > refresh_time) {
    /* Activate burn wire or Rotate servo as per command */
  /*This UART block -->*/  if (Serial1.available() > 0) {
      char receivedChar = Serial1.read();
      if (receivedChar == 'B' || receivedChar == 'b') {
        BurnWire();
      }

      svr_pos = Serial1.read();
      if (svr_pos >= 0 || svr_pos <= 180) {
        svr.write(svr_pos);
      }
    }

    // Collect data from L89 GPS Module
/*This UART block -->*/
    if (Serial2.available() > 0) {
      if (gps.encode(Serial2.read())) {
        Serial.print("# READING NO:- ");
        Serial.println(Read_Count);

        Serial.print("SATS :- ");
        Serial.println(gps.satellites.value());

        Serial.print("LAT :- ");
        Serial.println(gps.location.lat(), 7);

        Serial.print("LONG :- ");
        Serial.println(gps.location.lng(), 7);

        Serial.print("ALT :- ");
        Serial.println(gps.altitude.meters());

        Read_Count++;
      }
    }

    // filtered_pressure_value
    Pf = pressureKalmanFilter.updateEstimate(bmp.readPressure());

    // measured altitude
    H = bmp.readAltitude(Po * 0.01);

    // measured temprature
    T = bmp.readTemperature();

    // filtered altitude
    Hf = 44330 * (1 - pow((Pf / Po), (0.1903)));

    // Read_Count, gps_Altd, Lat, Lng, Sats, Hf, T, Po
    String csvData = String(Read_Count) + "," + String(gps_Altd) + "," + String(Lat) + "," + String(Long) + "," + String(Sats) + "," + String(Hf) + "," + String(T) + "," + String(Po);
    Serial1.println(csvData);
    Serial.println(csvData);

    Read_Count += 1;

    refresh_time = millis() + SERIAL_REFRESH_TIME;
  }
}

void BurnWire() {
  static bool executed = false;
  if (!executed) {
    Serial.println(" BURN WIRE TRIGGERED SUCCESSFULLY !! ");
    digitalWrite(burn_pin, HIGH);
    delay(1000);
    digitalWrite(burn_pin, LOW);
  }
  executed = true;
}

Please do not post in "Uncategorized"; see the sticky topics in https://forum.arduino.cc/c/using-arduino/uncategorized/184.

Your topic has been moved.


I can't help you with your problem.

Ok I'll take care of such mistakes!

You have marked two lines in your code.

Does this mean that both lines block?

You are using a delay(1000) inside your burnWire-function

delay() is of course blocking

This way of using non-blocking timing

  if (millis() > refresh_time) {
  // ...
    refresh_time = millis() + SERIAL_REFRESH_TIME;

will not work if a rollover to zero of millis() occurs

You should do all, each and every non-blocking time-checking in this way:

if (millis() - beginOfPeriod >= SERIAL_REFRESH_TIME) {
  beginOfPeriod = millis();
  // your code
}

Yes you got the correct inference, those two block marked with this comment : /*This UART block -->*/ are not working simultaneously

I tried doing that a week ago what u said, by removing that delay in Burnwire function but still the problem of multiple UART not working is still there! So I think that delay couldn't be the reason for blocking of those 2 blocks. Obviously I agree that delay is blocking for MCU sequential tasks.

Basically these below 2 blocks are not working together in same code:

/*This UART block -->*/
if (Serial1.available() > 0) {
      char receivedChar = Serial1.read();
      if (receivedChar == 'B' || receivedChar == 'b') {
        BurnWire();
      }

      svr_pos = Serial1.read();
      if (svr_pos >= 0 || svr_pos <= 180) {
        svr.write(svr_pos);
      }
    }

    // Collect data from L89 GPS Module
/*and This UART block -->*/
    if (Serial2.available() > 0) {
      if (gps.encode(Serial2.read())) {
        Serial.print("# READING NO:- ");
        Serial.println(Read_Count);

        Serial.print("SATS :- ");
        Serial.println(gps.satellites.value());

        Serial.print("LAT :- ");
        Serial.println(gps.location.lat(), 7);

        Serial.print("LONG :- ");
        Serial.println(gps.location.lng(), 7);

        Serial.print("ALT :- ");
        Serial.println(gps.altitude.meters());

        Read_Count++;
      }
    }

If you take a close look

your if-condition

    // Collect data from L89 GPS Module
    /*This UART block -->*/
    if (Serial2.available() > 0) {
      if (gps.encode(Serial2.read())) {

is inside of this if-condition

void loop() {
  // send to Serial output every 100ms
  if (millis() > refresh_time) {

this means only when this if-condition is true

  if (millis() > refresh_time) {

this if-condition

    if (Serial2.available() > 0) {

is executed

Is this what you really want?

yes, When the GPS is ready to send the processed data it will communicate with mcu via serial2 and when there is some serial data on Serial2 it must execute!

I got the reference of Multiple UART with Rpi Pico from a site (Shared in my first post of this topic)

I looked up the technical specs

a Raspberry Pi pico has only two UARTs

You are trying to use three UARTS

1: serial
2: serial1
3: serial2

are you sure that
"serial" the one without a traling-digit is additional to the two other UARTs?

I have looked up the specs and the Pinout here
https://www.raspberrypi.com/documentation/microcontrollers/raspberry-pi-pico.html
This pinout shows two UARTs
1: UART0 marked with cyan frames
and
2: UART1 marked with pink frames

You can assign the two UARTs to different IO-pins but there is only UART0 and UART1

EDIT:

After reading your link
https://arduino-pico.readthedocs.io/en/latest/serial.html
serial is indeed the USB-to-Serial converter which is extra to UART0 and UART1

To make visible what your code is doing run this version with additional debug-output

I was unable to compile because I got a compiler-error conflicting declaration SPI...

// MACRO-START * MACRO-START * MACRO-START * MACRO-START * MACRO-START * MACRO-START *
// a detailed explanation how these macros work is given in this tutorial
// https://forum.arduino.cc/t/comfortable-serial-debug-output-short-to-write-fixed-text-name-and-content-of-any-variable-code-example/888298

#define dbg(myFixedText, variableName) \
  Serial.print( F(#myFixedText " "  #variableName"=") ); \
  Serial.println(variableName);

#define dbgi(myFixedText, variableName,timeInterval) \
  { \
    static unsigned long intervalStartTime; \
    if ( millis() - intervalStartTime >= timeInterval ){ \
      intervalStartTime = millis(); \
      Serial.print( F(#myFixedText " "  #variableName"=") ); \
      Serial.println(variableName); \
    } \
  }

#define dbgc(myFixedText, variableName) \
  { \
    static long lastState; \
    if ( lastState != variableName ){ \
      Serial.print( F(#myFixedText " "  #variableName" changed from ") ); \
      Serial.print(lastState); \
      Serial.print( F(" to ") ); \
      Serial.println(variableName); \
      lastState = variableName; \
    } \
  }

#define dbgcf(myFixedText, variableName) \
  { \
    static float lastState; \
    if ( lastState != variableName ){ \
      Serial.print( F(#myFixedText " "  #variableName" changed from ") ); \
      Serial.print(lastState); \
      Serial.print( F(" to ") ); \
      Serial.println(variableName); \
      lastState = variableName; \
    } \
  }
// MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END *

// MAIN BALLOON TESTING CODE - By Vivek Samani
// Send b or B to trigger the burn wire from GS
// Serial transmit string format: Read_Count, gps_Altd, Lat, Lng, Sats, Hf, T, Po

/* ************ PROJECT DESCRIPTION ************

  HOT AIR BALLOON - MODEL SATELLITE DROP TEST

  Hardware description:
  MCU : Rpi Pico
  Burn wire triggering: MOSFET Module
  LOCATION: L89 GPS module
  Temp / Absolute Altitude / Pressure: BMP 280
  For Burnner valve control: Servo SG90
  Radio Module: LORA EBYTE E22 400T30D

  GS : Ground station occupied with LORA With (viaz TTL to USB) laptop and monitoring data on CUTECOM Software)
*/

// Including necessary libraries

#include <Wire.h>
#include <Servo.h>
#include <TinyGPS++.h>
#include <Adafruit_BMP280.h>
#include <SimpleKalmanFilter.h>

// LORA Rx & Tx pins declaration
#define LORA_Tx 16
#define LORA_Rx 17

// GPS @ Rx & Tx pins declaration
#define Tx_UART1 8
#define Rx_UART1 9

#define burn_pin 15

// Servo pin
#define svr_pin 22

bool newData;
float incoming_serial_pressure, Po, Pf;

SimpleKalmanFilter pressureKalmanFilter(1, 1, 1);

// Instance and object declaration6h
Servo svr;
TinyGPSPlus gps;
Adafruit_BMP280 bmp;

// Serial output refresh time
unsigned long refresh_time;
const long SERIAL_REFRESH_TIME = 100;

volatile float gps_Altd, Lat, Long, Hf, T, P, H;
volatile signed int Sats, svr_pos = 0, Read_Count = 1;

void setup() {
  // GPS Baud Rates and UART declaration
  Serial2.setTX(Tx_UART1);
  Serial2.setRX(Rx_UART1);
  Serial2.begin(9600);

  // LORA Baud Rates and UART declaration
  Serial1.setTX(LORA_Tx);
  Serial1.setRX(LORA_Rx);
  Serial1.begin(9600);

  // Serial monitor baud rate
  Serial.begin(9600);

  // Attach & Set servo to initial position
  svr.attach(svr_pin);
  svr.write(svr_pos);

  // Check the status of sensor
  unsigned status;
  status = bmp.begin(0x76);
  if (!status) {
    Serial.println(F("Could not find a valid BMP280 sensor, check wiring or "
                     "try a different address!"));
  }

  // Defining sampling rates for BMP280
  bmp.setSampling(Adafruit_BMP280::MODE_NORMAL,   /* Operating Mode. */
                  Adafruit_BMP280::SAMPLING_X2,   /* Temp. oversampling */
                  Adafruit_BMP280::SAMPLING_X16,  /* Pressure oversampling */
                  Adafruit_BMP280::FILTER_X16,    /* Filtering. */
                  Adafruit_BMP280::STANDBY_MS_1); /* Standby time. */

  // Set reference pressure
  for (int i = 0; i < 10; i++) {
    incoming_serial_pressure += bmp.readPressure();
    // wait for next reading
    delay(200);
  }

  // Reference pressure
  Po = incoming_serial_pressure / 10;
  P = Po;
}

void loop() {
  dbgc("S1",Serial1.available() );
  dbgc("S2",Serial2.available() );
  // send to Serial output every 100ms
  if (millis() > refresh_time) {
    /* Activate burn wire or Rotate servo as per command */
    /*This UART block -->*/  if (Serial1.available() > 0) {
      char receivedChar = Serial1.read();
      dbgc("A1_a",receivedChar );
      
      if (receivedChar == 'B' || receivedChar == 'b') {
        BurnWire();
      }

      svr_pos = Serial1.read();
      dbgc("A1_b",svr_pos);
      if (svr_pos >= 0 || svr_pos <= 180) {
        svr.write(svr_pos);
      }
    }

    // Collect data from L89 GPS Module
    /*This UART block -->*/
    if (Serial2.available() > 0) {
      char s2RcvdChar = Serial2.read();
      dbgc("A2_a", s2RcvdChar);
      
      if (gps.encode(s2RcvdChar) ) {
        Serial.print("# READING NO:- ");
        Serial.println(Read_Count);

        Serial.print("SATS :- ");
        Serial.println(gps.satellites.value());

        Serial.print("LAT :- ");
        Serial.println(gps.location.lat(), 7);

        Serial.print("LONG :- ");
        Serial.println(gps.location.lng(), 7);

        Serial.print("ALT :- ");
        Serial.println(gps.altitude.meters());

        Read_Count++;
        dbgc("A2_b",Read_Count);
      }
    }

    // filtered_pressure_value
    Pf = pressureKalmanFilter.updateEstimate(bmp.readPressure());

    // measured altitude
    H = bmp.readAltitude(Po * 0.01);

    // measured temprature
    T = bmp.readTemperature();

    // filtered altitude
    Hf = 44330 * (1 - pow((Pf / Po), (0.1903)));

    // Read_Count, gps_Altd, Lat, Lng, Sats, Hf, T, Po
    String csvData = String(Read_Count) + "," + String(gps_Altd) + "," + String(Lat) + "," + String(Long) + "," + String(Sats) + "," + String(Hf) + "," + String(T) + "," + String(Po);
    Serial1.println(csvData);
    Serial.println(csvData);

    Read_Count += 1;

    refresh_time = millis() + SERIAL_REFRESH_TIME;
  }
}

void BurnWire() {
  static bool executed = false;
  if (!executed) {
    Serial.println(" BURN WIRE TRIGGERED SUCCESSFULLY !! ");
    digitalWrite(burn_pin, HIGH);
    delay(1000);
    digitalWrite(burn_pin, LOW);
  }
  executed = true;
}

basically the "serial" is for printing on arduino serial monitor. It's by default UART occupied by the USB cable itself!

Yes you are correct. My fault. What does my code-version print to the serial monitor?
Post the debgug-output as a code-section

in this code text entered on Serial sent to Serial2 sent to Serial1 displayed on serial monitor

// Raspberry Pi Pico RP2040  Serial1 and Serial2 test
//
// text entered on Serial sent to Serial2 sent to Serial1 displayed on serial monitor

// Note
// Serial is the USB serial for program loading and serial mointor
// there are two hardware serial ports UART0 and UART1
//  Serial1 is mapped to UART0 on Rx pin GP1 Tx pin GP0
//  Serial2 is mapped to UART1 on Rx pin GP5 Tx pin GP4

#define TX2 4
#define RX2 5

void setup() {
  // initialize both serial ports:
  delay(5000);
  Serial.begin(115200);
  Serial.println();
  Serial.println("\n\nRaspberry Pi Pico RP2040 hardware serial test on Serial1 and Serial2"
                 "\n  Serial1 Rx pin GP1 Tx pin GP0");
  Serial1.begin(115200);
  // assign pin numbers for Serial2
  Serial2.setTX(TX2);  
  Serial2.setRX(RX2);
  Serial2.begin(115200);
 Serial.print("  Serial2 RX2 pin GP" + String(RX2));
  Serial.println(" TX2 pin GP" + String(TX2));
  Serial.println("connect GP0 to GP5 and GP4 to GP1");
  Serial.println("text entered on  Serial sent to Serial2 sent to Serial1 displayed on serial monitor");
 }

void loop() { 
  while (Serial2.available()) {
    String s=Serial2.readStringUntil('\n');
    Serial.println("Serial2 = " + s);
    Serial2.println("from Serial 2 " + s);
  }
  while (Serial1.available()) {
    Serial.println("Serial1 = " + Serial1.readStringUntil('\n'));
  }
  while (Serial.available()) {
    String s = Serial.readStringUntil('\n');
    Serial.println("Transmitting to Serial1 " + s);
    Serial1.print("from Serial 1 " + s);
  }
}

a run gave

Raspberry Pi Pico RP2040 hardware serial test on Serial1 and Serial2
  Serial1 Rx pin GP1 Tx pin GP0
  Serial2 RX2 pin GP5 TX2 pin GP4
connect GP0 to GP5 and GP4 to GP1
text entered on  Serial sent to Serial2 sent to Serial1 displayed on serial monitor
Transmitting to Serial1 test 1
Serial2 = from Serial 1 test 1
Serial1 = from Serial 2 from Serial 1 test 1
Transmitting to Serial1 test 2
Serial2 = from Serial 1 test 2
Serial1 = from Serial 2 from Serial 1 test 2
Transmitting to Serial1 test 3 1234567890
Serial2 = from Serial 1 test 3 1234567890
Serial1 = from Serial 2 from Serial 1 test 3 1234567890
Transmitting to Serial1 test 4 abcdefghijklmnopqrstuvwxyz
Serial2 = from Serial 1 test 4 abcdefghijklmnopqrstuvwxyz
Serial1 = from Serial 2 from Serial 1 test 4 abcdefghijklmnopqrstuvwxyz

I got nothing by way of help, but I am very curious about what kind of fun means needing to print what you do as quoted here. Seems also like a third '!' woukd be good.

If you can say without then needing to kill us, please do.

TIA

a7

I know that this is about a Pi Pico but be careful; I've read about a version of a bootloader for the Mega that, if it encountered !!!, would go into a special mode and uploads failed.

Live and learn!!

a7

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.