Initial question
I have a general question about the handling of interrupts in microcontrollers. I am using the MSP430, but I think the question may be extended to other uCs. I would like to know whether is or not a good practice to enable/disable interrupts frequently along the code. I mean, if I have a portion of code that is not going to be sensitive to interrupts (or even worse, must not listen to interrupts, for any reason), is it better to:
- Disable the interrupts before and then re-enable them after the critical section.
- Put a flag inside the respective ISR and (instead of disabling the interrupt), set the flag to false before the critical section and resetting it to true, just after. To prevent the code of the ISR from being executed.
- Neither of the two, so suggestions are welcome!
Update: interrupts and state charts
I will provide a specific situation. Let us assume we want to implement a state chart, which is composed by 4 blocks:
- Transitions/Effect.
- Exit conditions.
- Entry activity.
- Do activity.
This is what a professor taught us at university. Probably, not the best way of doing it is by following this scheme:
while(true) {
/* Transitions/Effects */
//----------------------------------------------------------------------
next_state = current_state;
switch (current_state)
{
case STATE_A:
if(EVENT1) {next_state = STATE_C}
if(d == THRESHOLD) {next_state = STATE_D; a++}
break;
case STATE_B:
// transitions and effects
break;
(...)
}
/* Exit activity -> only performed if I leave the state for a new one */
//----------------------------------------------------------------------
if (next_state != current_state)
{
switch(current_state)
{
case STATE_A:
// Exit activity of STATE_A
break;
case STATE_B:
// Exit activity of STATE_B
break;
(...)
}
}
/* Entry activity -> only performed the 1st time I enter a state */
//----------------------------------------------------------------------
if (next_state != current_state)
{
switch(next_state)
{
case STATE_A:
// Entry activity of STATE_A
break;
case STATE_B:
// Entry activity of STATE_B
break;
(...)
}
}
current_state = next_state;
/* Do activity */
//----------------------------------------------------------------------
switch (current_state)
{
case STATE_A:
// Do activity of STATE_A
break;
case STATE_B:
// Do activity of STATE_B
break;
(...)
}
}
Let us also assume that from, say STATE_A
, I want to be sensitive to a interrupt coming from a set of buttons (with debouce system, etc. etc.). When someone presses one of these buttons, an interrupt is generated and the flag related to the input port is copied into a variable buttonPressed
. If the debounce is set to 200 ms in some way (watchdog timer, timer, counter, ...) we are sure that buttonPressed
cannot be updated with a new value before 200 ms.
This is what I am asking you (and myself :) of course)
Do I need to enable interrupt in the DO activity of STATE_A
and disable before leaving?
/* Do activity */
//-------------------------------------
switch (current_state)
{
case STATE_A:
// Do activity of STATE_A
Enable_ButtonsInterrupt(); // and clear flags before it
// Do fancy stuff and ...
// ... wait until a button is pressed (e.g. LPM3 of the MSP430)
// Here I have my buttonPressed flag ready!
Disable_ButtonsInterrupt();
break;
case STATE_B:
// Do activity of STATE_B
break;
(...)
}
In a way that I am sure that the next time I execxute block 1 (transition/effects) at the next iteration I am sure that the conditions checked along the transitions are not coming from a subsequent interrupt that has overwritten the previous value of buttonPressed
that I need (although it is impossible that this happens because 250 ms must elapse).