Skip to content

Commit a7c33fe

Browse files
committed
UART: manually handle IRQ if DRE + interrupts disabled or in higher priority ISR
When write is called and TX buffer is full.
1 parent ee913a0 commit a7c33fe

File tree

3 files changed

+24
-3
lines changed

3 files changed

+24
-3
lines changed

Diff for: cores/arduino/SERCOM.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,7 @@ void SERCOM::initClockNVIC( void )
688688

689689
// Setting NVIC
690690
NVIC_EnableIRQ(IdNvic);
691-
NVIC_SetPriority (IdNvic, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority */
691+
NVIC_SetPriority (IdNvic, SERCOM_NVIC_PRIORITY); /* set Priority */
692692

693693
//Setting clock
694694
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( clockId ) | // Generic Clock 0 (SERCOMx)

Diff for: cores/arduino/SERCOM.h

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

2222
#include "sam.h"
2323

24-
#define SERCOM_FREQ_REF 48000000
24+
#define SERCOM_FREQ_REF 48000000
25+
#define SERCOM_NVIC_PRIORITY ((1<<__NVIC_PRIO_BITS) - 1)
2526

2627
typedef enum
2728
{

Diff for: cores/arduino/Uart.cpp

+21-1
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,27 @@ size_t Uart::write(const uint8_t data)
154154
if (sercom->isDataRegisterEmptyUART() && txBuffer.available() == 0) {
155155
sercom->writeDataUART(data);
156156
} else {
157-
while(txBuffer.isFull()); // spin lock until a spot opens up in the buffer
157+
// spin lock until a spot opens up in the buffer
158+
while(txBuffer.isFull()) {
159+
uint8_t interruptsEnabled = ((__get_PRIMASK() & 0x1) == 0);
160+
161+
if (interruptsEnabled) {
162+
uint32_t exceptionNumber = (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk);
163+
164+
if (exceptionNumber == 0 ||
165+
NVIC_GetPriority((IRQn_Type)(exceptionNumber - 16)) > SERCOM_NVIC_PRIORITY) {
166+
// no exception or called from an ISR with lower priority,
167+
// wait for free buffer spot via IRQ
168+
continue;
169+
}
170+
}
171+
172+
// interrupts are disabled or called from ISR with higher or equal priority than the SERCOM IRQ
173+
// manually call the UART IRQ handler when the data register is empty
174+
if (sercom->isDataRegisterEmptyUART()) {
175+
IrqHandler();
176+
}
177+
}
158178

159179
txBuffer.store_char(data);
160180

0 commit comments

Comments
 (0)