SoftwareSerial does not allow a baud rate change after an initial has been set.
I have a peripheral that has a default baud rate of 115200 which works great on a real UART.
However, with SoftwareSerial it loses RX-characters at the speed. This is a known, well-documented, and fully understood limitation of SoftwareSerial. So I set the SoftwareSerial port first to 115200, sent to the peripheral the instruction to work at 38400 and reset the SoftwareSerial to 38400. That works on ALL platforms.. except UNO-R4.
It can be tested with code at the end. It basically switches the baud rate between 38400/115200/38400.
On SoftwareSerial all the text is readable at 38400. There is NO change in speed to 115200 happening. The output looks like this:
Looking at SoftwareSerial.cpp around line 287, "// Configure the TX DMA and its trigger timer." works only the first time. Subsequent attempts will fail.
#include <SoftwareSerial.h>
SoftwareSerial softSerial(2, 3); //RX, TX
// define the serial port to use (E.g. softSerial, Serial1 etc)
#define TestSerial softSerial
// if delays are wanted to check whether that makes a difference (it does not)
#define TestDelay 000
void setup() {
Serial.begin(115200);
while (!Serial); //Wait for the serial port to come online
Serial.println(F("Serial speed 1: 38400"));
TestSerial.begin(38400);
if (TestDelay > 0) delay(TestDelay);
TestSerial.print(38400);
if (TestDelay > 0) delay(TestDelay);
Serial.println(F("Serial speed 2: 115200"));
TestSerial.begin(115200);
if (TestDelay > 0) delay(TestDelay);
TestSerial.print(115200);
if (TestDelay > 0) delay(TestDelay);
Serial.println(F("Serial speed 3: 38400"));
TestSerial.begin(38400);
if (TestDelay > 0) delay(TestDelay);
TestSerial.print(38400);
if (TestDelay > 0) delay(TestDelay);
Serial.println(F("done"));
}
void loop() {
// put your main code here, to run repeatedly:
}
The problem is NOT related to Serial1.. that works without a problem on the UNO R4 WIFI.The problem is with SoftwareSerial not able to change the initial baudrate.
yes, thanks. I know there is another UART available. The issue is that in some libraries SoftwareSerial is embedded and it means changing the code just for the UNO-R4 WIFI.
Did some more checking. The issue is related to obtaining a GPT-timer.
With every change in baud rate SoftwareSerial tries to get a new GPT-channel, instead of using the one obtained the first time around. There are 8 GPT channels/timers, 6 are reserved during initVariant() and assigned for PWM to pins 3, 5, 6, 9, 10 and 11. That leaves 2 GPT channels: one for SoftwareSerial TX and one for RX.
The solution can be done in SoftwareSerial.cpp with changes in begin() and fsp_tim_config().
1. Add in top of SoftwareSerial.cpp (somewhere around line 37)
int8_t channel = 0;
int8_t TX_channel = 0;
int8_t RX_channel = 0;
2. In begin() around line 293 add setting and save the TX-channel
channel = TX_channel;
if (fsp_tim_config(&tx_descr.tim, config.baudrate, false) != 0) {
return 0;
}
TX_channel = channel;
3. In begin() around line 307 add setting and save the RX-channel
channel = RX_channel;
if (fsp_tim_config(&rx_descr.tim, config.baudrate, true) != 0) {
return 0;
}
RX_channel = channel;
4. in fsp_tim_config(), around line 116
change: int8_t channel = FspTimer::get_available_timer(type);
to: if (channel == 0) channel = FspTimer::get_available_timer(type);
Unfortunately there does not appear to be a function to terminate a SoftwareSerial instance, similar to Serial.end(), which is what I was going to suggest, since multiple calls to begin() without destroying the previous instance could be problematic.
You might look at the library to see if there is a way to just directly change the baudrate by adding an additional function.