Skip to content

Commit 91e6926

Browse files
committed
Merge commit 'collin80-uart-fix' into ide-1.5.x
2 parents ad9fc89 + 37ea166 commit 91e6926

File tree

8 files changed

+140
-204
lines changed

8 files changed

+140
-204
lines changed

build/shared/revisions.txt

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ The following changes are included also in the Arduino IDE 1.0.7:
66
[ide]
77
* Mitigated Serial Monitor resource exhaustion when the connected device sends a lot of data (Paul Stoffregen)
88

9+
[core]
10+
* sam: HardwareSerial now performs ISR based buffered transmission (Collin Kidder)
11+
912
ARDUINO 1.6.0rc1
1013

1114
* IDE internals have been refactored and sorted out. (Claudio Indellicati)

hardware/arduino/sam/cores/arduino/RingBuffer.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
RingBuffer::RingBuffer( void )
2323
{
24-
memset( _aucBuffer, 0, SERIAL_BUFFER_SIZE ) ;
24+
memset( (void *)_aucBuffer, 0, SERIAL_BUFFER_SIZE ) ;
2525
_iHead=0 ;
2626
_iTail=0 ;
2727
}

hardware/arduino/sam/cores/arduino/RingBuffer.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@
2525
// using a ring buffer (I think), in which head is the index of the location
2626
// to which to write the next incoming character and tail is the index of the
2727
// location from which to read.
28-
#define SERIAL_BUFFER_SIZE 64
28+
#define SERIAL_BUFFER_SIZE 128
2929

