Plan d'expérience pour STM32L476

Objectif

Le programme donnera accés à 16 expériences de mesure de consommation :
expeMSIPLLVoltage
Scaling
Flash
Latency
Calibration
MSI vs LSE
Sleep (100Hz)Blue Mode
14 Mhz(def.)80 MHz1 (def.)4off off->on Sleep (100Hz)
224 Mhz off 1 (def.)1off->onoff Calibration MSI/LSE
324 Mhz off 2 3off off->on Sleep (100Hz)
424 Mhz off 2 3off->onoff Calibration MSI/LSE
524 Mhz off 2 3on on STOP0, wakeup 20s
624 Mhz off 2 3on on STOP1, wakeup 20s
724 Mhz off 2 3on on STOP2, wakeup 20s
824 Mhz off 2 3on on SHUTDOWN, wakeup 20s

Séquencement des expériences

Déroulement des opérations

Au reset (entrée dans la fonction main()), le programme devra :
  1. 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)
  2. lire expe dans le backup register 0, l'incrémenter s'il y a lieu et l'écrire à nouveau
  3. configurer l'horloge système en fonction de expe, y compris le voltage scaling et la latence de la mémoire flash
  4. activer la calibration de MSI vs LSE le cas échéant
  5. 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)
  6. 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 : 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 : N.B. le changement de range se fait en 2 étapes : 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 : 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 );
}