Serial1.availableForWrite() always returns 0

I'm porting my code for the Arduino UNO R4 Minima.

Serial1 port (D0/D1) can be used, but the value of Serial1.availableForWrite can never be larger than zero.

Here's the code:

void setup() {
    while (!Serial && millis() < 5000);
    Serial.begin(115200);
    Serial.println("Hello, World!");
    Serial1.begin(115200);
    while (Serial1.availableForWrite() <= 0) {
        // Serial1.availableForWrite() will never be larger than 0
        Serial.print("Serial1 bytes available to write: ");
        Serial.println(Serial1.availableForWrite());
        // Although below line is written to the port
        Serial1.println("Cannot write to Serial1");
        delay(500);
    }
}

void loop() { }

Result:

The function is not available on R4 Renesas boards?

A quick perusal of the R4 core source reveals that it only returns a non zero value for the SerialUSB class.

According to the code, Serial1 is an alias for the _UART1_ and this is an instance of the class UART derived from the class HardwareSerial in the ArduinoCore-API derived from the class Stream derived from the class Print which has availableForWrite as shown below.

    // default to zero, meaning "a single write may block"
    // should be overridden by subclasses with buffering
    virtual int availableForWrite() { return 0; }

It appears that the board does not support the use of an write buffer since the above virtual method does not seem to be overridden.
Is this the correct behavior of UNO R4?

As you have discovered, this is what it does.

Thanks,
It should be buffered, though.

Personally no. But that is what the current code base does.

There are lots of things wrong with the current code base.

As mentioned, it is not buffered. Sits and spins waiting for each character to fully output before returning to output the next... And it does this spinning waiting on an interrupt, that creates a callback on the default interrupt priority, such that if called from another interrupt will hang the processor....

Some of these issues, have more information in the issue:
Serial[x].print/write - Could use some major performance enhancement. · Issue #44 · arduino/ArduinoCore-renesas (github.com)

There were probably some other issues, like: #38 which I later closed out of frustration.

At one point I tried to address as many of these issues as I could. Back in August I issued a Pull Request:

Serial: Tx use FIFO plus fixes by KurtE · Pull Request #90 · arduino/ArduinoCore-renesas (github.com)

Which I have not heard any feedback on, so I may close it out soon.

Currently my boards are now in a box, inside a cabinet, that I may or may not look at again.

3 Likes

Don't close it. If they won't respond then let it rot.

It sounds terrible.
They don't seem to be up to the standard of embedded software development.

ArduinoCore-avr has buffered Serial.
I recall the good old AVR days. I can't believe that this new board is called as "UNO".

I totally agree.

Hi everyone, I understand the frustration but the amount of activities we are following is tremendous and some of them cannot be tackled in a timely manner.
We'll tackle the availableForWrite() issue in the next core release.
@KurtE talking about PRs, commenting on Serial: Tx use FIFO plus fixes by KurtE · Pull Request #90 · arduino/ArduinoCore-renesas · GitHub has been in my todo list for a long time, but having the patch in a better shape (multiple commits, no unrelated changes, debug in a separate commit) could help substantially. Sorry again for the long delay

2 Likes

@facchinm, I will try to take a look again. It is interesting between different groups, want PRs in different ways... Like some want all the changes squashed into one, as it makes it easier to then rebase and you don't have to deal with the intermediate rebase errors on stuff that changed again in the next commit... Note: Some of memory may be a bit hazy on some of the details as it was something like four to six months ago.

Note: the issue is not really availableForWrite() always returns 0 but is the symptom of the writes to Serial ports is not cached at all and is always blocking. So currently the hard coded 0 is correct, that is you cannot write out anything without blocking.

Some of the steps and problems I ran into, include:

a) The TX Fifo object that was built into the Hardware Serial object is not used. First step, Have the SerialX.write(), now put things into the software FIFO, have ISR pull things out of the FIFO. Note: Used a simple buffer within the Serial object to pass to HAL to do the write (buffer, size).

When, the HAL is done with the data in the temporary buffer, it calls back to us, where if appropriate I refill the temporary buffer and call back to the HAL to continue writing.

Ran into problem with the HAL. When it stuffs out the last character in your buffer into the hardware register, it then does the callback, and if I tell it to output more stuff, the HAL code assumes that the write register is empty and blindly stuffs the first character of your new buffer into the output register. Unfortunately, at times it is not empty, and you just trashed the last character from the previous write.. This issue manifests as well with the current code base. For example Serial.println() would randomly trash the last character with the CR/LF output.

b) If the HAL is busted, you do you try to fix the HAL, or avoid it? I avoided trying to change the HAL, as I recall, it was not clear of all of the steps you had to do, to build a new static library...
The implantation would be cleaner having the ISR grab the data directly from the FIFO software queue... Don't remember if I did this or not.

c) Optional: - I really do not like your standard (API) software FIFO queue implementation. It is completely unsafe. As both writing to and reading from them both use a common variable (count), and I saw several places that used it, where they ran into issues with counts getting out of sync. .. So I implemented my own, which is the same as many others, where the count is calculated from head and tail... And the Writer and Reader only update either the head or the tail... But could go back to using the current one SafeRingBuffer which disables interrupts each time you add a character to it or remove one...

d) availableForWrite: can simply then return the count unused in the software FIFO.

e) Hardware FIFO - If I remember correctly a couple of the hardware uarts have a hardware FIFO. Don't remember if we made use of this or not.

f) SerialX.flush(): Current code does nothing as it simply checks that the unused TX Fifo is empty...
However, this is not sufficient. The flush should not return, until all of the bits of the last character have been transmitted. I am trying to remember if I put something in to check the actual transmission completed or not... If I remember correctly you tried to address this as well.

I am probably forgetting some of the other details. WIll soon go back and take a look.

1 Like

@facchinm - Thanks for making an appearance. We were starting to think the core team had forgotten about us.

I can't begin to tell the disappointment I have with what I received in the R4. It almost feels like one of those things where the business folks were in such a hurry to release it that they didn't give the development folks time to finish it. I wonder if anyone at Arduino feels any sense of shame over this one. Or is this what we should expect in the future as well?

I rather doubt there's any shame felt at Arduino over the R4s. Not these days. A minimally viable product was rushed to market and traded on the name recognition of the Uno. And it sold. Huge success. And yes, I was rolling my eyes as I typed all that.

I don't think there's any question that it could have been so much better. But it isn't. And shouting at the wind won't change that. Avoid it, tinker with until you get it to do what you need (which I admit is hugely satisfying when it works out!), or curse it if you will. Just don't hold your breath expecting it to suddenly and miraculously be the product you think it should be.

Due to user issues with Arduino R4 using our product the IO Expander, I've rewritten the UART driver that has a properly working Tx buffer, fixed the ring buffer that is not interrupt safe, and got both Serial and Serial1 working full duplex at the same time. I'm looking for testers please contact me at my site. Once tested I plan on releasing it for free. Here's a video of both ports working at the same time at 115k; http://www.zevendevelopment.com/videos/IOExpanderArduinoR4WorkingWithBothSerialPorts.mp4