Hi:
I'm really struggling to understand how to deal with USCI39 on a 5xx MSP430. Are there any more technical details available anywhere on this errata, or are there any TI engineers more familiar with this errata? (Specifically what "unpredictable code execution" means?)
I've been observing situations where, when attempting to return from an interrupt handler (which sets GIE, obviously), the MSP430 apparently jumps to the completely wrong location. Setting a breakpoint at the 'RETI' instruction and attempting to single-step afterwards results in the FET returning an "Unknown State" error, and while SR has been set to the correct value (the previous stack pointer) and SP has been incremented by 4, PC is something else entirely. Which sounds like the "unpredictable code execution" bit in USCI39, although it's much more reproducible than that errata would imply.
So attempting to work around this, I ran into a stumbling block. Specifically, the errata says that you should
"Disable the UCSTTIFG, UCSTPIFG and UCNACKIFG before the GIE is set. After GIE is
set, the local interrupt enable flags can be set again."
However, there are two cases where this is impossible: first, when the uC is deciding whether or not to go to sleep, and second, in an interrupt handler. In the first case, it needs to
- Disable interrupts
- Check whatever condition it needs to to decide whether or not to go to sleep
- Set GIE and some of the LPM bits (e.g. GIE + CPUOFF) atomically
After step 3, it obviously can't re-enable the local interrupt flags, because it's no longer running.
I can't think of any way out of this, other than "no low power mode." Is there something I'm missing here?
In the second case, obviously RETI pops off SR, reenabling interrupts, and the previous SP. So I guess you could do something like test UCBxIE for (UCSTTIE/UCSTPIE/UCNACKIE), preserve them, clear UCBxIE, reenable interrupts, and then restore UCBxIE before returning from interrupt. That is,
cmp.b &UCBxIE jz do_reti push.b &UCBxIE clr.b &UCBxIE eint nop pop.b &UCBxIE do_reti: reti
for every interrupt handler. I think this is safe, because although interrupts could pop up between "eint nop pop.b", presumedly none of them would modify UCBxIE since they would see it as cleared.