Zeven Development

Fix Your Arduino UNO R4 UART Issues

ArduinoR4

Have the following Arduino UNO R4 issues?

  • Dropping Characters/Receiving Garbage
  • Serial Monitor not Working
  • Really Slow
  • Can't use Both Hardware UARTS at the same time
  • Need 9-bit Support

Arduino UNO R4 UART Issues with IO Expander Products

UART issues were reported by our customers, when using the Arduino UNO R4 with the IO Expander. When the Serial Monitor was enabled for debugging, the UART communications to the IO Expander started failing. What was going on? Surely a big company like Arduino would not release a faulty product? To help our customers we investigated the issue and discovered that the issue was with the Arduino UNO R4 UART driver and released this fix to help everyone else with these same issues.

IOExpanderR4

Transmit is Blocking

Upon examination of the UART::write(uint8_t) function we can clearly see the while (!tx_done), waiting for tx_done to be set by the Transmit End Interrupt. This function is blocking and will not return until the transmit is complete. What a waste of CPU!


/* -------------------------------------------------------------------------- */
size_t UART::write(uint8_t c) {
/* -------------------------------------------------------------------------- */
if(init_ok) {
    tx_done = false;
    R_SCI_UART_Write(&uart_ctrl, &c, 1);
    while (!tx_done) {}
    return 1;
  }
  else {
    return 0;
  }
}

Transmit Ring Buffer not Used

The class UART defines a txBuffer but is never used by the UART::write(uint8_t) function. What a waste of Memory!


class UART : public arduino::HardwareSerial {
  ...
  private:
  ...
    arduino::SafeRingBufferN<SERIAL_BUFFER_SIZE> txBuffer;
  ...
};

Ring Buffer is not Interrupt Safe

When you get a Receive Interrupt the function RingBufferN::store_char(uint8_t) is called which updates the _numElems variable. In your application when you call the Serial.read() function it calls the RingBufferN::read_char() which also updates the very same _numElems variable. This is not interrupt safe and can result in the _numElems not updating properly or even becoming corrupted.


/* -------------------------------------------------------------------------- */
void UART::WrapperCallback(uart_callback_args_t *p_args) {
/* -------------------------------------------------------------------------- */
  ...
    case UART_EVENT_RX_CHAR:
    {
    if (uart_ptr->rxBuffer.availableForStore()) {
      uart_ptr->rxBuffer.store_char(p_args->data);
    }
    break;
    }
  ...
}

void RingBufferN::store_char( uint8_t c )
{
  // 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.
  if (!isFull())
  {
    _aucBuffer[_iHead] = c ;
    _iHead = nextIndex(_iHead);
    _numElems = _numElems + 1;
  }
}

/* -------------------------------------------------------------------------- */
int UART::read() {
/* -------------------------------------------------------------------------- */
  return rxBuffer.read_char();
}

int RingBufferN::read_char()
{
  if (isEmpty())
    return -1;

  uint8_t value = _aucBuffer[_iTail];
  _iTail = nextIndex(_iTail);
  _numElems = _numElems - 1;

  return value;
}

USB Communications Blocks UART Interrupts

USB Communications has the same Interrupt Priority as UART communications, but the USB interrupt can consume too much time not allowing a UART interrupt, causing a Receive Interrupt Overrun at higher speed communications like 115k. No communication device should block others from getting their critical CPU time.


9-bit Support

To help support the IO Expander 9-bit mode, the UART class has also been modified to support 9-bit communications as well.


Download Files

Please make a backup of the files you are going to replace first, or you can reinstall the Arduino UNO R4 board package.

Download and replace the following files in the Arduino15\packages\arduino\hardware\renesas_uno\1.2.0\Cores\Arduino folder.

Windows: C:\Users\{username}\AppData\Local\Arduino15
macOS: /Users/{username}/Library/Arduino15
Linux: /home/{username}/.arduino15

serial.h
serial.cpp
IRQManager.cpp
api\HardwareSerial.h

Note: Fix is for Arduino UNO R4 v1.2.0 Board Package.

This fix is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.