Serial UART behaviour different on Connect RP2040 to 33 IOT

Hi all

Long time Arduino fan, first time poster :slight_smile:

I am attempting to use a NANO RP2040 CONNECT instead of my usual NANO IOT 33 and have found a difference in behaviour when using hardware serial.

The code at the bottom of the post reproduces the problem. I am setting a R/W direction pin to HIGH, writing a sequence of bytes to the serial port and then setting the R/W direction pin to LOW.

On a NANO IOT 33 the digital trace loooks as expected, i.e. the direction pin (marked 1 on the trace image) goes low after all of the bytes have been written:

On a NANO RP2040 the digital trace loooks different, i.e. the direction pin (marked 1 on the trace image) goes low before all of the bytes have been written:

In all of the calls to test below the direction pin goes low two bytes before the end of the buffer. My guess would be an issue with the RP2040 target code, but wanted to see if I'm missing something obvious.

Any and all help gratefully received :slight_smile:

Cheers,
Rich.

const uint8_t DIR_PIN = 2;

void setup() 
{
  Serial.begin(115200);
  Serial1.begin(57600);
  pinMode(DIR_PIN, OUTPUT);
}

void test(uint8_t* data, size_t length)

{
  Serial.print("Outputting ");
  Serial.print(length);
  Serial.println(" byte(s)");

  digitalWrite(DIR_PIN, HIGH);
  Serial1.write(data, length);
  Serial1.flush();
  digitalWrite(DIR_PIN, LOW);
  delay(10);
}

void loop()
{
  uint8_t data[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};

  test(data, 10);
  test(data, 12);
  test(data, 14);
  test(data, 16);
  test(data, 18);
  test(data, 20);
}

The difference comes from the Serial.flush. The function is empty for the Nano RP2040 Connect.

And, I think that is a good thing. This is a blocking function that can block the sketch for a very long time, crashing the RTOS and other libraries that need to execute code on a regular basis.

I thought the flush method was blank because it uses an unbuffered serial class and therefore there is no buffer to flush?

Regardless I’m not sure how through the Arduino serial abstraction this should be reliably achieved.

I think that is a good thing. This is a blocking function that can block the sketch for a very long time, crashing the RTOS

It's NOT a good thing. flush() has a careful definition, and was implemented because it was needed. flush() is no more likely to block that write(), and the OS should be satiable via yield()...

I thought the flush method was blank because it uses an unbuffered serial class

The rp2040 gets away with not having buffers because it has a 32byte hardware FIFO...

You can try this bit of code (which at least compiles):

void flush() {
  while (uart0_hw->fr & UART_UARTFR_BUSY_BITS) {
    yield();
  }
}

I'm afraid that I have no idea how Arduino and mBed "connect", so I can't come up with a "proper patch" :frowning:

It does not seem to use the FIFO. I just did a test similar to @Sagnad writing a pin HIGH before and LOW after write. When you write once or twice the pin goes LOW before the first bit has left the UART. When I write 3 bytes the pin goes LOW after the first byte has left the UART.
This looks like there can be one byte in the shift register and one in a data register.

This also matches the second picture from @Sagnad the signal at the bottom goes LOW as soon as only two bytes are left to send (18&19).

Edit: In the RP2040 datasheet page 436 it states.

You can program the FIFOs to be 1-byte deep providing a conventional double-buffered UART interface.

Maybe that is the default configuration.

The RP2040 target in mbed disables the fifo:

uart_set_fifo_enabled(obj->dev, false);

The RP2040 SDK documentation states:

You can disable the transmit FIFO to act like a one-byte holding
register.

It also goes on to say that :

When the FIFOs are disabled, a write to the data register bypasses the holding register
unless the transmit shift register is already in use.

I think I'll attempt to write the same test using the RP2040 SDK and get a handle on how it needs to work.

I believe the flush routine I posted should work whether or not the fifo is enabled.

Just to confirm, I tested it with my sketch and it does work as I believe @Sagnad would want it to work. The trigger signal goes low after all the transfers are done.
It would need to be changed, to make it generic so you could replace the flush method in the library.

Ah ok great I'll give it a go - thanks @Klaus_K and @westfw for your help

No experience with either board but maybe Serial.availableForWrite() can be of help.

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