From 8447da19c80c3a41c8bc221f4e085d3c1c79b2cf Mon Sep 17 00:00:00 2001 From: Georg Icking-Konert Date: Fri, 8 Nov 2019 06:10:16 +0100 Subject: [PATCH 1/2] added optional custom handler to Serial interrupt added optional custom handler to Serial interrupt. Is similar to NeoHWSerial by SlashDevin (https://github.com/SlashDevin/NeoHWSerial), but: - user function also gets UART status as parameter to e.g. detect LIN break in user routine. - ported to Arduino Due Added as core extension because AFAIK cannot be implemented as library for Due. Also note similar pull request for AVR (https://github.com/arduino/ArduinoCore-avr/pull/297) --- cores/arduino/UARTClass.cpp | 23 ++++++++++++++++++++--- cores/arduino/UARTClass.h | 8 ++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/cores/arduino/UARTClass.cpp b/cores/arduino/UARTClass.cpp index 36de1358..c7566664 100644 --- a/cores/arduino/UARTClass.cpp +++ b/cores/arduino/UARTClass.cpp @@ -31,6 +31,8 @@ UARTClass::UARTClass( Uart *pUart, IRQn_Type dwIrq, uint32_t dwId, RingBuffer *p _pUart=pUart; _dwIrq=dwIrq; _dwId=dwId; + + _isr = NULL; } // Public Methods ////////////////////////////////////////////////////////////// @@ -166,13 +168,28 @@ size_t UARTClass::write( const uint8_t uc_data ) return 1; } +void UARTClass::attachInterrupt( USART_isr_t fn ) +{ + _isr = fn; +} + void UARTClass::IrqHandler( void ) { uint32_t status = _pUart->UART_SR; // Did we receive data? - if ((status & UART_SR_RXRDY) == UART_SR_RXRDY) - _rx_buffer->store_char(_pUart->UART_RHR); + if ((status & UART_SR_RXRDY) == UART_SR_RXRDY) { + + // user function was attached -> call it with data and status byte + if (_isr) { + _isr(_pUart->UART_RHR, status); + } + // no user function attached -> store in ring buffer + else { + _rx_buffer->store_char(_pUart->UART_RHR); + } + + } // Do we need to keep sending data? if ((status & UART_SR_TXRDY) == UART_SR_TXRDY) @@ -189,7 +206,7 @@ void UARTClass::IrqHandler( void ) } // Acknowledge errors - if ((status & UART_SR_OVRE) == UART_SR_OVRE || (status & UART_SR_FRAME) == UART_SR_FRAME) + if ((status & UART_SR_OVRE) == UART_SR_OVRE || (status & UART_SR_FRAME) == UART_SR_FRAME || (status & UART_SR_RXBRK) == UART_SR_RXBRK) { // TODO: error reporting outside ISR _pUart->UART_CR |= UART_CR_RSTSTA; diff --git a/cores/arduino/UARTClass.h b/cores/arduino/UARTClass.h index 3747d8be..f32919aa 100644 --- a/cores/arduino/UARTClass.h +++ b/cores/arduino/UARTClass.h @@ -31,6 +31,9 @@ #define SERIAL_8M1 UARTClass::Mode_8M1 #define SERIAL_8S1 UARTClass::Mode_8S1 +// missing in CMSIS +#define UART_SR_RXBRK (0x1u << 2) + class UARTClass : public HardwareSerial { @@ -60,6 +63,10 @@ class UARTClass : public HardwareSerial void IrqHandler(void); + typedef void (*USART_isr_t)(uint8_t data, uint32_t status); + void attachInterrupt( USART_isr_t fn ); + void detachInterrupt() { attachInterrupt( (USART_isr_t) NULL ); }; + operator bool() { return true; }; // UART always active protected: @@ -72,6 +79,7 @@ class UARTClass : public HardwareSerial IRQn_Type _dwIrq; uint32_t _dwId; + USART_isr_t _isr; }; #endif // _UART_CLASS_ From 266e10efb0792cb6b75e5113129fb64348afe8d5 Mon Sep 17 00:00:00 2001 From: Georg Icking-Konert Date: Sat, 23 Nov 2019 14:00:23 +0100 Subject: [PATCH 2/2] add Serialx.attachInterrupt_Send - add Serialx.attachInterrupt_Send() - rename Serialx.attachInterrupt() to Serialx.attachInterrupt_Receive() --- cores/arduino/UARTClass.cpp | 53 ++++++++++++++++++++++++++++++++----- cores/arduino/UARTClass.h | 13 +++++---- 2 files changed, 54 insertions(+), 12 deletions(-) diff --git a/cores/arduino/UARTClass.cpp b/cores/arduino/UARTClass.cpp index c7566664..cd207faa 100644 --- a/cores/arduino/UARTClass.cpp +++ b/cores/arduino/UARTClass.cpp @@ -20,6 +20,7 @@ #include #include #include "UARTClass.h" +#include "Arduino.h" // Constructors //////////////////////////////////////////////////////////////// @@ -32,7 +33,8 @@ UARTClass::UARTClass( Uart *pUart, IRQn_Type dwIrq, uint32_t dwId, RingBuffer *p _dwIrq=dwIrq; _dwId=dwId; - _isr = NULL; + _isrRx = NULL; + _isrTx = NULL; } // Public Methods ////////////////////////////////////////////////////////////// @@ -168,9 +170,28 @@ size_t UARTClass::write( const uint8_t uc_data ) return 1; } -void UARTClass::attachInterrupt( USART_isr_t fn ) +void UARTClass::attachInterrupt_Receive( isrRx_t fn ) { - _isr = fn; + // pause interrupts + uint8_t oldISR = ((__get_PRIMASK() & 0x1) == 0 && (__get_FAULTMASK() & 0x1) == 0); noInterrupts(); + + // set custom function + _isrRx = fn; + + // restore old interrupt setting + if (oldISR != 0) { interrupts(); } +} + +void UARTClass::attachInterrupt_Send( isrTx_t fn ) +{ + // pause interrupts + uint8_t oldISR = ((__get_PRIMASK() & 0x1) == 0 && (__get_FAULTMASK() & 0x1) == 0); noInterrupts(); + + // set custom function for TX empty + _isrTx = fn; + + // restore old interrupt setting + if (oldISR != 0) { interrupts(); } } void UARTClass::IrqHandler( void ) @@ -180,11 +201,11 @@ void UARTClass::IrqHandler( void ) // Did we receive data? if ((status & UART_SR_RXRDY) == UART_SR_RXRDY) { - // user function was attached -> call it with data and status byte - if (_isr) { - _isr(_pUart->UART_RHR, status); + // custom function was attached -> call it with data and status byte + if (_isrRx) { + _isrRx(_pUart->UART_RHR, status); } - // no user function attached -> store in ring buffer + // no custom function attached -> store data in ring buffer else { _rx_buffer->store_char(_pUart->UART_RHR); } @@ -202,6 +223,24 @@ void UARTClass::IrqHandler( void ) { // Mask off transmit interrupt so we don't get it anymore _pUart->UART_IDR = UART_IDR_TXRDY; + + // if custom routine attached, activate TXBUFE interrupt -> delay call until transmission finished + if (_isrTx != NULL) { + _pUart->UART_IER = UART_IER_TXEMPTY; + } + } + + } + + // Is data transmission finished? Used for call of attached custom function at end of transmission? + if ((status & UART_SR_TXEMPTY) == UART_SR_TXEMPTY) + { + // Mask off interrupt so we don't get it anymore + _pUart->UART_IDR = UART_IDR_TXEMPTY; + + // if custom routine attached, call it + if (_isrTx != NULL) { + _isrTx(); } } diff --git a/cores/arduino/UARTClass.h b/cores/arduino/UARTClass.h index f32919aa..693ee3a3 100644 --- a/cores/arduino/UARTClass.h +++ b/cores/arduino/UARTClass.h @@ -34,7 +34,6 @@ // missing in CMSIS #define UART_SR_RXBRK (0x1u << 2) - class UARTClass : public HardwareSerial { public: @@ -63,9 +62,12 @@ class UARTClass : public HardwareSerial void IrqHandler(void); - typedef void (*USART_isr_t)(uint8_t data, uint32_t status); - void attachInterrupt( USART_isr_t fn ); - void detachInterrupt() { attachInterrupt( (USART_isr_t) NULL ); }; + typedef void (* isrRx_t)(uint8_t data, uint32_t status); + typedef void (* isrTx_t)( void ); + void attachInterrupt_Receive( isrRx_t fn ); + void detachInterrupt_Receive( void ) { attachInterrupt_Receive( (isrRx_t) NULL); }; + void attachInterrupt_Send( isrTx_t fn ); + void detachInterrupt_Send( void ) { attachInterrupt_Send( (isrTx_t) NULL); }; operator bool() { return true; }; // UART always active @@ -79,7 +81,8 @@ class UARTClass : public HardwareSerial IRQn_Type _dwIrq; uint32_t _dwId; - USART_isr_t _isr; + isrRx_t _isrRx; + isrTx_t _isrTx; }; #endif // _UART_CLASS_