I’m currently receiving data on UART1 of the FEZ Duino. The data received is binary data from a GPS receiver. I’m decoding the messages and verifying the checksums of each message received. The buadrate being used is 230400 and the amount of data being received is approximately 12,000 Bytes/Second.
The issue I’m having is that once I start writing the received data to a microSD card I start getting checksum errors on the received GPS data…these errors are printed on the debuggers output window. I’ve also induced delays in the main loop and get the same results, which leads me to believe it’s not the Storage Controller.
Here is some of the relevant code:
byte[] rxBuffer = new byte[2048];
byte[] rxGpsBuffer = new byte[Globals.gpsReceiveBufferLen];
int gpsBufferInIndex = 0;
int gpsBufferOutIndex = 0;
var gpsUart = UartController.FromName(SC20100.UartPort.Uart1);
var gpsUartSetting = new UartSetting()
{
BaudRate = 230400,
DataBits = 8,
Parity = UartParity.None,
StopBits = UartStopBitCount.One,
Handshaking = UartHandshake.None,
};
gpsUart.SetActiveSettings(gpsUartSetting);
gpsUart.ReadBufferSize = 2048;
gpsUart.Enable();
while(true)
{
var gpsBytesToRead = gpsUart.BytesToRead;
if (gpsBytesToRead > 0)
{
gpsUart.Read(rxBuffer, 0, gpsBytesToRead);
for (index = 0; index < gpsBytesToRead; index++)
{
rxGpsBuffer[gpsBufferInIndex] = rxBuffer[index];
gpsBufferInIndex = (gpsBufferInIndex+1) % Globals.gpsReceiveBufferLen;
}
}
if(gpsBufferInIndex != gpsBufferOutIndex)
{
do
{
status = UbloxDecoder.DecodeUbloxData(rxGpsBuffer[gpsBufferOutIndex]);
gpsBufferOutIndex = (gpsBufferOutIndex+1)% Globals.gpsReceiveBufferLen;
status = UbloxDecoder.DecodeUbloxMessage(status,statusLED1,statusLED4);
switch (status)
{
case 1: decodedGpsDataFlag = true; break;
case 2: decodedAckDataFlag = true; break;
case 3: decodedNmeaDataFlag = true; break;
default: break;
}
} while ((status == 0) && (gpsBufferInIndex != gpsBufferOutIndex));
}
}
Is there something that I’m doing wrong here? I’ve verified that I’m not writing over any undecoded data in my ring buffer. I feel like I’m doing something very dumb and am just not seeing it.
For context, the is C code that I’ve ported over to C#. The C version of this code works great, however, that code utilizes interrupts that saves each byte of data as it’s received in it’s interrupt handler.
From what I see, I suspect you are reading the serial data and then writing the SD. While you are writing the SD, the serial data is internally queueing. If you take too long to write to the SD then you will lose serial data.
I think you are going to have to implement the producer/consumer pattern. Read the serial data using an event and place the data into a queue. Then read the queue in the main thread and write the data to the SD. You will have to pre-allocated queue objects to avoid garbage collection, which will also impact the serial data.
This assume that SD writting is non-blocking.
But, first you might want to check the writing speed of the SD.
We removed the blocking interrupt during SD card read/write operations, which allows UART interrupts to be triggered. Hopefully, this will help in the next release.
Mike - Regarding using an event…this is essentially what I did in C when I had direct access to the microcontroller registers and interrupts. On every byte received an interrupt would occur, I’d save the byte in a buffer and deal with the buffer when I had the opportunity. Being very new to the SITCore environment and C#, I was assuming this was the basic operation of the UartController. Doesn’t the UartController operate in the background, filling up an internal buffer? Then when the program gets back around to reading it, reads all of the bytes in the buffer and sets the buffer “pointer” back to 0. The size of the internal uart buffer would be gpsUart.ReadBufferSize, which would essentially let the user dictate the size of the buffer based on needs…provided it fell within the SITCore limits. I would assume the only way I’d miss any data would be if their was an overflow on the uart read buffer. This was written before Dat_Tran’s response.
Gus - Regarding missing GPS message…I unfortunately don’t have that luxury. Eventually I will be adding an IMU in the mix which will be connected to another uart. This data will also need to be saved to the SD card and the throughput is much greater then the GPS receiver.
I’ve done some more testing and have induced a 500ms delay to simulate writing to an SD card. I was able to get this to work but not without increasing the uart.ReadBufferSize to accommodate the data received during this delay.
Dat_Tran - I’m assuming blocking interrupts during the SD card read/write operation would cause missing uart data being received during that timeframe? Is the blocking of interrupts also true when flushing files? If so, this will also pose an issue. Do you know when the next release will be?
Dat_Tran, if what I assume you stated to be true, I’m surprised I’m the only one experiencing this situation. Is missing data okay in most application? Our current system runs multiple sensors at high rates utilizing a microcontroller and your obsolete ALFAT and it becomes an issue if any data is missed.
I’m confused…So the blocking of interrupts during the SD card read/write operations have been removed or will be removed on the next release?
I could send you all of my code but it requires an external Ublox receiver. Below is the code that I’m using for testing. Thread.Sleep(500) is just used to test that I can receive and decode the GPS uart data without any errors during the delay…everything works as expected. If I comment out Thread.Sleep(500) and uncomment ubloxFile.Write I start getting errors in the uart data. The fileWriteBufferLength will not exceed 8192 bytes.
I did a quick check and discovered that if I leave ubloxFile.Write commented out and just uncomment ubloxFile.Flush there are no adverse affects to the uart data.