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
3738void 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
6575void 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
7999int 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
84112int 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
92120int 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
103131void 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
110139size_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
121163void 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}
0 commit comments