🛠 Sommeil profond Stop et réveil par RTC
Objectifs
Diviser la consommation par mille : plonger le GD32F103 en mode Stop (cœur et horloges APB arrêtés, SRAM conservée) et le réveiller périodiquement avec la RTC. Ordre de grandeur donné par la datasheet : environ 5,6 à 5,8 µA en standby RTC active, et un réveil en quelques microsecondes depuis le sleep. Vous apprendrez la hiérarchie Sleep/Stop/Standby, le rôle de VBAT et d'IRC40K (ou LXTAL 32,768 kHz), et le piège du retour à IRC8M après réveil.
Matériel
- Carte GD32F103C8T6 / CBT6 compatible Blue Pill ; pour mesurer le µA, retirer la LED et le régulateur de la carte (ou utiliser une core board nue) et un microampèremètre en série avec l'alimentation 3,3 V
- RTC alimentée en continu : source IRC40K interne (aucun quartz requis) ou LXTAL 32,768 kHz si peuplé ; VBAT 1,8-3,6 V possible sur pile bouton
- LED PC13 (active-LOW) pour visualiser les réveils ; console USART0 pour les messages
- SPL V2.2.x + OpenOCD compatible GD32
Code complet
/* stop_rtc.c — GD32F103C8, SPL V2.2.x : Stop + réveil RTC chaque seconde. */
#include "gd32f10x.h"
static bool led_on = false;
void RTC_IRQHandler(void)
{
if (rtc_flag_get(RTC_FLAG_SECOND) == SET) {
rtc_flag_clear(RTC_FLAG_SECOND);
led_on = !led_on; /* la LED ne clignote qu'aux reveils */
gpio_bit_write(GPIOC, GPIO_PIN_13, led_on ? RESET : SET);
}
}
static void rtc_source_irc40k(void)
{
/* 1) source RTC = IRC40K interne (pas de quartz externe requis) */
rcu_osci_on(RCU_IRC40K);
rcu_osci_stab_wait(RCU_IRC40K);
rcu_rtc_clock_config(RCU_RTCSRC_IRC40K);
/* 2) horloge de la RTC et de la interface backup */
rcu_periph_clock_enable(RCU_PMU);
rcu_periph_clock_enable(RCU_BKPI);
pmu_backup_write_enable;
/* 3) RTC : prescaler 32768 -> 1 Hz, interruption « seconde » */
rtc_init;
rtc_interrupt_enable(RTC_INT_SECOND);
rtc_enable;
while (rtc_flag_get(RTC_FLAG_INITS) != SET) { } /* sync. registres */
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
nvic_irq_enable(RTC_IRQn, 1, 0);
}
int main(void)
{
rcu_periph_clock_enable(RCU_GPIOC);
gpio_init(GPIOC, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13);
rtc_source_irc40k;
while (1) {
/* Entree en Stop : WFI, le réveil se fait par l'IRQ RTC.
En Stop, le système repart sur IRC8M (8 MHz) au réveil :
reconfigurer le PLL 108 MHz si le code en a besoin. */
pmu_to_deepsleepmode(PMU_LDO_LOWPOWER, WFI_CMD, STOP_MODE_ENTRY);
/* ... ici, on revient a chaque seconde ... */
}
}
Vérification attendue
La LED PC13 pulse une fois par seconde (chaque réveil RTC), et le microampèremètre chute fortement pendant les phases de Stop par rapport au mode run (à l'échelle de la centaine de µA contre 34-45 mA en run à 108 MHz d'après la datasheet ; le plancher standby est d'environ 5,6-5,8 µA RTC active). En mode débogage SWD, la connexion peut tomber pendant le Stop : c'est normal, reprenez la main juste après un réveil.
Erreurs fréquentes
- Aucun réveil : interruption RTC activée mais NVIC RTC_IRQn oublié, ou drapeau SECOND non effacé dans le handler (le réveil ne se produit alors qu'une fois).
- Le programme ne repart pas à la bonne vitesse : après Stop, l'horloge système revient sur IRC8M ; tout code calibré sur 108 MHz (delais, UART) dérive tant que le PLL n'est pas relancé.
- RTC qui ne compte plus après extinction : sans maintien (VBAT ou alimentation continue), la RTC repart à zéro ; l'IRC40K interne est moins précis qu'un LXTAL 32,768 kHz.
- Confondre Stop et Standby : en Standby, la SRAM est perdue (réinitialisation complète au réveil, consommation minimale ~5,6 µA) ; en Stop, la SRAM est conservée mais le solde est plus élevé.
- Régulateur et LED de la carte : sur une Blue Pill complète, le régulateur et la LED consomment plus que le MCU en Stop ; vos mesures µA seront dominées par la carte, pas la puce.
- Réveil intempestif : une broche flottante sur une ligne de wake-up peut réveiller le cœur ; mettez les entrées inutilisées en pull défini.
Autres tutoriels pour cette carte
Exemples de code pour cette carte
clignotante.inoArduinobouton-led.inoArduinorespiration.inoArduinopotentiometre.inoArduinopont-uart.inoArduinooled-i2c.inoArduino