diff --git a/cores/arduino/UARTClass.cpp b/cores/arduino/UARTClass.cpp index 922cf74d..cfb21828 100644 --- a/cores/arduino/UARTClass.cpp +++ b/cores/arduino/UARTClass.cpp @@ -93,7 +93,7 @@ void UARTClass::init(const uint32_t dwBaudRate, const uint8_t modeReg) while (uart_irq_rx_ready(CONFIG_UART_CONSOLE_INDEX)) uart_fifo_read(CONFIG_UART_CONSOLE_INDEX, &c, 1); - + uart_irq_err_enable(CONFIG_UART_CONSOLE_INDEX); uart_irq_rx_enable(CONFIG_UART_CONSOLE_INDEX); } @@ -116,6 +116,7 @@ void UARTClass::end( void ) //enable loopback, needed to prevent a short disconnection to be //interpreted as a packet and corrupt receiver state uart_loop_enable(CONFIG_UART_CONSOLE_INDEX); + uart_irq_err_disable(CONFIG_UART_CONSOLE_INDEX); SET_PIN_MODE(17, GPIO_MUX_MODE); // Rdx SOC PIN (Arduino header pin 0) SET_PIN_MODE(16, GPIO_MUX_MODE); // Txd SOC PIN (Arduino header pin 1) @@ -168,7 +169,7 @@ int UARTClass::read( void ) void UARTClass::flush( void ) { - while (_tx_buffer->_iHead != _tx_buffer->_iTail); //wait for transmit data to be sent + while (_tx_buffer->_iHead != *(volatile int*)&(_tx_buffer->_iTail)); //wait for transmit data to be sent // Wait for transmission to complete while(!uart_tx_complete(CONFIG_UART_CONSOLE_INDEX)); } @@ -179,11 +180,11 @@ size_t UARTClass::write( const uint8_t uc_data ) return(0); // Is the hardware currently busy? - if (_tx_buffer->_iTail != _tx_buffer->_iHead) + if (_tx_buffer->_iTail != _tx_buffer->_iHead || !uart_tx_ready(CONFIG_UART_CONSOLE_INDEX)) { // If busy we buffer int l = (_tx_buffer->_iHead + 1) % SERIAL_BUFFER_SIZE; - while (_tx_buffer->_iTail == l) + while (*(volatile int*)&(_tx_buffer->_iTail) == l) ; // Spin locks if we're about to overwrite the buffer. This continues once the data is sent _tx_buffer->_aucBuffer[_tx_buffer->_iHead] = uc_data; @@ -201,21 +202,39 @@ size_t UARTClass::write( const uint8_t uc_data ) void UARTClass::IrqHandler( void ) { - uint8_t uc_data; - int ret; - ret = uart_poll_in(CONFIG_UART_CONSOLE_INDEX, &uc_data); - - while ( ret != -1 ) { - _rx_buffer->store_char(uc_data); + uart_irq_update(CONFIG_UART_CONSOLE_INDEX); + // if irq is Receiver Line Status + if(uart_irq_err_detected(CONFIG_UART_CONSOLE_INDEX)) + { + // if it is a break line, we discard the data + if(uart_break_check(CONFIG_UART_CONSOLE_INDEX)) + { + uint8_t uc_data; + uart_poll_in(CONFIG_UART_CONSOLE_INDEX, &uc_data); + } + } + // if irq is Receiver Data Available + else if(uart_irq_rx_ready(CONFIG_UART_CONSOLE_INDEX)) + { + uint8_t uc_data; + int ret; ret = uart_poll_in(CONFIG_UART_CONSOLE_INDEX, &uc_data); + + while ( ret != -1 ) { + _rx_buffer->store_char(uc_data); + ret = uart_poll_in(CONFIG_UART_CONSOLE_INDEX, &uc_data); + } } - // Do we need to keep sending data? - if (!uart_irq_tx_ready(CONFIG_UART_CONSOLE_INDEX)) + // if irq is Transmitter Holding Register + else if(uart_irq_tx_ready(CONFIG_UART_CONSOLE_INDEX)) { - if (_tx_buffer->_iTail != _tx_buffer->_iHead) { - uart_poll_out(CONFIG_UART_CONSOLE_INDEX, _tx_buffer->_aucBuffer[_tx_buffer->_iTail]); - _tx_buffer->_iTail = (unsigned int)(_tx_buffer->_iTail + 1) % SERIAL_BUFFER_SIZE; + if(_tx_buffer->_iTail != _tx_buffer->_iHead) + { + int end = (_tx_buffer->_iTail < _tx_buffer->_iHead) ? _tx_buffer->_iHead:SERIAL_BUFFER_SIZE; + int l = min(end - _tx_buffer->_iTail, UART_FIFO_SIZE); + uart_fifo_fill(CONFIG_UART_CONSOLE_INDEX, _tx_buffer->_aucBuffer+_tx_buffer->_iTail, l); + _tx_buffer->_iTail = (_tx_buffer->_iTail+l)%SERIAL_BUFFER_SIZE; } else { diff --git a/system/libarc32_arduino101/drivers/ns16550.c b/system/libarc32_arduino101/drivers/ns16550.c index 386c6b22..f32d5d32 100644 --- a/system/libarc32_arduino101/drivers/ns16550.c +++ b/system/libarc32_arduino101/drivers/ns16550.c @@ -340,7 +340,7 @@ unsigned char uart_poll_out( ) { /* wait for transmitter to ready to accept a character */ - while ((INBYTE(LSR(which)) & LSR_TEMT) == 0) + while ((INBYTE(LSR(which)) & LSR_THRE) == 0) ; OUTBYTE(THR(which), outChar); @@ -352,6 +352,8 @@ unsigned char uart_poll_out( * * uart_fifo_fill - fill FIFO with data * +* It is up to the caller to make sure that FIFO capcity is not exceeded +* * RETURNS: number of bytes sent */ @@ -362,8 +364,8 @@ int uart_fifo_fill(int which, /* UART on which to send */ { int i; - for (i = 0; i < size && (INBYTE(LSR(which)) & - LSR_BOTH_EMPTY) != 0; i++) { + for (i = 0; i < size ; i++) + { OUTBYTE(THR(which), txData[i]); } return i; @@ -640,6 +642,19 @@ uint8_t uart_tx_complete(int which) return INBYTE(LSR(which)) & LSR_TEMT; } +/******************************************************************************* +* +* uart_tx_complete - check if tx holding register is empty +* +* RETURNS: zero if register is non-empty, +* non-zero if register is empty (ready to receive new data) +*/ + +uint8_t uart_tx_ready(int which) +{ + return INBYTE(LSR(which)) & LSR_THRE; +} + /******************************************************************************* * * uart_loop_enable - enable loopback diff --git a/system/libarc32_arduino101/drivers/uart.h b/system/libarc32_arduino101/drivers/uart.h index ed737780..456c244b 100644 --- a/system/libarc32_arduino101/drivers/uart.h +++ b/system/libarc32_arduino101/drivers/uart.h @@ -54,6 +54,9 @@ extern "C" { /* options for uart init */ #define UART_OPTION_AFCE 0x01 +/* Size of the FIFO in bytes */ +#define UART_FIFO_SIZE 16 + /* generic UART info structure */ struct uart_init_info { int baud_rate; @@ -92,6 +95,7 @@ int uart_break_check(int port); void uart_break_send(int port, int delay); void uart_disable(int port); uint8_t uart_tx_complete(int which); +uint8_t uart_tx_ready(int which); void uart_loop_enable(int which); void uart_loop_disable(int which);