From b98946b5c1b46e9399dae8d1cc41a15b2a5ee15f Mon Sep 17 00:00:00 2001 From: Victor Oliveira Date: Thu, 10 Sep 2020 00:46:50 -0300 Subject: [PATCH] Raise STM32F1 UART IRQ Priority, add error handling (#19301) (Error handling for Overrun, Framing and Parity.) --- Marlin/src/HAL/STM32/MarlinSerial.cpp | 6 +-- Marlin/src/HAL/STM32F1/MarlinSerial.cpp | 55 ++++++++++++++++--------- Marlin/src/HAL/STM32F1/MarlinSerial.h | 15 +++++++ 3 files changed, 52 insertions(+), 24 deletions(-) diff --git a/Marlin/src/HAL/STM32/MarlinSerial.cpp b/Marlin/src/HAL/STM32/MarlinSerial.cpp index 8d99ab7855..2d799ea54d 100644 --- a/Marlin/src/HAL/STM32/MarlinSerial.cpp +++ b/Marlin/src/HAL/STM32/MarlinSerial.cpp @@ -55,10 +55,8 @@ void MarlinSerial::begin(unsigned long baud, uint8_t config) { HardwareSerial::begin(baud, config); - // replace the IRQ callback with the one we have defined - #if ENABLED(EMERGENCY_PARSER) - _serial.rx_callback = _rx_callback; - #endif + // Replace the IRQ callback with the one we have defined + TERN_(EMERGENCY_PARSER, _serial.rx_callback = _rx_callback); } // This function is Copyright (c) 2006 Nicholas Zambetti. diff --git a/Marlin/src/HAL/STM32F1/MarlinSerial.cpp b/Marlin/src/HAL/STM32F1/MarlinSerial.cpp index 61fde718b3..9a48e901f4 100644 --- a/Marlin/src/HAL/STM32F1/MarlinSerial.cpp +++ b/Marlin/src/HAL/STM32F1/MarlinSerial.cpp @@ -29,28 +29,43 @@ // Copied from ~/.platformio/packages/framework-arduinoststm32-maple/STM32F1/system/libmaple/usart_private.h // Changed to handle Emergency Parser static inline __always_inline void my_usart_irq(ring_buffer *rb, ring_buffer *wb, usart_reg_map *regs, MarlinSerial &serial) { - /* Handle RXNEIE and TXEIE interrupts. - * RXNE signifies availability of a byte in DR. - * - * See table 198 (sec 27.4, p809) in STM document RM0008 rev 15. - * We enable RXNEIE. - */ - if ((regs->CR1 & USART_CR1_RXNEIE) && (regs->SR & USART_SR_RXNE)) { - uint8_t c = (uint8)regs->DR; - #ifdef USART_SAFE_INSERT - // If the buffer is full and the user defines USART_SAFE_INSERT, - // ignore new bytes. - rb_safe_insert(rb, c); - #else - // By default, push bytes around in the ring buffer. - rb_push_insert(rb, c); - #endif - #if ENABLED(EMERGENCY_PARSER) - emergency_parser.update(serial.emergency_state, c); - #endif + /* Handle RXNEIE and TXEIE interrupts. + * RXNE signifies availability of a byte in DR. + * + * See table 198 (sec 27.4, p809) in STM document RM0008 rev 15. + * We enable RXNEIE. + */ + uint32_t srflags = regs->SR, cr1its = regs->CR1; + + if ((cr1its & USART_CR1_RXNEIE) && (srflags & USART_SR_RXNE)) { + if (srflags & USART_SR_FE || srflags & USART_SR_PE ) { + // framing error or parity error + regs->DR; // Read and throw away the data, which also clears FE and PE + } + else { + uint8_t c = (uint8)regs->DR; + #ifdef USART_SAFE_INSERT + // If the buffer is full and the user defines USART_SAFE_INSERT, + // ignore new bytes. + rb_safe_insert(rb, c); + #else + // By default, push bytes around in the ring buffer. + rb_push_insert(rb, c); + #endif + #if ENABLED(EMERGENCY_PARSER) + emergency_parser.update(serial.emergency_state, c); + #endif + } + } + else if (srflags & USART_SR_ORE) { + // overrun and empty data, just do a dummy read to clear ORE + // and prevent a raise condition where a continous interrupt stream (due to ORE set) occurs + // (see chapter "Overrun error" ) in STM32 reference manual + regs->DR; } + // TXE signifies readiness to send a byte to DR. - if ((regs->CR1 & USART_CR1_TXEIE) && (regs->SR & USART_SR_TXE)) { + if ((cr1its & USART_CR1_TXEIE) && (srflags & USART_SR_TXE)) { if (!rb_is_empty(wb)) regs->DR=rb_remove(wb); else diff --git a/Marlin/src/HAL/STM32F1/MarlinSerial.h b/Marlin/src/HAL/STM32F1/MarlinSerial.h index 4e8a47d2f9..eb0059bfbc 100644 --- a/Marlin/src/HAL/STM32F1/MarlinSerial.h +++ b/Marlin/src/HAL/STM32F1/MarlinSerial.h @@ -22,6 +22,7 @@ #pragma once #include +#include #include #include "../../inc/MarlinConfigPre.h" @@ -29,6 +30,8 @@ #include "../../feature/e_parser.h" #endif +#define UART_IRQ_PRIO 1 + class MarlinSerial : public HardwareSerial { public: MarlinSerial(struct usart_dev *usart_device, uint8 tx_pin, uint8 rx_pin) : @@ -38,6 +41,18 @@ public: #endif { } + #ifdef UART_IRQ_PRIO + // shadow the parent methods to set irq priority after the begin + void begin(uint32 baud) { + MarlinSerial::begin(baud, SERIAL_8N1); + } + + void begin(uint32 baud, uint8_t config) { + HardwareSerial::begin(baud, config); + nvic_irq_set_priority(c_dev()->irq_num, UART_IRQ_PRIO); + } + #endif + #if ENABLED(EMERGENCY_PARSER) EmergencyParser::State emergency_state; #endif