From 2fedb00552e45aaca1623789138d223690244f43 Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Wed, 24 Dec 2014 10:20:37 -0500 Subject: [PATCH] Switch all of the transmit interrupt code to UARTClass. Also, turn USARTClass into a stub because it did nothing differently from the UART code anyway. Now all serial ports use transmit interrupts. --- .../arduino/sam/cores/arduino/UARTClass.cpp | 58 +++++++- .../arduino/sam/cores/arduino/UARTClass.h | 5 +- .../arduino/sam/cores/arduino/USARTClass.cpp | 132 +----------------- .../arduino/sam/cores/arduino/USARTClass.h | 14 +- .../sam/variants/arduino_due_x/variant.cpp | 3 +- 5 files changed, 66 insertions(+), 146 deletions(-) diff --git a/hardware/arduino/sam/cores/arduino/UARTClass.cpp b/hardware/arduino/sam/cores/arduino/UARTClass.cpp index 16188b128..99e7219b5 100644 --- a/hardware/arduino/sam/cores/arduino/UARTClass.cpp +++ b/hardware/arduino/sam/cores/arduino/UARTClass.cpp @@ -23,9 +23,10 @@ // Constructors //////////////////////////////////////////////////////////////// -UARTClass::UARTClass( Uart* pUart, IRQn_Type dwIrq, uint32_t dwId, RingBuffer* pRx_buffer ) +UARTClass::UARTClass( Uart *pUart, IRQn_Type dwIrq, uint32_t dwId, RingBuffer *pRx_buffer, RingBuffer *pTx_buffer ) { _rx_buffer = pRx_buffer ; + _tx_buffer = pTx_buffer; _pUart=pUart ; _dwIrq=dwIrq ; @@ -34,7 +35,14 @@ UARTClass::UARTClass( Uart* pUart, IRQn_Type dwIrq, uint32_t dwId, RingBuffer* p // Public Methods ////////////////////////////////////////////////////////////// + + void UARTClass::begin( const uint32_t dwBaudRate ) +{ + begin( dwBaudRate, UART_MR_PAR_NO | UART_MR_CHMODE_NORMAL ); +} + +void UARTClass::begin( const uint32_t dwBaudRate, const uint32_t config ) { // Configure PMC pmc_enable_periph_clk( _dwId ) ; @@ -46,7 +54,7 @@ void UARTClass::begin( const uint32_t dwBaudRate ) _pUart->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX | UART_CR_RXDIS | UART_CR_TXDIS ; // Configure mode - _pUart->UART_MR = UART_MR_PAR_NO | UART_MR_CHMODE_NORMAL ; + _pUart->UART_MR = config ; // Configure baudrate (asynchronous, no oversampling) _pUart->UART_BRGR = (SystemCoreClock / dwBaudRate) >> 4 ; @@ -58,6 +66,10 @@ void UARTClass::begin( const uint32_t dwBaudRate ) // Enable UART interrupt in NVIC NVIC_EnableIRQ(_dwIrq); + //make sure both ring buffers are initialized back to empty. + _rx_buffer->_iHead = _rx_buffer->_iTail = 0; + _tx_buffer->_iHead = _tx_buffer->_iTail = 0; + // Enable receiver and transmitter _pUart->UART_CR = UART_CR_RXEN | UART_CR_TXEN ; } @@ -67,6 +79,8 @@ void UARTClass::end( void ) // clear any received data _rx_buffer->_iHead = _rx_buffer->_iTail ; + while (_tx_buffer->_iHead != _tx_buffer->_iTail); //wait for transmit data to be sent + // Disable UART interrupt in NVIC NVIC_DisableIRQ( _dwIrq ) ; @@ -81,6 +95,14 @@ int UARTClass::available( void ) return (uint32_t)(SERIAL_BUFFER_SIZE + _rx_buffer->_iHead - _rx_buffer->_iTail) % SERIAL_BUFFER_SIZE ; } +int UARTClass::availableForWrite(void) +{ + int head = _tx_buffer->_iHead; + int tail = _tx_buffer->_iTail; + if (head >= tail) return SERIAL_BUFFER_SIZE - 1 - head + tail; + return tail - head - 1; +} + int UARTClass::peek( void ) { if ( _rx_buffer->_iHead == _rx_buffer->_iTail ) @@ -109,12 +131,21 @@ void UARTClass::flush( void ) size_t UARTClass::write( const uint8_t uc_data ) { - // Check if the transmitter is ready - while ((_pUart->UART_SR & UART_SR_TXRDY) != UART_SR_TXRDY) - ; + if ((_pUart->UART_SR & UART_SR_TXRDY) != UART_SR_TXRDY) //is the hardware currently busy? + { + //if busy we buffer + unsigned int l = (_tx_buffer->_iHead + 1) % SERIAL_BUFFER_SIZE; + while (_tx_buffer->_iTail == l); //spin locks if we're about to overwrite the buffer. This continues once the data is sent - // Send character - _pUart->UART_THR = uc_data; + _tx_buffer->_aucBuffer[_tx_buffer->_iHead] = uc_data; + _tx_buffer->_iHead = l; + _pUart->UART_IER = UART_IER_TXRDY; //make sure TX interrupt is enabled + } + else + { + // Send character + _pUart->UART_THR = uc_data ; + } return 1; } @@ -126,6 +157,19 @@ void UARTClass::IrqHandler( void ) if ((status & UART_SR_RXRDY) == UART_SR_RXRDY) _rx_buffer->store_char(_pUart->UART_RHR); + //Do we need to keep sending data? + if ((status & UART_SR_TXRDY) == UART_SR_TXRDY) + { + if (_tx_buffer->_iTail != _tx_buffer->_iHead) { //just in case + _pUart->UART_THR = _tx_buffer->_aucBuffer[_tx_buffer->_iTail]; + _tx_buffer->_iTail = (unsigned int)(_tx_buffer->_iTail + 1) % SERIAL_BUFFER_SIZE; + } + else + { + _pUart->UART_IDR = UART_IDR_TXRDY; //mask off transmit interrupt so we don't get it anymore + } + } + // Acknowledge errors if ((status & UART_SR_OVRE) == UART_SR_OVRE || (status & UART_SR_FRAME) == UART_SR_FRAME) diff --git a/hardware/arduino/sam/cores/arduino/UARTClass.h b/hardware/arduino/sam/cores/arduino/UARTClass.h index 5836f2e62..6c513374f 100644 --- a/hardware/arduino/sam/cores/arduino/UARTClass.h +++ b/hardware/arduino/sam/cores/arduino/UARTClass.h @@ -29,6 +29,7 @@ class UARTClass : public HardwareSerial { protected: RingBuffer *_rx_buffer ; + RingBuffer *_tx_buffer; protected: Uart* _pUart ; @@ -36,11 +37,13 @@ class UARTClass : public HardwareSerial uint32_t _dwId ; public: - UARTClass( Uart* pUart, IRQn_Type dwIrq, uint32_t dwId, RingBuffer* pRx_buffer ) ; + UARTClass( Uart* pUart, IRQn_Type dwIrq, uint32_t dwId, RingBuffer* pRx_buffer, RingBuffer* pTx_buffer) ; void begin( const uint32_t dwBaudRate ) ; + void begin( const uint32_t dwBaudRate , const uint32_t config ) ; void end( void ) ; int available( void ) ; + int availableForWrite(void); int peek( void ) ; int read( void ) ; void flush( void ) ; diff --git a/hardware/arduino/sam/cores/arduino/USARTClass.cpp b/hardware/arduino/sam/cores/arduino/USARTClass.cpp index ce2c28a5c..310e5680b 100644 --- a/hardware/arduino/sam/cores/arduino/USARTClass.cpp +++ b/hardware/arduino/sam/cores/arduino/USARTClass.cpp @@ -23,14 +23,10 @@ // Constructors //////////////////////////////////////////////////////////////// -USARTClass::USARTClass( Usart* pUsart, IRQn_Type dwIrq, uint32_t dwId, RingBuffer* pRx_buffer, RingBuffer* pTx_buffer ) +USARTClass::USARTClass( Usart* pUsart, IRQn_Type dwIrq, uint32_t dwId, RingBuffer* pRx_buffer, RingBuffer* pTx_buffer ) : UARTClass((Uart*)pUsart, dwIrq, dwId, pRx_buffer, pTx_buffer) { - _rx_buffer = pRx_buffer; - _tx_buffer = pTx_buffer; - _pUsart=pUsart ; - _dwIrq=dwIrq ; - _dwId=dwId ; + _pUsart=pUsart ; //In case anyone needs USART specific functionality in the future } // Public Methods ////////////////////////////////////////////////////////////// @@ -42,140 +38,26 @@ void USARTClass::begin( const uint32_t dwBaudRate ) void USARTClass::begin( const uint32_t dwBaudRate, const uint32_t config ) { - // Configure PMC - pmc_enable_periph_clk( _dwId ) ; - - // Disable PDC channel - _pUsart->US_PTCR = US_PTCR_RXTDIS | US_PTCR_TXTDIS ; - - // Reset and disable receiver and transmitter - _pUsart->US_CR = US_CR_RSTRX | US_CR_RSTTX | US_CR_RXDIS | US_CR_TXDIS ; - - // Configure mode - _pUsart->US_MR = config; - - - // Configure baudrate, asynchronous no oversampling - _pUsart->US_BRGR = (SystemCoreClock / dwBaudRate) / 16 ; - - // Configure interrupts - _pUsart->US_IDR = 0xFFFFFFFF; - _pUsart->US_IER = US_IER_RXRDY | US_IER_OVRE | US_IER_FRAME; - - // Enable UART interrupt in NVIC - NVIC_EnableIRQ( _dwIrq ) ; - - //make sure both ring buffers are initialized back to empty. - _rx_buffer->_iHead = _rx_buffer->_iTail = 0; - _tx_buffer->_iHead = _tx_buffer->_iTail = 0; - - // Enable receiver and transmitter - _pUsart->US_CR = US_CR_RXEN | US_CR_TXEN ; + UARTClass::begin(dwBaudRate, config); } void USARTClass::end( void ) { - // clear any received data - _rx_buffer->_iHead = _rx_buffer->_iTail ; - - while (_tx_buffer->_iHead != _tx_buffer->_iTail); //wait for transmit data to be sent - - // Disable UART interrupt in NVIC - NVIC_DisableIRQ( _dwIrq ) ; - - // Wait for any outstanding data to be sent - flush(); - - pmc_disable_periph_clk( _dwId ) ; -} - -int USARTClass::available( void ) -{ - return (uint32_t)(SERIAL_BUFFER_SIZE + _rx_buffer->_iHead - _rx_buffer->_iTail) % SERIAL_BUFFER_SIZE ; -} - -int USARTClass::availableForWrite(void) -{ - int head = _tx_buffer->_iHead; - int tail = _tx_buffer->_iTail; - if (head >= tail) return SERIAL_BUFFER_SIZE - 1 - head + tail; - return tail - head - 1; -} - -int USARTClass::peek( void ) -{ - if ( _rx_buffer->_iHead == _rx_buffer->_iTail ) - return -1 ; - - return _rx_buffer->_aucBuffer[_rx_buffer->_iTail] ; -} - -int USARTClass::read( void ) -{ - // if the head isn't ahead of the tail, we don't have any characters - if ( _rx_buffer->_iHead == _rx_buffer->_iTail ) - return -1 ; - - uint8_t uc = _rx_buffer->_aucBuffer[_rx_buffer->_iTail] ; - _rx_buffer->_iTail = (unsigned int)(_rx_buffer->_iTail + 1) % SERIAL_BUFFER_SIZE ; - return uc ; + UARTClass::end(); } void USARTClass::flush( void ) { - // Wait for transmission to complete - while ((_pUsart->US_CSR & US_CSR_TXRDY) != US_CSR_TXRDY) - ; + UARTClass::flush(); } size_t USARTClass::write( const uint8_t uc_data ) { - if ((_pUsart->US_CSR & US_CSR_TXRDY) != US_CSR_TXRDY) //is the hardware currently busy? - { - //if busy we buffer - unsigned int l = (_tx_buffer->_iHead + 1) % SERIAL_BUFFER_SIZE; - while (_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; - _tx_buffer->_iHead = l; - _pUsart->US_IER = US_IER_TXRDY; //make sure TX interrupt is enabled - } - else - { - // Send character - _pUsart->US_THR = uc_data ; - } - return 1; + return UARTClass::write(uc_data); } void USARTClass::IrqHandler( void ) { - uint32_t status = _pUsart->US_CSR; - - // Did we receive data ? - if ((status & US_CSR_RXRDY) == US_CSR_RXRDY) - { - _rx_buffer->store_char(_pUsart->US_RHR); - } - //Do we need to keep sending data? - if ((status & US_CSR_TXRDY) == US_CSR_TXRDY) - { - if (_tx_buffer->_iTail != _tx_buffer->_iHead) { //just in case - _pUsart->US_THR = _tx_buffer->_aucBuffer[_tx_buffer->_iTail]; - _tx_buffer->_iTail = (unsigned int)(_tx_buffer->_iTail + 1) % SERIAL_BUFFER_SIZE; - } - else - { - _pUsart->US_IDR = US_IDR_TXRDY; //mask off transmit interrupt so we don't get it anymore - } - } - - // Acknowledge errors - if ((status & US_CSR_OVRE) == US_CSR_OVRE || - (status & US_CSR_FRAME) == US_CSR_FRAME) - { - // TODO: error reporting outside ISR - _pUsart->US_CR |= US_CR_RSTSTA; - } + UARTClass::IrqHandler(); } diff --git a/hardware/arduino/sam/cores/arduino/USARTClass.h b/hardware/arduino/sam/cores/arduino/USARTClass.h index fcce9fd12..53fee41d8 100644 --- a/hardware/arduino/sam/cores/arduino/USARTClass.h +++ b/hardware/arduino/sam/cores/arduino/USARTClass.h @@ -19,7 +19,7 @@ #ifndef _USART_CLASS_ #define _USART_CLASS_ -#include "HardwareSerial.h" +#include "UARTClass.h" #include "RingBuffer.h" // Includes Atmel CMSIS @@ -56,16 +56,10 @@ #define SERIAL_7O2 (US_MR_USART_MODE_NORMAL | US_MR_USCLKS_MCK | US_MR_CHRL_7_BIT | US_MR_PAR_ODD | US_MR_NBSTOP_2_BIT | US_MR_CHMODE_NORMAL) #define SERIAL_8O2 (US_MR_USART_MODE_NORMAL | US_MR_USCLKS_MCK | US_MR_CHRL_8_BIT | US_MR_PAR_ODD | US_MR_NBSTOP_2_BIT | US_MR_CHMODE_NORMAL) -class USARTClass : public HardwareSerial +class USARTClass : public UARTClass { - protected: - RingBuffer *_rx_buffer; - RingBuffer *_tx_buffer; - protected: Usart* _pUsart ; - IRQn_Type _dwIrq ; - uint32_t _dwId ; public: USARTClass( Usart* pUsart, IRQn_Type dwIrq, uint32_t dwId, RingBuffer* pRx_buffer, RingBuffer* pTx_buffer ) ; @@ -73,10 +67,6 @@ class USARTClass : public HardwareSerial void begin( const uint32_t dwBaudRate ) ; void begin( const uint32_t dwBaudRate , const uint32_t config ) ; void end( void ) ; - int available( void ) ; - int availableForWrite(void); - int peek( void ) ; - int read( void ) ; void flush( void ) ; size_t write( const uint8_t c ) ; diff --git a/hardware/arduino/sam/variants/arduino_due_x/variant.cpp b/hardware/arduino/sam/variants/arduino_due_x/variant.cpp index f746fdf44..4cbe0df80 100644 --- a/hardware/arduino/sam/variants/arduino_due_x/variant.cpp +++ b/hardware/arduino/sam/variants/arduino_due_x/variant.cpp @@ -299,8 +299,9 @@ extern const PinDescription g_APinDescription[]= * UART objects */ RingBuffer rx_buffer1; +RingBuffer tx_buffer1; -UARTClass Serial(UART, UART_IRQn, ID_UART, &rx_buffer1); +UARTClass Serial(UART, UART_IRQn, ID_UART, &rx_buffer1, &tx_buffer1); void serialEvent() __attribute__((weak)); void serialEvent() { }