I am using the nano 33 BLE connected to a peripheral GPS module based on the U-blox ZED-F9P receiver. I have connected to the GPS module via UART TX1 and RX0 on the nano doing the crossover connection to the RX1 and TX1. Everything works great. I can send configuration packets to the GPS module and get the correct ACK packets back.
the my main goal of my project is to constantly request data from the GPS module, such as latitude and longitude. In setup() I configure the GPS module as needed. In loop(), I simply query the GPS module for its status. At some point, the nano stops receiving "valid packets." Using debug messages, I find that the bytes of the packet in question are received, however the number of bytes available to read is short by 1, which is the second byte of the rolling checksum. I even try to manually read the from the serial port but get a -1 out. My software times out waiting for the last packet and it request status from the GPS module as before. This time the number of available bytes is the correct number, however the first byte received by the nano uart is actually the byte I was last byte expected of the previous packet - the second byte of the rolling checksum. I verified the value is correct for the previous packet's data. I then continue to receiving data for the new packet. But I don't receive the last byte again even with the correct number of available bytes. And again, the last byte pre-pends the next received packet. What should be noted is that all subsequently received frames are off by one, but no data is ever lost. This failure condition continues until I do a hard reset of the board.
From what I gather, it seems like the number of available bytes, gotten by .available(), loses one while still retaining the data. It's almost like a rx overrun, but the software is fast enough to pull the data out before its over written. Has anybody encountered this? Has anybody solved this?
On Serial ( usb) port. After long serie msg and echo and msg and echo to usb host we had same strange sporadic unrestorable behavior on 33 BLE. Smaller message length -> probability of effect down (not to zero).
Thanks for the feedback. This issue is on the NRF52840 UART1 (Serial1 in the code). Really have not had any issue with the USB so far. May I ask how you reduced your issue?
Sorry, bigger is better in our case. we try chunk size 32 bytes 64, 128... and 176 was metastable variant for 33BLE throught SerialUSB. Plus I need to say, other mbed-arduino product Portenta Serial* works with same questions. Maybe mbed layer need more time to learn.
Hi Klaus_K, thank you very much for the input. Just to let you know I am using the latest board support package Arduino Mbed OS Boards->Arduino Nano 33 BLE->2.0.0. I did try the other one you mentioned but got the same failure. Also, during compile time it gave me a warning that the nano 33 BLE was no included. That's why I used the one mentioned above. I do notice that it now says deprecated. I don't know what the instruction in the title "Please Install standalone Packages" means. The only other related package is Arduino Mbed OS Nano Boards which give me the warning during compile and doesn't seem to fix my problem. The other library I am using is attached.
I have added a lot of debug identified by //gfh labels and a workarounds mostly at the start of waitForNoACK(). The workaround is kind of ugly and wasteful, but it allows me to reliably get data out of the attached GPS module. My example is attached too. Example11_GetHighPrecisionPositionUsingDouble-greg.ino (8.2 KB) SparkFun_u-blox_GNSS_Arduino_Library.zip (433.7 KB)
Hi, I am battling a very similar issue on Serial1 (or 2) on a Nano 33 BLE.
After receiving many complete packets of 2120 bytes (coming in over a 5 second period) for between 5 and 30 minutes (random), all of a sudden the last byte is missing, only to be 'found' in the next cycle. I.e. only 2119 bytes are received, isAvailable() reports 0 (for 5 'idle' seconds) and when the next cycle starts (every 10 seconds), the 'missing' byte appears out of nowhere.
My cycle starts by sending a 'S' to the connected device and writing to the serial port appears to shake up the UART buffer.
The connected device works fine when connected to a Windows c++ program and Python on Linux so the device is not a suspect.
I will create my own topic, but this seems a related issue and i want to raise awareness.
That does sound very similar to my issue though my packets were not as large. For now, I simply request the same packet as many times until I receive the complete packet. See my .cpp file attached on a earlier entry. I enclosed all my changes with //gfh. If you have any questions, I would be happy to answer if I can. I am moving past this issue and continuing on with other features I need to integrate.
I believe I found the likely cause. Here is what I think:
You will need to look into the following files:
-- .\mbed_nano\2.0.0\cores\arduino\Serial.cpp and Serial.h
-- .\mbed_nano\2.0.0\cores\arduino\api\RingBuffer.h
In Serial.h the UART class gets a RingBuffer called rx_buffer
class UART : public HardwareSerial {
public:
...
RingBufferN<256> rx_buffer;
In RingBuffer.h that class has 3 variables to manage the buffer
class RingBufferN
{
public:
volatile int _iHead ;
volatile int _iTail ;
volatile int _numElems;
In Serial.cpp the on_rx function is attached to the interrupt
void UART::begin(unsigned long baudrate) {
... if (_serial->obj != NULL) {
_serial->obj->attach(mbed::callback(this, &UART::on_rx), ... );
}
In Serial.cpp: on_rx calls rx_buffer.store_char(c);
In RingBuffer.h _numElems is incremented inside that function (during ISR)
void RingBufferN<N>::store_char( uint8_t c )
{
if (!isFull())
{
_aucBuffer[_iHead] = c;
_iHead = nextIndex(_iHead);
_numElems++;
}
}
In RingBuffer.h _numElems is decremented when the RingBuffer is read (outside ISR)
int RingBufferN<N>::read_char()
{
if (isEmpty())
return -1;
uint8_t value = _aucBuffer[_iTail];
_iTail = nextIndex(_iTail);
_numElems--; // This is where the issue can happen
return value;
}
Decrementing _numElems requires a read from memory, then the value is decremented and then written back to memory. When an UART RX interrupt happens in between, the value is incremented inside the ISR and then the old decremented value is written back. This causes the _numElems to be smaller by -1. When you call available() _numElems is returned.
The character is still inside the buffer because the variable _iHead is used for storing and _iTail is used for reading. That part works correct, but keeping track of the number of elements in the buffer is not.
Appreciate your work on this. It does sound like my issue. It also explains why I would get a -1 when the available() count was 0 and I knew one character was still in the buffer. Is there a way we can disable interrupts when decrementing _numElems?
You can use the CMSIS function for enabling and disabling individual interrupts.
Workaround, apply at your own risk. Click to reveal.
In RingBuffer.h
template <int N>
int RingBufferN<N>::read_char()
{
if (isEmpty())
return -1;
uint8_t value = _aucBuffer[_iTail];
_iTail = nextIndex(_iTail);
NVIC_DisableIRQ( UART0_IRQn );
_numElems--;
NVIC_EnableIRQ( UART0_IRQn );
return value;
}
This is not a general fix. It should work for UART0. If the ringbuffer is used for another peripheral the same issue could happen.
A general fix should calculate the available characters in the buffer from _iHead and _iTail. It will need some thinking to get the math right and efficient. If available() would just return a bool, simply comparing the two variables would be enough. In both cases all functions using _numElems would need to be changed.
I came up with a very similar TEMPORARY solution in the read_char() function to disable the interrupts. But instead of NVIC_DisableIRQ( UART0_IRQn ), i used noInterrupts() / interrupts()
So far, this seems to have fixed the problem (running for 3 hours now vs 10-30 minutes before).
I understand that this is a hack and the proposed calculation will be much better.
I have quickly looked at the ATOMIC_BLOCK macro, but have not had time yet to fully investigate.
volatile may also be an option (for a buffer <256 bytes). I have done a lot of coding in C/C++ and later C# but not on Arduino and things seem a bit different here.
I meet the similar problem with Nano 33 BLE, for your solution, did you mean using the noInterrupts() or interrupts() during uart.read(). Could I know how you implement those in the code
Update** I tried you method and fixed the problem, Thank you
Much appreciated Klaus. Just so you know I found the issue in both mbed and mbed_nano hardware package directories. For my development I corrected by protecting numElems-- by disabling interrupts around. However, I will look at the RingBuffer.h file in the nano 33 IoT package.
Just a quick update. The Arduino guys told me this issue is solved in version 2.3.1. They chose to solve this differently for the Arduino Nano 33 BLE from the solution for the Arduino Nano 33 IoT. You can read this in detail on GitHub.