CHAPITRE-I STM32
Programmation du GPIO par
adressage direct des registres
1
PLAN
■ Objectifs du cours
■ Description des GPIOS
■ Adresses des registres du GPIO
■ Activation des horloges des périphériques
■ Programmation en C des GPIOS
■ Utilisation des registres de la bibliothéque
2
Objectifs
■ Utiliser le C embarqué pour:
– Définir les registres relatifs au GPIO par un code en langage C
– Adresser les différents registres
– Manipuler entièrement ou par bits les registres
– Programmer les registres de STM32 par adressage de ses registres
en se référant au plan mémoire (Memory Map)
– Utiliser les registres des bibliothèques et interpréter les différences
Plateforme embarquée à utiliser:
STM32 F4Discovery
4
Architecture de l’STM32
§ Architecture de type RISC (Reduced Instructions Set Computer) à Bus des Instructions et bus
des Données sont séparés -> Architecture Harvard.
§ CPU CortexM4 fait le calcul à la cadence du Bus (AHB: ARM Hi-Speed Bus).
§ Les périphériques, moins rapides, sont montés sur les Bus APB1 et APB2.
§ Dans le cas d’un tansfert DMA (Direct Memory Acces) c-à-d d’une adresse mémoire ou d’une
périphérique vers une autre, le DMA devient le maître du bus AHB.
I-bus
Flash I/F
D-bus FLASH
CORTEX-M4
Master 1
System
BusMatrix
SRAM
Slave
APB2
Peripheral Bus APB2
AHB AHB-APB2
GP-DMA
Master 2 APB1
AHB-APB1
Peripheral Bus APB1
Arbiter Bridges
5
Architecture détaillée d’un STM32 F40x
CORTEXTM-M4 CPU
24 MHz Power Supply
Flash I/F
256KB-512kB
Reg 1.8V
Flash Memory
POR/PDR/PVD
24KB-32kB SRAM XTAL oscillators
ARM ® Lite Hi-Speed 36us
Matrix / Arbiter (max 24MHz)
32KHz + 4~25MHz
JTAG/SW Debug 84B Backup Data
Int. RC oscillators
Nested vect IT Ctrl 40KHz + 8MHz
1 x Systick Timer FSMC
SRAM/ NOR/ LCD parallel interface PLL
DMA RTC / AWU
up to 12 Channels Clock Control
ARM ® Peripheral Bus
Bridge
(max 24MHz)
Bridge
1 x 16-bit PWM Synchronized AC Timer
10 x 16-bit Timer
1 x CEC
ARM® Peripheral Bus
Up to 16 Ext. ITs 2 x Watchdog
(independent & window)
(max 24MHz)
51/80/112 I/Os 4 x USART/LIN
2-channel 12-bit DAC Smartcard / IrDa
Modem Control
1 x SPI
1 x 12-bit ADC
up to 16 channels 2 x SPI
1 x USART/LIN
Smartcard/IrDa
Modem Control Temperature Sensor 2 x I2C
6
Tools and Software
■ Outils de développements
– IAR Embedded Workbench
– kEIL µVision IDE
– Raisonnance Ride7
IDE à utiliser:
– MikroC Pro for ARM
http://www.keil.com/uvision/
– CooCox (riche en exemples)
– Circle OS (couche applicative de l’OS
circleOS)
– CubeMX: Outil graphique permettant de
configurer un STM32 et générer le code
associé.
L’outil de configuration à utiliser:
http://www.st.com/en/development-
– La plupart des outils sont bâtis autour tools/stm32cubemx.html
de CMSIS - Cortex Microcontroller
Software Interface Standard:
http://www.keil.com/pack/doc/CMSIS/
General/html/index.html
7
8
■ E/S bidirectionnels de STM32
– GPIO standard (tolère une valeur de 5v en entrée) et génère une
sortie de 3v
– GPIOs délivre un courant 25mA
– Temps de montée en sorite configurable (max 100 MHz)
– Toutes les pines peuvent être programmeés comme entrée
analogique
– Toutes les pines peuvent être programmeés en fonctions alternés
(USARTx, TIMx, I2Cx, SPIx,…)
– Toute entrée pourrait être configurée comme source d’interruption
– 9 ports de GPIO standard (GPIOA..GPIOI) (1 port = 16 pines d’E/S)
9
10
Push-Pull Open-Drain
Registres de contrôle des GPIOs
■ Pour la manipulation des 9 GPIOx(x=A..I), nous avons recours à
l’utilisation des registres de contrôle suivants:
– GPIOx_MODER : registre utilisé pour sélectionner la direction (Entrée
ou Sortie), Fonction alternée et analogique (input, output, AF, analog)
– GPIOx_OTYPER : Registre utilisé pour sélectionner le type de sortie
PP(pushpull ) ou OD (open-drain)
– GPIOx_OSPEEDR : Registre utilisé pour sélectionner la vitesse quelque
soit la direction I/O
– GPIOx_PUPDR : Registre utilisé pour la sélection du mode PU ou PD (
pull-up/pull-down) quelque soit la direction I/O
14
GPIO port mode register (GPIOx_MODER) (x = A..I)
GPIO port output type register (GPIOx_OTYPER) (x = A..I)
GPIO port output speed register (GPIOx_OSPEEDR)
GPIO port pull-up/pull-down register (GPIOx_PUPDR)
Address offset: 0x0C
Registres des données
– GPIOx_IDR (x=A..I): récupérer les données entrantes du
port x, accédé en lecture seule
– GPIOx_ODR (x=A..I): envoyer les données en sorties du
port x, accédé en écriture et en lecture
Rq: Il existe d’autres registres GPIO non traités dans ce
chapitre
19
GPIO port input data register (GPIOx_IDR) (x = A..I)
GPIO port output data register (GPIOx_ODR) (x = A..I)
Registres des données
– GPIOx_IDR (x=A..I): récupérer les données entrantes du
port x, accédé en lecture seule
– GPIOx_ODR (x=A..I): envoyer les données en sorties du
port x, accédé en écriture et en lecture
Rq: Il existe d’autres registres GPIO non traités dans ce
chapitre
22
Les Autres Registres GPIO
q GPIO port bit set/reset register
§ (GPIOx_BSRR) (x = A..I)
q GPIO port configuration lock register
§(GPIOx_LCKR) (x = A..I)
q GPIO alternate function low register
§(GPIOx_AFRL) (x = A..I)
qGPIO alternate function high register
§(GPIOx_AFRH) (x = A..I)
23
CALCUL DES
ADRESSES DES
REGISTRES DU GPIO
L’adresse d’un registre d’un périphérique donnée est la somme de:
q l’adresse de base d’un périphérique
q l’adresse d’offset du registre
l’adresse de base d’un périphérique est définie dans le memory map (Table 10
page 71 de la datasheet STM32F40x)
Les adresses d’offset des registres sont définies dans la description des registres
du RM (Table 32 pages 203/204 du fichier « Reference Manual » de STM32F40x)
Remarque: Les adresses de base des GPIOs et d’offset des principaux registres
sont présentées par la suite
Memory MAP:
Table 10 page 71 de la datasheet STM32F40x
Adresses de base des PORTS
d’E/S (GPIOs)
@ d’offset des registres GPIOs
Table 32 pages 203/204 du « Reference Manual » de
STM32F40x
Suite …
Suite …
Exemples de calcul des adresses
Calculer les adresses des registres suivants:
?
• GPIOC_ODR
• GPIOA_AFRH
• GPIOB_PUPDR
30
Exemples de calcul des adresses
Calculer les adresses des registres suivants:
GPIOC_ODR = GPIOC_BASE + OFSET_ODR
= 0x4002 0800 + 0x14
= 0x4002 0814
GPIOA_AFRH = GPIOA_BASE + PFSET_AFRH
= 0x4002 0000 + 0x24 = 0x4002 0024
GPIOH_PUPDR = 0x4002 1C00 + 0x0C
= 0x4002 1C0C
31
ACTIVATION DE
L’HORLOGE D’UN
GPIO
32
RCC ( Reset Clock Control) est le contrôleur de la circuiterie de Reset est
d’horloge.
Permet de synchroniser les trois bus du Cortex-M4 (AHB, APB1 et APB2) avec le
bus interne du système le bus matrix
Les GPIOs sont montés sur le bus AHB1. Tout GPIO(composant en général) doit
être activé par RCC avant utilisation.
L’avantage de RCC est la possibilité d’activer, suivant le besoin de l’application, les
composants nécessaires à l’application.
En conséquent, une meilleure gestion de la consommation du système
embarqué.
33
RCC AHB1 peripheral clock enable register
(RCC_AHB1ENR)
RCC AHB1 peripheral clock enable register (RCC_AHB1ENR)
@ RCC_AHB1ENR = @base_RCC + @offset AHB1ENR
= 0x4002 3800 + 0x30
= 0x4002 3830
RCC AHB1 peripheral reset register (RCC_AHB1RSTR)
§@ RCC_AHB1RSTR = @base_RCC + @offset AHB1RSTR
§ = 0x4002 3800 + 0x10 = 0x4002 3810
§Ce registre permet de remettre à l’état initial le périphérique à
utiliser par une écriture de 1.
§Suite à cette écriture de 1, il faut écrire 0 pour que le
périphérique sorte de son état de reset.
EXEMPLE DE Clignotement de
PROGRAMMATION la LED
connectée au
D’UN GPIO PD12
36
Applications: 4 Leds et Bouton utilisateurs de
STM32f4Discovery
37
Principe de programmation des registres (1/5)
Un programme C qui utilise uniquement les registres d’une périphérique pourrait
être vu comme étant une fonction de registres mis en jeu.
PROG = f(registres)
La programmation dans ce cas consiste à :
§ ETAPE 1: Définir les registres à utiliser: chaque registre est équivalent à une
adresse donc un pointeur en langage C
§ ETAPE 2: Initialiser ces pointeurs par les adresses adéquates
§ ETAPE 3: Lecture et/ou écriture des contenus des registres
- Lecture: lire l’état du système
- Ecriture: commander le système
Principe de programmation des registres (2/5)
ETAPE 1: Définir les adresses des registres
Les périphériques à utiliser dans notre cas sont :
qRCC (Reset and Clock Control): pour l’activation de l’horloge
- Les registres à utiliser de l’RCC est RCC_AHB1ENR + RCC_AHB1RSTR
qGPIOD: pour commander la pine PD12 connectée au LED4
- Les registres à utiliser du périphérique GPIOD sont MODREG , DOTYPE , DSPEED,
PUPPDR et ODR (de même pour les autres)
RCC adresse de base: GPIOD adresse de base:
0x4002 3800 @ 0x4002 0C00
AHB1ENR: AHB1RSTR: MODREG : @offset= 0x00
@offset= 0x30 @offset= 0x10
ODR: @offset= 0x14
@ AHB1RSTR = 0x40023810 @ DMODREG = 0x40020C00
@ AHB1ENR = 0x40023830
@DODR= 0x40020C14
Principe de programmation des registres (3/5)
ETAPE 2: définir des pointeurs et les initialiser
Définition et initialisation des pointeurs des registres
volatile unsigned int* DMODER = (unsigned int *) 0x40020C00;
volatile unsigned int * DOTYPER = (unsigned int *) 0x40020C04;
volatile unsigned int * DSPEEDR = (unsigned int *) 0x40020C08;
volatile unsigned int * DODR = (unsigned int *) 0x40020C14;
volatile unsigned int * DPUPDR = (unsigned int *) 0x40020C0C;
//RCC_AHB1ENR
volatile unsigned int * AHB1_ENR =(unsigned int*) 0x40023830;
//RCC_AHB1ENR
volatile unsigned int * AHB1_RSTR =(unsigned int*) 0x40023810;
Remarque: volatile neutralise l’effet de l’optimisation (taille du code + Speed)
sur les variables déclarées. Ici les @ des registres.
Principe de programmation des registres (4/5)
ETAPE 3: Lecture/écriture dans les registres
Réinitialiser le GPIOD Mettre le Bit3 de AHB1_RSTR à 1 puis 0
Activer l’horloge de GPIOD Mettre le Bit3 de AHB1_ENR à 1
Configurer les PD12 en mode General Purpose Output Push Pull
(GP Output 50 Mhz):
Bits [25-24] Bit [12] =0 Bits [25-24] Bits [25-24]
=01 =10=50Mhz =01
Principe de programmation des registres (4/5)
ETAPE 3: Lecture/écriture dans les registres (suite …)
int main() {
// SET GPIOD DENIT …..
*AHB1_RSTR |= 1<<3; ….
// RESET GPIOD DENIT ….
*AHB1_RSTR &= ~(1<<3); …..
…..
// Enable GPIOD Clock …..
*AHB1_ENR |= 1<<3;
// SPEED = 50 Mhz bits 25-24 = 0-1
// Configuration MODREG *DSPEEDR &= 0xFCFFFFFF;
// bits 25-24 = 01 *DSPEEDR |= 0x01000000;
*DMODER &= 0xFCFFFFFF;
* DMODER |= 0x01000000; // Bits 25-24 = 00
// Bit 12 = 0 *DPUPDR &= 0xFCFFFFFF;
*DOTYPER &= ~(1<<12);
Principe de programmation des registres (5/5)
ETAPE 3 suite: Lecture/écriture dans les registres
Activer l’état de la sortie PD12 :
Mettre le bit 12 à 1 dans le registre DODR Ecriture dans le
registre DODR
Insérrer un delay en utilisant la boucle for
Désactiver l’état de la sortie PD12 :
Mettre le bit 12 à 0 dans le registre EODR Ecriture dans le
registre DODR
Insérrer un delay en utilisant la boucle for
Principe de programmation des registres (5/5)
ETAPE 3: Lecture/écriture dans les
registres (suite …)
while(1){
*DODR |= 1<<12;
tempo(0xffffff);
*DODR &= ~(1<<12);
tempo(0xffffff);
}
Code complet de l’application (1/2)
volatile unsigned int * MODREG = (unsigned int *) 0x40020C00;
volatile unsigned int * DOTYPE = (unsigned int *) 0x40020C04;
volatile unsigned int * DSPEED = (unsigned int *) 0x40020C08;
volatile unsigned int * DODR = (unsigned int *) 0x40020C14;
volatile unsigned int * PUPPDR = (unsigned int *) 0x40020C0C;
volatile unsigned int * AHB1_ENR=(unsigned int *) 0x40023830;
volatile unsigned int * AHB1_RSTR=(unsigned int*) 0x40023810;
void tempo(volatile unsigned int CNT)
{
for(; CNT > 0 ;CNT --);
}
Code Complet de l’application (2/2)
int main() { // SPEED = 50 Mhz bits 25-24 = 0-1
// SET GPIOD DENIT *DSPEED &= 0xFCFFFFFF;
*AHB1_RSTR |= 1<<3; *DSPEED |= 0x01000000;
// RESET GPIOD DENIT // Bits 25-24 = 00
*AHB1_RSTR &= ~(1<<3); *PUPPDR &= 0xFCFFFFFF;
// Enable GPIOD Clock while(1)
*AHB1_ENR |= 1<<3; {
// Configuration MODREG *DODR |= 1<<12;
// bits 25-24 = 01 tempo(0xffffff);
*MODREG &= 0xFCFFFFFF; *DODR &= ~(1<<12);
*MODREG |= 0x01000000; tempo(0xffffff);
// Bit 12 = 0 }
*DOTYPE &= ~(1<<12); }
Clignotez les 4 LEDS en même
temps? ?
47
Défiler les 4 leds ?
48
Utiliser le bouton USER pour
inverser les leds deux à deux à
chaque appui ?
49
DÉFINITION DES REGISTRES
DANS LA BIBLIOTHÈQUE DE
STM32
CMSIS
50
Interprétation des macros dans STM32F407xx.h
#define PERIPH_BASE 0x40000000U
#define AHB1PERIPH_BASE (PERIPH_BASE + 0x00020000U)
#define GPIOD_BASE (AHB1PERIPH_BASE + 0x0C00U)
#define GPIOD ((GPIO_TypeDef *) GPIOD_BASE)
§ AHB1PERIPH_BASE sera remplacé par 0x40000000U + 0x00020000U = 0x40020000U. Le
suffixe U est utilisé pour forcer le compilateur à utiliser le type Unsigned int pour une constante.
§ GPIOD_BASE sera alors remplacé par 0x40020000U + 0x0C00U = 0x40020C00U
§ GPIOD par 0x40020C00U. Cette valeur sera convertie en une adresse sur GPIO_TypeDef:
#define GPIOD (GPIO_TypeDef *) 0x40020C00U
GPIOD: 0xX…XX…..X 0x40020C00U
…. …..
typedef struct {
__IO uint32_t MODER; /* Address offset: 0x00 */
0x40020C00U MODER
__IO uint32_t OTYPER; /* Address offset: 0x04 */
+0x04 OTYPER __IO uint32_t OSPEEDR; / Address offset: 0x08 */
En Mémoire __IO uint32_t PUPDR; /* Address offset: 0x0C */
+0x08 OSPEEDR __IO uint32_t IDR; /* Address offset: 0x10 */
__IO uint32_t ODR; /* Address offset: 0x14 */
+0x0C PUPDR __IO uint32_t BSRR; /* Address offset: 0x18 */
……
+0x10 IDR
} GPIO_TypeDef;
+0x10 ODR
+0x14
#define __IO volatile
BSRR 51
Suite ….
§Chaque case est 32 bits (4 octets) d’où les offsets 0x04, 0x08 … 0x18.
§Les adresses des registres étudiés en première partie sont alors vérifiées.
§GPIOD est un pointeur sur la structure GPIO_TypeDef.
§L’accès au champ IDR (ou autre) de la structure se fait comme suit:
(*GPIOD).IDR ou encore GPIOD->IDR en utilisant l’écriture simplifiée.
0xX…XX…..XXX 0x40020C00U GPIOD: une case mémoire quelconque
…. …..
typedef struct {
__IO uint32_t MODER; /* Address offset: 0x00 */
0x40020C00U MODER
__IO uint32_t OTYPER; /* Address offset: 0x04 */
+0x04 OTYPER __IO uint32_t OSPEEDR; / Address offset: 0x08 */
__IO uint32_t PUPDR; /* Address offset: 0x0C */
+0x08 OSPEEDR __IO uint32_t IDR; /* Address offset: 0x10 */
__IO uint32_t ODR; /* Address offset: 0x14 */
+0x0C PUPDR __IO uint32_t BSRR; /* Address offset: 0x18 */
……
+0x10 IDR
} GPIO_TypeDef;
+0x10 ODR
+0x14 BSRR #define __IO volatile
52
Principe de Programmation
volatile unsigned int * DIDR = 0x40020C10U
■ Sans Bibliothèque
if ((*DIDR & 0xFFFF) == 0x0000)
…
■ Avec Bibliothèque
#include "STM32F407xx.h"
if (GPIOD->IDR & 0xFFFF) ==
0x0000) …
53
Exemple
■ Modifier l’exemple de la première partie:
Clignoter la diode LED connectée à PD12 en
utilisant les registres prédéfinis dans CMSIS en
modifiant l’exercice ci-dessous?
54
Compléter ?
int main() { // SPEED = 50 Mhz bits 25-24 = 0-1
// Enable GPIOD Clock *DSPEED &= 0xFCFFFFFF;
*AHB1_ENR |= 1<<3; ……………………………….
………………………………. *DSPEED |= 0x01000000;
// Configuration MODREG ……………………………….
// bits 25-24 = 01 // Bits 25-24 = 00
*MODREG &= 0xFCFFFFFF; *PUPPDR &= 0xFCFFFFFF;
………………………………. ……………………………….
*MODREG |= 0x01000000; while(1){
………………………………. *DODR |= 1<<12;
// Bit 12 = 0 ……………………………….
*DOTYPE &= ~(1<<12); tempo(0xffffff);
………………………………. *DODR &= ~(1<<12);
……………………………….
tempo(0xffffff);
}
}
55
Réponse
// SPEED = 50 Mhz bits 25-24 = 0-1
*DSPEED &= 0xFCFFFFFF;
int main() {
*DSPEED |= 0x01000000;
// Enable GPIOD Clock
……………………………….
*AHB1_ENR |= 1<<3; GPIOD->OSPEEDR &= 0xFCFFFFFF;
……………………………….
………………………………. GPIOD->OSPEEDR |= 0x01000000;
RCC->AHB1ENR |= 1<<3; //CMSIS ……………………………….
// Bits 25-24 = 00
// Configuration MODREG
*PUPPDR &= 0xFCFFFFFF;
// bits 25-24 = 01
*MODREG &= 0xFCFFFFFF; ……………………………….
GPIOD->PUPDR
………………………………. &= 0xFCFFFFFF;
……………………………….
GPIOD->MODER &= 0xFCFFFFFF; while(1){
*DODR |= 1<<12;
*MODREG |= 0x01000000;
……………………………….
……………………………….
GPIOD->MODER |= 0x01000000; GPIOD->ODR |= 1<<12;
……………………………….
tempo(0xffffff);
// Bit 12 = 0
*DODR &= ~(1<<12);
*DOTYPE &= ~(1<<12);
……………………………….
GPIOD->ODR &= ~(1<<12);
……………………………….
GPIOD->OTYPER &= ~(1<<12);
……………………………….
tempo(0xffffff);
}
}
56
Utiliser les registres prédéfinis en
bibliothèque CMSIS pour clignotez les 4
LEDS en même temps? ?
57
Utiliser les registres prédéfinis en
bibliothèque CMSIS pour défiler les 4 leds ?
58
Utiliser les registres prédéfinis en
bibliothèque et le bouton USER pour inverser
les leds deux à deux à chaque appui ?
59
Créer votre propre librairie : Mylib.c et Mylib.h
Coder les fonctions suivantes :
GPIO_ReadInputDataBit,
GPIO_ReadInputData,
GPIO_ReadOutputDataBit,
GPIO_ReadOutputData,
GPIO_SetBits,
GPIO_ResetBits,
GPIO_WriteBit,
GPIO_Write,
GPIO_ToggleBits
60