3030
class RingBuffer
3131
{
3232
public:
33-
uint8_t _aucBuffer[SERIAL_BUFFER_SIZE] ;
34-
int _iHead ;
35-
int _iTail ;
33+
volatile uint8_t _aucBuffer[SERIAL_BUFFER_SIZE] ;
34+
volatile int _iHead ;
35+
volatile int _iTail ;
3636

3737
public:
3838
RingBuffer( void ) ;

hardware/arduino/sam/cores/arduino/UARTClass.cpp

+90-35
Original file line numberDiff line numberDiff line change
@@ -23,33 +23,39 @@
2323

2424
// Constructors ////////////////////////////////////////////////////////////////
2525

26-
UARTClass::UARTClass( Uart* pUart, IRQn_Type dwIrq, uint32_t dwId, RingBuffer* pRx_buffer )
26+
UARTClass::UARTClass( Uart *pUart, IRQn_Type dwIrq, uint32_t dwId, RingBuffer *pRx_buffer, RingBuffer *pTx_buffer )
2727
{
28-
_rx_buffer = pRx_buffer ;
28+
_rx_buffer = pRx_buffer;
29+
_tx_buffer = pTx_buffer;
2930

30-
_pUart=pUart ;
31-
_dwIrq=dwIrq ;
32-
_dwId=dwId ;
31+
_pUart=pUart;
32+
_dwIrq=dwIrq;
33+
_dwId=dwId;
3334
}
3435

3536
// Public Methods //////////////////////////////////////////////////////////////
3637

3738
void UARTClass::begin( const uint32_t dwBaudRate )
39+
{
40+
begin( dwBaudRate, UART_MR_PAR_NO | UART_MR_CHMODE_NORMAL );
41+
}
42+
43+
void UARTClass::begin( const uint32_t dwBaudRate, const uint32_t config )
3844
{
3945
// Configure PMC
40-
pmc_enable_periph_clk( _dwId ) ;
46+
pmc_enable_periph_clk( _dwId );
4147

4248
// Disable PDC channel
43-
_pUart->UART_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS ;
49+
_pUart->UART_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS;
4450

4551
// Reset and disable receiver and transmitter
46-
_pUart->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX | UART_CR_RXDIS | UART_CR_TXDIS ;
52+
_pUart->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX | UART_CR_RXDIS | UART_CR_TXDIS;
4753

4854
// Configure mode
49-
_pUart->UART_MR = UART_MR_PAR_NO | UART_MR_CHMODE_NORMAL ;
55+
_pUart->UART_MR = config;
5056

5157
// Configure baudrate (asynchronous, no oversampling)
52-
_pUart->UART_BRGR = (SystemCoreClock / dwBaudRate) >> 4 ;
58+
_pUart->UART_BRGR = (SystemCoreClock / dwBaudRate) >> 4;
5359

5460
// Configure interrupts
5561
_pUart->UART_IDR = 0xFFFFFFFF;
@@ -58,79 +64,128 @@ void UARTClass::begin( const uint32_t dwBaudRate )
5864
// Enable UART interrupt in NVIC
5965
NVIC_EnableIRQ(_dwIrq);
6066

67+
// Make sure both ring buffers are initialized back to empty.
68+
_rx_buffer->_iHead = _rx_buffer->_iTail = 0;
69+
_tx_buffer->_iHead = _tx_buffer->_iTail = 0;
70+
6171
// Enable receiver and transmitter
62-
_pUart->UART_CR = UART_CR_RXEN | UART_CR_TXEN ;
72+
_pUart->UART_CR = UART_CR_RXEN | UART_CR_TXEN;
6373
}
6474

6575
void UARTClass::end( void )
6676
{
67-
// clear any received data
68-
_rx_buffer->_iHead = _rx_buffer->_iTail ;
69-
70-
// Disable UART interrupt in NVIC
71-
NVIC_DisableIRQ( _dwIrq ) ;
77+
// Clear any received data
78+
_rx_buffer->_iHead = _rx_buffer->_iTail;
7279

7380
// Wait for any outstanding data to be sent
7481
flush();
7582

76-
pmc_disable_periph_clk( _dwId ) ;
83+
// Disable UART interrupt in NVIC
84+
NVIC_DisableIRQ( _dwIrq );
85+
86+
pmc_disable_periph_clk( _dwId );
87+
}
88+
89+
void UARTClass::setInterruptPriority(uint32_t priority)
90+
{
91+
NVIC_SetPriority(_dwIrq, priority & 0x0F);
92+
}
93+
94+
uint32_t UARTClass::getInterruptPriority()
95+
{
96+
return NVIC_GetPriority(_dwIrq);
7797
}
7898

7999
int UARTClass::available( void )
80100
{
81-
return (uint32_t)(SERIAL_BUFFER_SIZE + _rx_buffer->_iHead - _rx_buffer->_iTail) % SERIAL_BUFFER_SIZE ;
101+
return (uint32_t)(SERIAL_BUFFER_SIZE + _rx_buffer->_iHead - _rx_buffer->_iTail) % SERIAL_BUFFER_SIZE;
102+
}
103+
104+
int UARTClass::availableForWrite(void)
105+
{
106+
int head = _tx_buffer->_iHead;
107+
int tail = _tx_buffer->_iTail;
108+
if (head >= tail) return SERIAL_BUFFER_SIZE - 1 - head + tail;
109+
return tail - head - 1;
82110
}
83111

84112
int UARTClass::peek( void )
85113
{
86114
if ( _rx_buffer->_iHead == _rx_buffer->_iTail )
87-
return -1 ;
115+
return -1;
88116

89-
return _rx_buffer->_aucBuffer[_rx_buffer->_iTail] ;
117+
return _rx_buffer->_aucBuffer[_rx_buffer->_iTail];
90118
}
91119

92120
int UARTClass::read( void )
93121
{
94122
// if the head isn't ahead of the tail, we don't have any characters
95123
if ( _rx_buffer->_iHead == _rx_buffer->_iTail )
96-
return -1 ;
124+
return -1;
97125

98-
uint8_t uc = _rx_buffer->_aucBuffer[_rx_buffer->_iTail] ;
99-
_rx_buffer->_iTail = (unsigned int)(_rx_buffer->_iTail + 1) % SERIAL_BUFFER_SIZE ;
100-
return uc ;
126+
uint8_t uc = _rx_buffer->_aucBuffer[_rx_buffer->_iTail];
127+
_rx_buffer->_iTail = (unsigned int)(_rx_buffer->_iTail + 1) % SERIAL_BUFFER_SIZE;
128+
return uc;
101129
}
102130

103131
void UARTClass::flush( void )
104132
{
133+
while (_tx_buffer->_iHead != _tx_buffer->_iTail); //wait for transmit data to be sent
105134
// Wait for transmission to complete
106135
while ((_pUart->UART_SR & UART_SR_TXRDY) != UART_SR_TXRDY)
107-
;
136+
;
108137
}
109138

110139
size_t UARTClass::write( const uint8_t uc_data )
111140
{
112-
// Check if the transmitter is ready
113-
while ((_pUart->UART_SR & UART_SR_TXRDY) != UART_SR_TXRDY)
114-
;
115-
116-
// Send character
117-
_pUart->UART_THR = uc_data;
141+
// Is the hardware currently busy?
142+
if (((_pUart->UART_SR & UART_SR_TXRDY) != UART_SR_TXRDY) |
143+
(_tx_buffer->_iTail != _tx_buffer->_iHead))
144+
{
145+
// If busy we buffer
146+
unsigned int l = (_tx_buffer->_iHead + 1) % SERIAL_BUFFER_SIZE;
147+
while (_tx_buffer->_iTail == l)
148+
; // Spin locks if we're about to overwrite the buffer. This continues once the data is sent
149+
150+
_tx_buffer->_aucBuffer[_tx_buffer->_iHead] = uc_data;
151+
_tx_buffer->_iHead = l;
152+
// Make sure TX interrupt is enabled
153+
_pUart->UART_IER = UART_IER_TXRDY;
154+
}
155+
else
156+
{
157+
// Bypass buffering and send character directly
158+
_pUart->UART_THR = uc_data;
159+
}
118160
return 1;
119161
}
120162

121163
void UARTClass::IrqHandler( void )
122164
{
123165
uint32_t status = _pUart->UART_SR;
124166

125-
// Did we receive data ?
167+
// Did we receive data?
126168
if ((status & UART_SR_RXRDY) == UART_SR_RXRDY)
127169
_rx_buffer->store_char(_pUart->UART_RHR);
128170

171+
// Do we need to keep sending data?
172+
if ((status & UART_SR_TXRDY) == UART_SR_TXRDY)
173+
{
174+
if (_tx_buffer->_iTail != _tx_buffer->_iHead) {
175+
_pUart->UART_THR = _tx_buffer->_aucBuffer[_tx_buffer->_iTail];
176+
_tx_buffer->_iTail = (unsigned int)(_tx_buffer->_iTail + 1) % SERIAL_BUFFER_SIZE;
177+
}
178+
else
179+
{
180+
// Mask off transmit interrupt so we don't get it anymore
181+
_pUart->UART_IDR = UART_IDR_TXRDY;
182+
}
183+
}
184+
129185
// Acknowledge errors
130-
if ((status & UART_SR_OVRE) == UART_SR_OVRE ||
131-
(status & UART_SR_FRAME) == UART_SR_FRAME)
186+
if ((status & UART_SR_OVRE) == UART_SR_OVRE || (status & UART_SR_FRAME) == UART_SR_FRAME)
132187
{
133-
// TODO: error reporting outside ISR
188+
// TODO: error reporting outside ISR
134189
_pUart->UART_CR |= UART_CR_RSTSTA;
135190
}
136191
}

hardware/arduino/sam/cores/arduino/UARTClass.h

+22-22
Original file line numberDiff line numberDiff line change
@@ -28,32 +28,32 @@
2828
class UARTClass : public HardwareSerial
2929
{
3030
protected:
31-
RingBuffer *_rx_buffer ;
31+
RingBuffer *_rx_buffer;
32+
RingBuffer *_tx_buffer;
3233

3334
protected:
34-
Uart* _pUart ;
35-
IRQn_Type _dwIrq ;
36-
uint32_t _dwId ;
35+
Uart* _pUart;
36+
IRQn_Type _dwIrq;
37+
uint32_t _dwId;
3738

3839
public:
39-
UARTClass( Uart* pUart, IRQn_Type dwIrq, uint32_t dwId, RingBuffer* pRx_buffer ) ;
40-
41-
void begin( const uint32_t dwBaudRate ) ;
42-
void end( void ) ;
43-
int available( void ) ;
44-
int peek( void ) ;
45-
int read( void ) ;
46-
void flush( void ) ;
47-
size_t write( const uint8_t c ) ;
48-
49-
void IrqHandler( void ) ;
50-
51-
#if defined __GNUC__ /* GCC CS3 */
52-
using Print::write ; // pull in write(str) and write(buf, size) from Print
53-
#elif defined __ICCARM__ /* IAR Ewarm 5.41+ */
54-
// virtual void write( const char *str ) ;
55-
// virtual void write( const uint8_t *buffer, size_t size ) ;
56-
#endif
40+
UARTClass(Uart* pUart, IRQn_Type dwIrq, uint32_t dwId, RingBuffer* pRx_buffer, RingBuffer* pTx_buffer);
41+
42+
void begin(const uint32_t dwBaudRate);
43+
void begin(const uint32_t dwBaudRate, const uint32_t config);
44+
void end(void);
45+
int available(void);
46+
int availableForWrite(void);
47+
int peek(void);
48+
int read(void);
49+
void flush(void);
50+
size_t write(const uint8_t c);
51+
using Print::write; // pull in write(str) and write(buf, size) from Print
52+
53+
void setInterruptPriority(uint32_t priority);
54+
uint32_t getInterruptPriority();
55+
56+
void IrqHandler(void);
5757

5858
operator bool() { return true; }; // UART always active
5959
};

0 commit comments

Comments
 (0)