RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; GPIOC->CRH |= GPIO_CRH_MODE13_1; GPIOC->BSRR = GPIO_BSRR_BS13;La manipulation de bits en C est un pré-requis qui ne sera pas traité.
Les ressources concernant la programmation d'une carte Blue Pill ne manquent pas (la puce animant cette carte datant de 2007) et c'est plus pour mettre mes idées au clair que je partage mon expérience de ce monde fabuleux qu'est l'embarqué. A l'heure de l'informatique nuagique, des stockages toujours plus volumineux, des vitesses toujours plus rapides, il est utile de parfois prendre son temps et de revenir à quelque chose de plus "physique" (et abordable (financièrement)).
Pour appréhender une carte, l'exercice de base consiste à faire clignoter une LED (ce qui est d'autant plus facile lorsque ladite LED est intégrée à la carte). Mais avant de songer à la faire clignoter, il serait utile de savoir comment l'allumer ou l'éteindre. Une fois le schéma de la carte sous les yeux (rechercher "stm32f103 schematic bluepill"):
on peut constater pourquoi la LED verte (D2) est allumée par défaut: on part de l'alimentation (VCC3V3), puis la LED, sa résistance (R5) et enfin la broche PC13. Cette broche est inactive par défaut (donc reliée à la masse), le courant circule, la LED s'allume. Passer cette broche à l'état actif va la relier à l'alimentation, le courant ne circule plus, la LED s'éteint.
La LED rouge D1 étant directement connectée à la masse (GND) elle est allumée en permanence.
Les broches (ou PINs à partir de maintenant) d'un micro-contrôleur sont référencées par un nombre et regroupées dans des PORTs (aussi appelés GPIOs) nommés par une lettre. Les PORTs vont de 'A' à 'G' (sur une Blue Pill seuls les PORTs A, B et C sont disponibles) et les PINs vont de 0 à 15. La LED est reliée à la 13ème PIN du PORT C et cette PIN est notée "PC13" (la 6ème PIN du PORT B est notée "PB6", la 10ème du GPIO A "PA10", etc). Le code suivant passe PC13 à l'état haut/actif et éteint la LED:
1 #include "stm32f1xx.h" 2 3 int 4 main (void) { 5 RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; 6 GPIOC->CRH |= GPIO_CRH_MODE13_1; 7 GPIOC->BSRR = GPIO_BSRR_BS13; 8 return 0; 9 }On distingue assez facilement:
où l'on peut voir que:
RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;se compose des expressions:
RCC->APB1ENR |= RCC_APB1ENR_I2C2EN;où APB1ENR correspond à APB1 ENable Register (page 115) et I2C2EN à I2C2 ENable (page 116). Toutes les expressions du code proviennent du fichier d'entête "stm32f1xx.h" qui va, par le jeu de définition de macros, finir par inclure "stm32f103xb.h". Ce fichier décrit tous les composants, leurs registres et les principales valeurs à utiliser pour notre carte (pour plus de détails: compilation et chargement de la carte). La deuxième ligne de code :
GPIOC->CRH |= GPIO_CRH_MODE13_1;se traduit par: "dans le registre de configuration supérieur (Configuration Register High, page 172) du composant GPIO C passer à 1 le bit numéro 1 des bits du mode de la PIN 13 (GPIO_CRH_MODE13_1)". Pour activer les bits numéro 0 et 1 des bits du mode de la PIN 6 du PORT B (page 171) on écrira:
GPIOB->CRL |= GPIO_CRL_MODE6_0 | GPIO_CRL_MODE6_1;Petite subtilité: les PINs 0 à 7 sont contrôlées par le registre Configuration Register Low, les PINs de 8 à 15 par le CRH déjà vu. Une PIN ayant un mode et une configuration, pour activer par exemple le bit numéro 0 des bits de configuration de la PIN 10 du GPIOA:
GPIOA->CRH |= GPIO_CRH_CNF10_0;Reste la dernière ligne de code:
GPIOC->BSRR = GPIO_BSRR_BS13;"dans le registre Bit Set Reset Register (page 173) du composant GPIO C passer à 1 le bit qui active la PIN 13".
GPIOB->BRR = GPIO_BRR_BR6;On peut maintenant commenter le code initial:
1 #include "stm32f1xx.h" 2 3 int 4 main (void) { 5 // Passe à 1 le bit numéro 4 du registre APB2 == activation du GPIO C 6 RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; 7 8 // mode de la PIN 13 de GPIO C à 0b10 == Output mode, max speed 2 MHz 9 GPIOC->CRH |= GPIO_CRH_MODE13_1; 10 11 // Passe à 1 le bit numéro 13 du registre BSRR du GPIO C == passage à l'étact haut/actif de la PIN 13 du GPIO C 12 GPIOC->BSRR = GPIO_BSRR_BS13; 13 14 // La LED est désormais éteinte 15 return 0; 16 }qui est une version que je considère plus lisible (bien que trop commentée) mais bien moins courante que
1 #include "stm32f1xx.h" 2 3 int 4 main (void) { 5 RCC->APB2ENR |= (1 << 4); 6 GPIOC->CRH |= (1 << 23); 7 GPIOC->BSRR = (1 << 13); 8 return 0; 9 }où les valeurs utilisées ne sont pas particulièrement intuitives. Comme je commence à devenir bilingue en STM32, je vais tenter de respecter ce style de code:
1 #include "stm32f1xx.h" 2 3 int 4 main (void) { 5 RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; // Enable GPIOC 6 GPIOC->CRH |= GPIO_CRH_MODE13_1; // GPIOC PIN 13 mode 0b10: Output mode, max speed 2 MHz 7 GPIOC->BSRR = GPIO_BSRR_BS13; // GPIOC PIN 13 state high 8 9 // LED is off 10 return 0; 11 }Le code complet: https://gitlab.com/dsx/blue-pill/-/tree/master/stm32f103c8t6/00_gpio Reste à compiler et charger le code dans la carte ou passer directement à la LED qui clignote (ou compter le temps qui passe).
RCC->BRIENR |= RCC_BRIENR_COMPEN;Un composant possède un (ou plusieurs) Configuration Register.