Code: Select all
SIGNAL(USARTn_RX_vect){
uint8_t i = (serialHeadRX[n] + 1) % SERIAL_RX_BUFFER_SIZE;
if (i != serialTailRX[n]) {serialBufferRX[serialHeadRX[n]][n] = UDRn; serialHeadRX[n] = i;}
}
Where all the lowercase 'n' characters are replaced by the USART number.
This code is very much like the Arduino Core "HardwareSerial.cpp" library. The library uses some 'inline' routines; the resulting code is nearly, but not quite, identical. In both places, the code is intentionally written to stop when the buffer is about to 'wrap' or 'overflow. To quote the library:
// if we should be storing the received character into the location
// just before the tail (meaning that the head would advance to the
// current location of the tail), we're about to overflow the buffer
// and so we don't write the character or advance the head.
However, there is a crucial difference. The library routing ALWAYS reads the UDRn register. The code in MultiWii does not, if an overflow is about to occur. Unfortunately, there is an negative interaction with ATmega hardware if UDRn is not read. The read is required to clear the interrupt. If the read does not occur, as soon as the interrupt handler exits, the interrupt will re-interrupt. Since the buffer is still full, the sketch ends up doing nothing but taking that interrupt over and over. From an outside view, everything just dies.
I believe this is an undesired behavior, but this serial stuff is not my code. There are two ways we could change it. First, we could follow the Arduino serial library and discard data once the buffer is full. This leaves the oldest data in the buffer, and discards the newest:
Code: Select all
SIGNAL(USARTn_RX_vect){
uint8_t i = (serialHeadRX[n] + 1) % SERIAL_RX_BUFFER_SIZE;
uint8_t c = UDRn;
if (i != serialTailRX[n]) {serialBufferRX[serialHeadRX[n]][n] = c; serialHeadRX[n] = i;}
}
Or, we could read the freshest data, and advance the buffer tail to discard the oldest unread:
Code: Select all
SIGNAL(USARTn_RX_vect){
uint8_t i = (serialHeadRX[n] + 1) % SERIAL_RX_BUFFER_SIZE;
serialBufferRX[serialHeadRX[n]][n] = UDRn; serialHeadRX[n] = i;
if (i = serialTailRX[n]) serialTailRX[n] = (serialTailRX[n] + 1) % SERIAL_RX_BUFFER_SIZE;
}
Which do you prefer?
I believe, given the kinds of things we are reading most of the time, like Spektrum or SBUS receivers, or GUIs, or pushbuttons on LCDs for configuration, that the freshest data is the most desirable. I therefore vote for the second fix.
But, again, which do you prefer?