From b0ba1ee8bb8f89d765c6d0016728603ae4c95530 Mon Sep 17 00:00:00 2001 From: Andrew Cunningham Date: Mon, 18 Oct 2021 10:12:48 +0200 Subject: [PATCH] fix Serial.flush() blocks forever #597 * The aynchronous nature of the DRE and TXC interrupt flags causes issues (lockups) when the TX DATA register is empty on start and a flush is issued. Simply looking at the DRE prior to waiting for TXC is insufficient because the data register may well be empty but the shift register could still contain data, in this case SERCOM::flushUART() would return before TXC has been raised thus before flushing is complete. * bool added to SERCOM.h to indicate when it is ok for SERCOM::flushUART() to wait for the TXC flag. This flag is set when any data is written to the data register via SERCOM::writeDataUART(). It is cleared when a flush is done. --- cores/arduino/SERCOM.cpp | 11 +++++++---- cores/arduino/SERCOM.h | 5 +++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/cores/arduino/SERCOM.cpp b/cores/arduino/SERCOM.cpp index b9fbf05b9..ab86aabab 100644 --- a/cores/arduino/SERCOM.cpp +++ b/cores/arduino/SERCOM.cpp @@ -112,11 +112,10 @@ void SERCOM::enableUART() void SERCOM::flushUART() { // Skip checking transmission completion if data register is empty -// if(isDataRegisterEmptyUART()) -// return; + // Wait for transmission to complete, if ok to do so. + while(!sercom->USART.INTFLAG.bit.TXC && onFlushWaitUartTXC); - // Wait for transmission to complete - while(!sercom->USART.INTFLAG.bit.TXC); + onFlushWaitUartTXC = false; } void SERCOM::clearStatusUART() @@ -183,6 +182,10 @@ int SERCOM::writeDataUART(uint8_t data) //Put data into DATA register sercom->USART.DATA.reg = (uint16_t)data; + + // indicate it's ok to wait for TXC flag when flushing + onFlushWaitUartTXC = true; + return 1; } diff --git a/cores/arduino/SERCOM.h b/cores/arduino/SERCOM.h index cbc3a05de..80b54de5b 100644 --- a/cores/arduino/SERCOM.h +++ b/cores/arduino/SERCOM.h @@ -218,6 +218,11 @@ class SERCOM uint8_t calculateBaudrateSynchronous(uint32_t baudrate) ; uint32_t division(uint32_t dividend, uint32_t divisor) ; void initClockNVIC( void ) ; + + // Flag set when data is loaded into sercom->USART.DATA.reg. + // Helps with preventing UART lockups when flushing on startup + // and the asyncronous nature of the DRE and TXC interrupt flags. + bool onFlushWaitUartTXC = false; }; #endif