This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
In this project i'm using a MSP430F169. The basic idea is main goes into LPM3 waiting for a timer to trigger the ADC interrupt. At the end of the ADC interrupt main gets woken up using _BIC_SR_IRQ(LPM3_bits); What will happen if main executes for too long and the ADC interrupt completes again while the processor is still awake?
void main(void) {
...
while(1) {
// Put main to sleep with interrupts enabled until ADC tells us to wake up
_BIS_SR(LPM3_bits+GIE);
...
}
}
Here's the bottom of the ADC interrupt in disassembly:
_BIC_SR_IRQ(LPM3_bits);
001D3A C0B1 00D0 0014 bic.w #0xD0,0x14(SP)
001D40 3C3A jmp 0x1DB6
To me it seems like bic.w will put the processor back in LPM3 if it is already awake. I'm also not sure why the bic.w has the SP as destination instead of the SR.
If main is still awake and the ADC ISR tries to wake it up, no harm is done and main will stay awake. This is the same situation as your code tries to clear certain bits in certain register that are already cleared. No harm is done and those bits stay cleared.
However, if subsequently main goes to sleep and you did not re-enable the Timer and ADC to wake it again, main might sleep forever because the original wake up ISR is already fired and executed.
ok I see now, my thinking was flawed. Why is it the SP that is the destination of the instruction instead of the SR though?
Actually the bic.w command is not acting on the SP but an address offset from the SP.
When the ISR is prompted, the status register (and various other stuff) is pushed onto the stack before the ISR function begins. When the ISR completes the old value of the SR is pushed back from the stack to restore the previous state. To exit a low power mode on return from an ISR you have to adjust the SR value that is on the stack - that way when the SR is restored upon return from the ISR the low power mode bits are no longer set and so the processor does not go back to sleep. That is what this command is doing.
If you think your foreground may run a bit long one time and not be asleep when the next ADC conversion is completed then you can add a global flag to indicate an unprocessed conversion is available. Set the flag during the ADC ISR. In main, test the flag before going to sleep e.g.
while(1)
{
// test if sleep required
while(!g_ucFlags.bit.unprocADC)
{
LPM3;
_nop();
}
// wake-up
g_ucFlags.bit.unprocADC = 0;
// etc...
}
You should probably ensure that the worst-case execution time of two consecutive runs through your main loop is less than the time for two ADC sample events to be prompted otherwise you may start dropping results.
When an interrupt is acknowledged, the current contents of SR and PC are both pushed to the stack. The SR is cleared, and the PC is loaded with the interrupt vector to invoke the ISR in the active mode. At the conclusion of ISR, the RETI instruction will pop the stack to SR and PC and restore them.
Thus inside the ISR, the LPM-bits in SR are already cleared. Clearing them again has no effect. On the other hand, if you clear those bits in the stored copy of the SR inside the stack, they will take effect after the RETI instruction.
**Attention** This is a public forum