Estoy estudiando el desarrollo de software alimentado por batería que use los controladores EFM Gekko (http://energymicro.com/) y me gustaría que el controlador esté dormido cuando no haya nada útil que esté haciendo. La instrucción WFI (Wait For Interrupt) se usa para este propósito; pondrá el procesador en suspensión hasta que se produzca una interrupción.
Si el sueño se activara almacenando algo en algún lugar, se podrían usar operaciones exclusivas de carga / tienda para hacer algo como:
// 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 omitir store_exclusive, lo que provocaría que el sistema se ejecutara a través del bucle una vez más (para ver si la interrupción se había establecido en dont_sleep). Desafortunadamente, el Gekko usa una instrucción WFI en lugar de una dirección de escritura para activar el modo de suspensión; escribiendo 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 el dont_sleep establecido, pero el wfi seguiría adelante y se ejecutaría de todos modos. ¿Cuál es el mejor patrón para prevenir eso? Establezca PRIMASK en 1 para evitar que las interrupciones interrumpan el procesador justo antes de ejecutar el WFI, y elimínelo inmediatamente después? ¿O hay algún truco mejor?
EDIT
Me pregunto sobre el bit de Evento. Según la descripción general, le gustaría que estuviera destinado a la compatibilidad con varios procesadores, pero se 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 establece la función de desactivación o desactivación también debe ejecutar una instrucción SEV, por lo que si la interrupción ocurre después de la prueba "if", el WFE borrará el indicador de evento pero no se pondrá en suspensión. ¿Eso suena como un buen paradigma?