Skip to content

Commit 205c1e4

Browse files
descampsaeriknyquist
authored andcommitted
Enable interrupt mode of UART tx
Previous version of write will never use the interrupt mode transmission, because it fails to check if holding register is empty. This commit fix that, and several bugs related to interrupt mode serial transmission. When possible, it uses the tx FIFO, in order to reduce the number of interrupts called and the overhead.
1 parent 5279509 commit 205c1e4

File tree

4 files changed

+44
-18
lines changed

4 files changed

+44
-18
lines changed

cores/arduino/UARTClass.cpp

+22-15
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ int UARTClass::read( void )
168168

169169
void UARTClass::flush( void )
170170
{
171-
while (_tx_buffer->_iHead != _tx_buffer->_iTail); //wait for transmit data to be sent
171+
while (_tx_buffer->_iHead != *(volatile int*)&(_tx_buffer->_iTail)); //wait for transmit data to be sent
172172
// Wait for transmission to complete
173173
while(!uart_tx_complete(CONFIG_UART_CONSOLE_INDEX));
174174
}
@@ -179,12 +179,11 @@ size_t UARTClass::write( const uint8_t uc_data )
179179
return(0);
180180

181181
// Is the hardware currently busy?
182-
if (_tx_buffer->_iTail != _tx_buffer->_iHead)
182+
if (_tx_buffer->_iTail != _tx_buffer->_iHead || !uart_tx_ready(CONFIG_UART_CONSOLE_INDEX))
183183
{
184184
// If busy we buffer
185185
int l = (_tx_buffer->_iHead + 1) % UART_BUFFER_SIZE;
186-
while (_tx_buffer->_iTail == l)
187-
; // Spin locks if we're about to overwrite the buffer. This continues once the data is sent
186+
while (*(volatile int*)&(_tx_buffer->_iTail) == l); // Spin locks if we're about to overwrite the buffer. This continues once the data is sent
188187

189188
_tx_buffer->_aucBuffer[_tx_buffer->_iHead] = uc_data;
190189
_tx_buffer->_iHead = l;
@@ -201,21 +200,29 @@ size_t UARTClass::write( const uint8_t uc_data )
201200

202201
void UARTClass::IrqHandler( void )
203202
{
204-
uint8_t uc_data;
205-
int ret;
206-
ret = uart_poll_in(CONFIG_UART_CONSOLE_INDEX, &uc_data);
207-
208-
while ( ret != -1 ) {
209-
_rx_buffer->store_char(uc_data);
203+
uart_irq_update(CONFIG_UART_CONSOLE_INDEX);
204+
// if irq is Receiver Data Available
205+
if(uart_irq_rx_ready(CONFIG_UART_CONSOLE_INDEX))
206+
{
207+
uint8_t uc_data;
208+
int ret;
210209
ret = uart_poll_in(CONFIG_UART_CONSOLE_INDEX, &uc_data);
210+
211+
while ( ret != -1 ) {
212+
_rx_buffer->store_char(uc_data);
213+
ret = uart_poll_in(CONFIG_UART_CONSOLE_INDEX, &uc_data);
214+
}
211215
}
212216

213-
// Do we need to keep sending data?
214-
if (!uart_irq_tx_ready(CONFIG_UART_CONSOLE_INDEX))
217+
// if irq is Transmitter Holding Register
218+
else if(uart_irq_tx_ready(CONFIG_UART_CONSOLE_INDEX))
215219
{
216-
if (_tx_buffer->_iTail != _tx_buffer->_iHead) {
217-
uart_poll_out(CONFIG_UART_CONSOLE_INDEX, _tx_buffer->_aucBuffer[_tx_buffer->_iTail]);
218-
_tx_buffer->_iTail = (unsigned int)(_tx_buffer->_iTail + 1) % UART_BUFFER_SIZE;
220+
if(_tx_buffer->_iTail != _tx_buffer->_iHead)
221+
{
222+
int end = (_tx_buffer->_iTail < _tx_buffer->_iHead) ? _tx_buffer->_iHead:UART_BUFFER_SIZE;
223+
int l = min(end - _tx_buffer->_iTail, UART_FIFO_SIZE);
224+
uart_fifo_fill(CONFIG_UART_CONSOLE_INDEX, _tx_buffer->_aucBuffer+_tx_buffer->_iTail, l);
225+
_tx_buffer->_iTail = (_tx_buffer->_iTail+l)%UART_BUFFER_SIZE;
219226
}
220227
else
221228
{

system/libarc32_arduino101/drivers/ns16550.c

+18-3
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ unsigned char uart_poll_out(
340340
)
341341
{
342342
/* wait for transmitter to ready to accept a character */
343-
while ((INBYTE(LSR(which)) & LSR_TEMT) == 0)
343+
while ((INBYTE(LSR(which)) & LSR_THRE) == 0)
344344
;
345345

346346
OUTBYTE(THR(which), outChar);
@@ -352,6 +352,8 @@ unsigned char uart_poll_out(
352352
*
353353
* uart_fifo_fill - fill FIFO with data
354354
*
355+
* It is up to the caller to make sure that FIFO capcity is not exceeded
356+
*
355357
* RETURNS: number of bytes sent
356358
*/
357359

@@ -362,8 +364,8 @@ int uart_fifo_fill(int which, /* UART on which to send */
362364
{
363365
int i;
364366

365-
for (i = 0; i < size && (INBYTE(LSR(which)) &
366-
LSR_BOTH_EMPTY) != 0; i++) {
367+
for (i = 0; i < size ; i++)
368+
{
367369
OUTBYTE(THR(which), txData[i]);
368370
}
369371
return i;
@@ -640,6 +642,19 @@ uint8_t uart_tx_complete(int which)
640642
return INBYTE(LSR(which)) & LSR_TEMT;
641643
}
642644

645+
/*******************************************************************************
646+
*
647+
* uart_tx_complete - check if tx holding register is empty
648+
*
649+
* RETURNS: zero if register is non-empty,
650+
* non-zero if register is empty (ready to receive new data)
651+
*/
652+
653+
uint8_t uart_tx_ready(int which)
654+
{
655+
return INBYTE(LSR(which)) & LSR_THRE;
656+
}
657+
643658
/*******************************************************************************
644659
*
645660
* uart_loop_enable - enable loopback

system/libarc32_arduino101/drivers/uart.h

+4
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ extern "C" {
5454
/* options for uart init */
5555
#define UART_OPTION_AFCE 0x01
5656

57+
/* Size of the FIFO in bytes */
58+
#define UART_FIFO_SIZE 16
59+
5760
/* generic UART info structure */
5861
struct uart_init_info {
5962
int baud_rate;
@@ -92,6 +95,7 @@ int uart_break_check(int port);
9295
void uart_break_send(int port, int delay);
9396
void uart_disable(int port);
9497
uint8_t uart_tx_complete(int which);
98+
uint8_t uart_tx_ready(int which);
9599
void uart_loop_enable(int which);
96100
void uart_loop_disable(int which);
97101

182 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)