4
\$\begingroup\$

I am working on a MSP430 connected to the PC via serial. The MSP430 also communicates with some other boards using a bit-banged serial interface. I'm using the timer peripheral to bit bang the serial, and I'm using the UART to talk to the PC.

When commands arrive from the PC, the USCIAB0RX_VECTOR interrupt gets executed, and while it's running, it blocks other interrupts. However, some times my serial RX routine takes a little while, which delays the timer interrupt and throws off the bit-bang interface.

In the serial RX ISR, I would like to allow the timer interrupt to still be serviced, but I would like to prevent the serial RX from interrupting itself (which shouldn't be able to happen for my specific application, but I would like to protect against this just in case)

  • Should I simply manually mask the serial RX interrupt in the top of the serial ISR, and then enable global interrupts?
  • Do I also need to unmask the serial RX interrupt at the end?
  • Do I need to manually clear any interrupt request flags?
  • After the timer ISR returns, will the serial ISR continue, and then return to the main loop?

  • Are there any potential race conditions I need to consider?

  • Is there a better solution?
  • Is there an article about interrupting and interrupt? (i've already read about nested interrupts in the users guide)
\$\endgroup\$

3 Answers 3

3
\$\begingroup\$

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.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Regarding "I don't think you have DMA on MSP430?": 223 of the 421 different MSP430 microcontrollers currently listed on TI.com do have DMA, starting with the MSP430F5131 at the low end of the price range ($1.20), which has 3 DMA channels. \$\endgroup\$ Dec 20, 2013 at 12:22
  • \$\begingroup\$ Regarding "each access is atomic, which you usually can't unless you write the code in assembler" - typically this would be done by the equivalent of cli(); atomic code block; sti(); in C, hence for the MSP430 family: __enable_interrupt(); // enable all interrupts --> GIE = 1 (HIGH) __disable_interrupt(); // disable all interrupts --> GIE = 0 (LOW) \$\endgroup\$ Dec 20, 2013 at 12:29
2
\$\begingroup\$

Move your RX packet handling routines from the interrupt vector. The interrupt function should be as short as possible (In your case, put a byte into a buffer for later processing and signal the main program that there is a byte pending). Decide upon priorities, which interface is more important? Peripheral or PC? Can one of them wait?

\$\endgroup\$
0
\$\begingroup\$

One possible solution is to serve the UART from the timer interrupt, not letting it interrupt by itself. Checking if a character has arrived on the UART and storing it in a buffer can be done with a few instructions. Next you service the bit banging. Exiting the timer interrupt allows user mode code to run until next timer interrupt. When not bit banging, you might elect to enable the UART interrupt and increase time between timer interrupts to garn more time in user mode.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.