Blue Pill - GPIOs - PINs - IRQs
Table des matières
TL;DR
Mise en place d'une interruption externe.
Le matériel
En plus du montage précédent:
- un bouton
- deux résistances de 10K ohms
- un condensateur de 10µ farad
Ce bouton va permettre de basculer en mode "EMERGENCY" où seule la LED "ORANGE" clignote.
Interruption externe
Pour faire simple, il est possible de générer une interruption quand une PIN, configurée en entrée, change d'état. Appuyer sur le bouton va faire passer la PIN de l'état bas à haut (rising), relâcher le bouton fera passer la PIN de l'état haut à bas (falling). Les instructions pour mettre en place une interruption externe se trouvent page 208 paragraphe 10.2.4 Functional description du manuel de référence (RM0008):
- activer les lignes d'interruption dans le registrer IMR (Interrupt Mask Register) du composant EXTI (EXTernal Interrupt)
- activer les déclencheurs des lignes dans les registres FTSR (Falling Trigger Selection Register) et/ou RTSR (Rising ...)
- définir les gestionnaires d'interruption correspondant aux lignes d'interruption
Par soucis de simplicité, le montage précédent est modifié comme suit:
- le transistor est connecté à PA7
- le bouton est connecté à PA0
et config.h devient:
...
#define SWITCH_GPIO GPIOA
#define SWITCH_PIN 7
...
#define BUTTON_GPIO GPIOA
#define BUTTON_PIN 0
...
Le montage modifié.
Quelques petites choses à savoir avant d'envoyer le code:
- les sources d'interruptions externes se définissent dans le composant AFIO (Alternate Function Input Output)
- ce composant comprend 4 registres de configuration EXTICRx (EXTernal Interrupt Configuration Register) où "x" va de 1 à 4
- chaque registre contrôle 4 lignes d'interruption
- quand une interruption se déclenche, il faut l'acquitter (annoncer sa prise en compte) au sein de son gestionnaire, ceci pour éviter de la traiter plusieurs fois
L'extrait du config.h:
1 #define BUTTON_EXTICR_IDX (BUTTON_PIN / 4)
2 #define BUTTON_EXTICR_VAL AFIO_EXTICR1_EXTI0_PA // 1 == 1 + (BUTTON_PIN / 4), 0 == BUTTON_PIN, A == BUTTON GPIO
3 #define BUTTON_EXTI_PR EXTI_PR_PR0 // 0 == BUTTON_PIN
4 #define BUTTON_FTSR EXTI_FTSR_TR0 // F == Falling, 0 == BUTTON_PIN
5 #define BUTTON_HANDLER EXTI0_IRQHandler // cf STM32-base-master/startup/STM32F1xx/STM32F103xB.s
6 #define BUTTON_IMR EXTI_IMR_MR0 // 0 == BUTTON_PIN
7 #define BUTTON_IRQn EXTI0_IRQn // 0 == BUTTON_PIN
8
9 #define APB2_EN RCC_APB2ENR_IOPAEN | RCC_APB2ENR_AFIOEN // GPIOA + AFIO
- index du registre de configuration du composant EXTI
- valeur à utiliser dans le registre de configuration
- valeur à utiliser pour acquitter l'interruption
- l'interruption se déclenche quand la PIN passe de l'état haut à l'état bas (Falling) donc quand on relâche le bouton
- nom du gestionnaire d'interruption
- ligne d'interruption à prendre en compte
- numéro d'interruption
et pour finir on active aussi le composant AFIO. Extraits du programme principal:
...
enum STATES { INIT = 0, RED, ORANGE, GREEN, EMERGENCY };
...
gpio_pin_init(BUTTON_GPIO, BUTTON_PIN, I_PU_PD);
...
__disable_irq();
AFIO->EXTICR[BUTTON_EXTICR_IDX] = BUTTON_EXTICR_VAL;
EXTI->IMR |= BUTTON_IMR;
EXTI->FTSR |= BUTTON_FTSR;
NVIC_EnableIRQ(BUTTON_IRQn);
__enable_irq();
...
else if (state == EMERGENCY) {
SWITCH_GPIO->ODR ^= 1 << SWITCH_PIN; // toogle state
}
...
void
BUTTON_HANDLER(void) {
EXTI->PR |= BUTTON_EXTI_PR; // Reset irq
if (state == EMERGENCY) {
state = RED;
SWITCH_GPIO->BSRR = 1 << SWITCH_PIN; // PIN high SWITCH on
ORANGE_GPIO->BSRR = 1 << ORANGE_PIN; // PIN high ORANGE off
RED_GPIO->BRR = 1 << RED_PIN; // PIN low RED on
}
else {
if (state == RED) {
RED_GPIO->BSRR = 1 << RED_PIN; // PIN high RED off
}
else if (state == GREEN) {
GREEN_GPIO->BSRR = 1 << GREEN_PIN; // PIN high GREEN off
}
state = EMERGENCY;
ORANGE_GPIO->BRR = 1 << ORANGE_PIN; // PIN low ORANGE on
}
systick_irqs = 0;
}
- nouvel état "EMERGENCY"
- la PIN du bouton est en Input Pull Up / Pull Down
- mise en place de l'interruption
- nouvel état à prendre en compte
- gestionnaire d'interruption
Même si ici cela ne s'impose pas, la mise en place de l'interruption est encadrée par les fonctions __disable_irq et __enable_irq afin qu'une éventuelle autre interruption ne vienne pas interrompre le code.
Le code complet: https://gitlab.com/dsx/blue-pill/-/tree/master/stm32f103c8t6/00_gpios_ext_irq