Je cherche à développer un logiciel alimenté par batterie en utilisant les contrôleurs EFM Gekko (http://energymicro.com/) et je voudrais que le contrôleur soit en veille chaque fois qu'il n'y a rien d'utile à faire. L'instruction WFI (Wait For Interrupt) est utilisée à cet effet; il mettra le processeur en veille jusqu'à ce qu'une interruption se produise.
Si le sommeil était activé en stockant quelque chose quelque part, on pourrait utiliser des opérations de chargement exclusif / magasin exclusif pour faire quelque chose comme:
// dont_sleep est chargé de 2 chaque fois que quelque chose arrive // devrait forcer la boucle principale à tourner au moins une fois. Si une interruption // se produit qui entraîne sa réinitialisation à 2 lors de l'instruction suivante, // le comportement sera comme si l'interruption s'était produite après. store_exclusive (load_exclusive (dont_sleep) >> 1); while (! dont_sleep) { // Si une interruption se produit entre la prochaine instruction et store_exclusive, ne dors pas load_exclusive (SLEEP_TRIGGER); si (! dont_sleep) store_exclusive (SLEEP_TRIGGER); }
Si une interruption devait se produire entre les opérations load_exclusive et store_exclusive, l'effet serait d'ignorer store_exclusive, ce qui obligerait le système à parcourir la boucle une fois de plus (pour voir si l'interruption avait défini dont_sleep). Malheureusement, le Gekko utilise une instruction WFI plutôt qu'une adresse d'écriture pour déclencher le mode veille; écrire du code comme
si (! dont_sleep) WFI ();
courrait le risque qu'une interruption puisse se produire entre le «si» et le «wfi» et définirait dont_sleep, mais le wfi irait de l'avant et s'exécuterait de toute façon. Quel est le meilleur schéma pour éviter cela? Réglez PRIMASK sur 1 pour empêcher les interruptions d'interrompre le processeur juste avant d'exécuter le WFI, et effacez-le immédiatement après? Ou y a-t-il une meilleure astuce?
ÉDITER
Je m'interroge sur le bit Event. D'après la description générale, il aimerait qu'il soit destiné à la prise en charge multi-processeur, mais se demandait si quelque chose comme ce qui suit pouvait fonctionner:
if (dont_sleep) SEV (); / * Rendra le drapeau d'événement WFE clair mais ne dormira pas * / WFE ();
Chaque interruption qui définit don't_sleep doit également exécuter une instruction SEV, donc si l'interruption se produit après le test "if", la WFE effacera l'indicateur d'événement mais ne se mettra pas en veille. Cela ressemble-t-il à un bon paradigme?
Réponses:
Je n'ai pas bien compris la
dont_sleep
chose, mais une chose que vous pourriez essayer est de faire le "travail principal" dans le gestionnaire PendSV, défini sur la priorité la plus basse. Ensuite, planifiez simplement un PendSV à partir d'autres gestionnaires chaque fois que vous avez besoin de quelque chose. Voir ici comment faire (c'est pour M1 mais M3 n'est pas trop différent).Une autre chose que vous pourriez utiliser (peut-être avec l'approche précédente) est la fonction Veille à la sortie. Si vous l'activez, le processeur se mettra en veille après avoir quitté le dernier gestionnaire ISR, sans que vous ayez à appeler WFI. Voir quelques exemples ici .
la source
Mettez-le dans une section critique. Les ISR ne s'exécuteront pas, vous ne courez donc pas le risque de changer dont_sleep avant WFI, mais ils réveilleront toujours le processeur et les ISR s'exécuteront dès la fin de la section critique.
Votre environnement de développement a probablement des fonctions de section critiques, mais c'est à peu près comme ceci:
EnterCriticalSection est:
ExitCriticalSection est:
la source
Votre idée va bien, c'est exactement ce que Linux implémente. Voyez ici .
Citation utile du fil de discussion mentionné ci-dessus pour clarifier pourquoi WFI fonctionne même avec des interruptions désactivées:
la source
En admettant que:
Ensuite, la solution consiste à utiliser PRIMASK pour bloquer les interruptions entre la validation de l'indicateur et WFI:
la source
Qu'en est-il du mode veille à la sortie? Cela se met automatiquement en veille chaque fois qu'un gestionnaire IRQ se termine, il n'y a donc pas vraiment de "mode normal" en cours d'exécution une fois configuré. Un IRQ se produit, il se réveille et exécute le gestionnaire, puis se rendort. Aucun WFI nécessaire.
la source