Estoy estudiando el desarrollo de software alimentado por batería utilizando los controladores EFM Gekko (http://energymicro.com/) y me gustaría que el controlador estuviera dormido siempre que no haya nada útil que hacer. La instrucción WFI (Wait For Interrupt) se utiliza para este propósito; pondrá el procesador en reposo hasta que se produzca una interrupción.
Si el sueño se comprometiera almacenando algo en algún lugar, se podrían utilizar operaciones de carga-exclusiva/almacenamiento-exclusivo para hacer algo así:
// dont\_sleep gets loaded with 2 any time something happens that
// should force the main loop to cycle at least once. If an interrupt
// occurs that causes it to be reset to 2 during the following statement,
// behavior will be as though the interrupt happened after it.
store\_exclusive(load\_exclusive(dont\_sleep) >> 1);
while(!dont\_sleep)
{
// If interrupt occurs between next statement and store\_exclusive, don't sleep
load\_exclusive(SLEEP\_TRIGGER);
if (!dont\_sleep)
store\_exclusive(SLEEP\_TRIGGER);
}
Si se produjera una interrupción entre las operaciones load_exclusive y store_exclusive, el efecto sería saltarse la store_exclusive, haciendo así que el sistema recorriera el bucle una vez más (para ver si la interrupción había activado dont_sleep). Desafortunadamente, el Gekko utiliza una instrucción WFI en lugar de una dirección de escritura para activar el modo sleep; escribir código como
if (!dont\_sleep)
WFI();
correría el riesgo de que se produjera una interrupción entre el 'if' y el 'wfi' y fijara dont_sleep, pero el wfi seguiría adelante y se ejecutaría de todos modos. ¿Cuál es el mejor patrón para evitar eso? ¿Poner PRIMASK a 1 para evitar que las interrupciones interrumpan el procesador justo antes de ejecutar el WFI, y borrarlo inmediatamente después? ¿O hay algún truco mejor?
EDITAR
Me pregunto por la parte del Evento. Por la descripción general, parece que está pensado para soporte multiprocesador, pero me preguntaba si algo como lo siguiente podría funcionar:
if (dont\_sleep)
SEV(); /\* Will make following WFE clear event flag but not sleep \*/
WFE();
Cada interrupción que activa don't_sleep también debería ejecutar una instrucción SEV, de modo que si la interrupción ocurre después de la prueba "if", el WFE borraría la bandera de evento pero no entraría en reposo. ¿Le parece un buen paradigma?