Plan d'expérience pour STM32L476
Objectif
Le programme donnera accés à 16 expériences de mesure de consommation :
expe | MSI | PLL | Voltage Scaling | Flash Latency | Calibration MSI vs LSE | Sleep (100Hz) | Blue Mode |
1 | 4 Mhz(def.) | 80 MHz | 1 (def.) | 4 | off | off->on | Sleep (100Hz) |
2 | 24 Mhz | off | 1 (def.) | 1 | off->on | off | Calibration MSI/LSE |
3 | 24 Mhz | off | 2 | 3 | off | off->on | Sleep (100Hz) |
4 | 24 Mhz | off | 2 | 3 | off->on | off | Calibration MSI/LSE |
5 | 24 Mhz | off | 2 | 3 | on | on | STOP0, wakeup 20s |
6 | 24 Mhz | off | 2 | 3 | on | on | STOP1, wakeup 20s |
7 | 24 Mhz | off | 2 | 3 | on | on | STOP2, wakeup 20s |
8 | 24 Mhz | off | 2 | 3 | on | on | SHUTDOWN, wakeup 20s |
Séquencement des expériences
- le numéro d'expérience expe sera stocké dans un backup register du module RTC
le module RTC restera actif sur toutes les expériences
- expe sera incrémenté à chaque reset, si le bouton bleu (PC13) est pressé à cet instant
il bouclera sur 1 après 8
- la LED verte (PA5) clignotera à 0.5 Hz avec une durée active égale à (expe * 50ms)
- le bouton bleu (PC13) produira un changement de mode (irréversible jusqu'au prochain reset), mémorisé dans la variable blue_mode
- pour mesurer la dérive de l'oscillateur, le port GPIO PC10 produira un signal carré à 50Hz
Déroulement des opérations
Au reset (entrée dans la fonction main()), le programme devra :
- initialiser le module RTC (en distinguant le démarrage à froid d'un
redémarrage consécutif à un reset (manuel ou causé par le wake-up timer)
- lire expe dans le backup register 0, l'incrémenter s'il y a lieu et l'écrire à nouveau
- configurer l'horloge système en fonction de expe,
y compris le voltage scaling et la latence de la mémoire flash
- activer la calibration de MSI vs LSE le cas échéant
- configurer le timer systick en fonction de la variable SystemCoreClock. Le handler de l'interruption systick gèrera :
- le clignotement de la LED
- la détection des actions sur le bouton bleu (détecter la transition repos->pressé)
- l'action sur le GPIO PC10 (sortie 50Hz)
- entrer dans la boucle principale, qui agira en fonction de la variable blue_mode
Initialisation RTC
Au démarrage "à froid", le programme devra effectuer une initialisation complète du module RTC, incluant principalement :
- le démarrage de l'oscillateur LSE (Low Speed External = quartz 32768 Hz), alimenté par le backup-domain
- le reset du backup-domain (ce qui va notamment mettre à zéro les backup-registers). Cette opération est indispensable pour activer l'oscillateur LSE.
- la config des 2 prescalers du RTC (AsynchPrescaler et SynchPrescaler). Attention, les registres de configuration du RTC sont protégés en écriture ! Il est donc nécessaire
de désactiver cette protection avant de pouvoir entrer en mode initialisation. Il faudra sortir du mode initialisation et remettre la protection en écriture à l'issue
de la confiuration du RTC.
Aux démarrages ultérieurs, "à chaud", le RTC est supposée déjà fonctionner, mais l'interface RTC-MPU n'est pas actif,
il faut l'initialiser avant de tenter l'accés aux backup-registers :
LL_APB1_GRP1_EnableClock( LL_APB1_GRP1_PERIPH_PWR );
LL_PWR_EnableBkUpAccess();
L'identification du démarrage à froid peut se faire en testant l'activité du LSE.
N.B. L'initialisation du wake-up timer n'est pas souhaitable à cette étape.
Horloge Système
Au reset, l'horloge est le MSI (Multi-Speed Internal Oscillator) à 4MHz par défaut.
Dans les démos ST, ainsi que le projet de départ "L476_ats_blink",
la PLL principale est activée avec une multiplication de 40 et
une post-division par 2 pour arriver à 80 MHz.
Pour fonctionner en MSI 24 MHz il faut :
- ne pas activer ni sélectionner comme source système la PLL
- changer la fréquence du MSI, en changeant de "Range"
N.B. le changement de range se fait en 2 étapes :
- changer le code de 4 bits dans MSISRANGE[3:0] (registre RCC->CR)
- mettre a 1 le bit MSIRGSEL dans le même registre
Si le nouveau scaling nécessite d'augmenter la latence d'accés à la mémoire flash,
cette augmentation doit être effectuée
avant la réduction de voltage.
Voltage Scaling
Le régulateur qui alimente le coeur du STM32L476 supporte deux "scalings" de la tension d'alimentation interne :
- range 1 "high performance" : 1.2 V, max 80 MHz (défaut)
- range 2 "Low power" : 1.0 V, max 26 MHz
Ceci est contrôlé par le registre PWR->CR1 du module PWR.
Si le nouveau scaling nécessite d'augmenter la latence d'accés à la mémoire flash, cette augmentation doit être effectuée
avant la réduction de la tension interne.
La latence flash se configure dans le registre FLASH->ACR (stm32l4xx_ll_system.h -> fonction LL_FLASH_SetLatency).
Calibration du MSI vs LPE
Le mécanisme dit "calibration" utilise une sorte de PLL asservie à l'oscillateur LSE,
totalement indépendante de la PLL principale.
Si le LSE est déjà actif (ce qui est le cas dans toute cette série d'expériences), il suffit
de mettre a 1 le bit MSIPLLEN dans le registre RCC->CR.
Wake-Up Timer
La mise en oeuvre du wake-up timer n'est pas nécessaire pour les mesures de consommation,
mais il est important de vérifier qu'on a une solution pour redémarrer le processeur après
passage en STOPx, STANDBY ou SHUTDOWN.
Le délai d'action du timer se configure en secondes (à condition que son horloge soit à 1Hz comme la RTC).
Le traitement de l'évènement wakeup est différent selon qu'on considère les modes STOPx ou les modes STANDBY et SHUTDOWN
(voir commentaires de l'exemple de code ci-dessous).
// partie commune a toutes les utilisations du wakeup timer
static void RTC_wakeup_init( int delay )
{
LL_RTC_DisableWriteProtection( RTC );
LL_RTC_WAKEUP_Disable( RTC );
while ( !LL_RTC_IsActiveFlag_WUTW( RTC ) )
{ }
// connecter le timer a l'horloge 1Hz de la RTC
LL_RTC_WAKEUP_SetClock( RTC, LL_RTC_WAKEUPCLOCK_CKSPRE );
// fixer la duree de temporisation
LL_RTC_WAKEUP_SetAutoReload( RTC, delay ); // 16 bits
LL_RTC_ClearFlag_WUT(RTC);
LL_RTC_EnableIT_WUT(RTC);
LL_RTC_WAKEUP_Enable(RTC);
LL_RTC_EnableWriteProtection(RTC);
}
// Dans le cas des modes STANDBY et SHUTDOWN, le MPU sera reveille par reset
// causé par 1 wakeup line (interne ou externe) (le NVIC n'est plus alimenté)
void RTC_wakeup_init_from_standby_or_shutdown( int delay )
{
RTC_wakeup_init( delay );
// enable the Internal Wake-up line
LL_PWR_EnableInternWU(); // ceci ne concerne que Standby et Shutdown, pas STOPx
}
// Dans le cas des modes STOPx, le MPU sera reveille par interruption
// le module EXTI et une partie du NVIC sont encore alimentes
// le contenu de la RAM et des registres étant préservé, le MPU
// reprend l'execution après l'instruction WFI
void RTC_wakeup_init_from_stop( int delay )
{
RTC_wakeup_init( delay );
// valider l'interrupt par la ligne 20 du module EXTI, qui est réservée au wakeup timer
LL_EXTI_EnableIT_0_31( LL_EXTI_LINE_20 );
LL_EXTI_EnableRisingTrig_0_31( LL_EXTI_LINE_20 );
// valider l'interrupt chez NVIC
NVIC_SetPriority( RTC_WKUP_IRQn, 1 );
NVIC_EnableIRQ( RTC_WKUP_IRQn );
}
// wakeup timer interrupt Handler (inutile mais doit etre defini)
void RTC_WKUP_IRQHandler()
{
LL_EXTI_ClearFlag_0_31( LL_EXTI_LINE_20 );
}