I don't know this specific MCU, but the question is fairly generic.
The obvious answer to all problems like these is to keep the ISRs as slim as possible. At most, they should stuff data into a ring buffer, which is later processed by the main program. (A MCU with DMA would have been even better, but I don't think you have DMA on MSP430?)
If the ISR is still too slow after such optimizations, then you have no other option but to do as you suggest: enable the global interrupt mask at the top of the UART ISR and let the higher priority interrupt take precedence. Be aware however, that when you allow more interrupts to come on top of an already executing ISR, you allow more stack depth.
Do I also need to unmask the serial RX interrupt at the end?
I assume that you have to do that from the ISR no matter the nature of the application? That's how most MCUs work. And yes, if you touch the global interrupt mask, you will have to clear the specific interrupt after you are done serving it, i.e. after you have copied the received data into local variables.
After the timer ISR returns, will the serial ISR continue, and then return to the main loop?
If you have changed the global interrupt mask, then yes.
Are there any potential race conditions I need to consider?
You always have to consider such whenever sharing data between an ISR and something else. It doesn't matter if the ISR only writes and the main program only reads etc, unless you can guarantee that each access is atomic, which you usually can't unless you write the code in assembler.
In a high level language, you may have to use some semaphore variable. How this is implemented is application-dependent. It particularly depends on if you can afford to miss out some data from the ISR or if you have to catch all data.
Is there a better solution?
DMA or a multi-core MCU.
I found you post when I was looking for optimization of ISR routine. Finally, I've got a solution which you (and I) wanted to get.
I use Atmel Studio 6.1 (GCC 3.4.2.1002)
ISR(TIM0_OVF_vect,ISR_NAKED)
{
asm volatile(
"push r24" "\n"
"in r24, __SREG__" "\n"
"push r24" "\n"
"push r25" "\n"
"lds r24, %A[_ts]" "\n"
"lds r25, %B[_ts]" "\n"
"adiw r24,1" "\n"
"sts %B[_ts], r25" "\n"
"sts %A[_ts], r24" "\n"
"pop r25" "\n"
"pop r24" "\n"
"out __SREG__,r24" "\n"
"pop r24" "\n"
"reti" "\n"
:
: [_ts] "m" (ts)
: "r24", "r25"
);
}
Here ts
is declared as volatile unsigned int ts = 0;
I use named operands ([_ts] "m" (ts)
) instead of defailt %0
The result is:
0000005a <__vector_11>:
5a: 8f 93 push r24
5c: 8f b7 in r24, 0x3f ; 63
5e: 8f 93 push r24
60: 9f 93 push r25
62: 80 91 60 00 lds r24, 0x0060
66: 90 91 61 00 lds r25, 0x0061
6a: 01 96 adiw r24, 0x01 ; 1
6c: 90 93 61 00 sts 0x0061, r25
70: 80 93 60 00 sts 0x0060, r24
74: 9f 91 pop r25
76: 8f 91 pop r24
78: 8f bf out 0x3f, r24 ; 63
7a: 8f 91 pop r24
7c: 18 95 reti
Best Answer
Definitely false. Look up the Interrupts and Events chapter in the Reference Manual, there are about 60 interrupt handlers.
There are a few instances where more peripherals share a single interrupt handler, but these are rather the exception than the rule.
There are ARM microcontrollers with a single interrupt handler (or rather 2, IRQ and FIQ), but the Cortex-M family has lots of them.
Each timer has its own handler, the advanced timers
TIM1
andTIM8
have some more for various event types. There is a tiny grain of truth however, as timers have a common interrupt vector for all (up to 4) of their channels, so the reading of a single status register can be necessary.Interrupt handling does not depend on the compiler. You don't even have to declare the interrupt handler as such, they can be ordinary C functions taking no parameters and returning nothing (
void
), as the necessary register saving and restoring is handled by the hardware.The source of the confusion might be HAL library shipped with CubeMX, which has common handler and callback functions for each peripheral type, passing around so-called handles with state information. You don't have to use HAL, you'd get by fine with the descriptions of using each peripheral in the Reference Manual.