Cours 4
Cours 4
Cours 4
Matthias Puech
1 / 23
La librairie HAL
2 / 23
La librairie HAL
3 / 23
Présentation de HAL
4 / 23
Présentation de HAL
Organisation du code
• dans lib/HAL/
• paire de fichiers .h et .c pour chaque périphérique
(ex : stm32f3xx_hal_gpio.{c,h})
• structures de données dans les .h
• fonctions et documentation dans les .c
4 / 23
HAL Configuration des GPIOs
lib/HAL/stm32f3xx_hal_gpio.{c,h}
1. on déclare une structure GPIO_InitTypeDef
2. on remplit ses champs
Pin les pins à configurer (ORées) :
GPIO_PIN_0 . . . GPIO_PIN_15
Mode un des 4 modes pré-cités, et plus :
GPIO_MODE_INPUT, GPIO_MODE_OUTPUT_PP,
GPIO_MODE_AF_PP. . .
Pull GPIO_NOPULL, GPIO_PULLUP,
GPIO_PULLDOWN
Speed GPIO_SPEED_FREQ_LOW . . .
GPIO_SPEED_FREQ_HIGH
Alternate si Mode == GPIO_MODE_AF_*, determine la
fonction alternative à connecter.
3. on la passe à la fonction HAL_GPIO_Init() avec le port à
configurer (GPIOA, GPIOB. . .)
5 / 23
HAL Configuration des GPIOs
lib/HAL/stm32f3xx_hal_gpio_ex.h
5 / 23
HAL Utilisation des GPIOs
Remarque
On peut agir sur plusieurs pins à la fois avec des OR
6 / 23
HAL Configuration des horloges de périphérique
lib/HAL/stm32f3xx_hal_rcc.h
7 / 23
Exemple
int main()
{
/* LEDs initialization */
RCC->AHBENR |= (1 << 21); /* enable GPIO E clock */
GPIOE->MODER |= 0x55550000; /* conf E8-E15 as output */
while(1) {
GPIOE->ODR ^= 0x0000FF00; /* invert pin 8-15 */
delay();
}
}
8 / 23
Exemple
int main() {
__HAL_RCC_GPIOE_CLK_ENABLE();
GPIO_InitTypeDef gpio_init;
gpio_init.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10
| GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13
| GPIO_PIN_14 | GPIO_PIN_15;
gpio_init.Mode = GPIO_MODE_OUTPUT_PP;
gpio_init.Pull = GPIO_PULLUP;
gpio_init.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOE, &gpio_init);
while (1) {
HAL_GPIO_TogglePin(GPIOE, gpio_init.Pin);
delay();
}
}
8 / 23
La librairie HAL
9 / 23
Taxonomie des protocoles de communication
Protocole langage de communication machine ↔ machine.
(les parties)
Support du protocole
• couche physique (ex : Ethernet/PHY, RS232)
• superposé à un autre protocole (ex : IP)
10 / 23
Taxonomie des protocoles de communication
Synchrone/Asynchrone
synchrone notion de temps commune à toutes les parties
(horloge partagée, ex : USART, JTAG, I2 C)
asynchrone temps relatif à chaque partie (ex : UART)
Duplex
simplex émetteur → destinataire (ex : radio)
half-duplex “à l’alternat” (ex : talkie-walkie, JTAG)
à un instant donné, partie 1 → partie 2 ou
partie 2 → partie 1
full-duplex “bidirectionnel” (ex : UART)
partie 1 → partie 2 et partie 2 → partie 1
en même temps
10 / 23
Taxonomie des protocoles de communication
Symétrie
client-serveur partie principale (serveur) qui répond aux requêtes
des autres (ex : HTTP) ou qui initie la
communication (ex : I2 C)
distribué chaque partie a le même rôle dans la communication
(ex : BitTorrent, CAN)
Modalité
série les informations se succèdent sur une seule voie de
communication (“une ligne”, ex : UART, USB)
parallèle les informations sont transmisent en même temps sur
pluseurs voies (“plusieurs lignes” ; ex : CPU↔RAM)
10 / 23
Taxonomie des protocoles de communication
Topologie
point-à-point 2 parties seulement (ex : UART, PPP)
étoile un “hub” central connecté à toutes les parties
(ex : routeur sur un LAN)
daisy-chain n parties en chaîne, chacun fait passer le message au
suivant jusqu’au destinataire
(ex : SCSI, MIDI)
bus n parties, toutes connectées sur un seul “câble”
(ex : CAN, PCI, les bus internes au STM32)
...
10 / 23
Piles de protocoles
Un “protocole” n’est qu’une vue de l’esprit, un moyen de
comprendre une communication donnée.
Il n’apparaît que rarement isolé, mais repose sur d’autres
protocoles plus élémentaires pile de protocoles
Exemple
Le modèle OSI :
11 / 23
UART
É point-à-point
É asynchrone
É série
12 / 23
Description du protocole UART
• deux lignes : RX (réception) et TX (transmission)
(à brancher sur TX et RX de l’autre côté)
• pas d’horloge commune, mais une vitesse de transmission
convenue des deux côtés, multiple de 9600 Hz (a.k.a. Baud).
(appelons T la période d’horloge)
• pour chaque ligne RX et TX :
É niveau haut au repos
É bas pendant 1, 5T début de trame
É puis chaque n bits tous les T
(par défaut LSB : bits de poids faibles d’abord)
É haut pendant 1, 5T fin de trame
(en fait, temps configurable : 0.5, 1, 1.5 ou 2T)
Description du protocole UART
Addendum
Il existe une trame spéciale, qui peut être reçue/envoyée :
• Break : trame de 0
(utilisé pour indiquer un “temps mort” dans l’émission)
13 / 23
Description du protocole UART
Addendum
Il existe une trame spéciale, qui peut être reçue/envoyée :
• Break : trame de 0
(utilisé pour indiquer un “temps mort” dans l’émission)
Solutions
sur-échantillonnage le receveur échantillonne le signal entrant
tous les T/n pour connaître sa phase
correction d’erreur un bit supplémentaire de parité est transmis
ajout d’une ligne d’horloge commune USART
13 / 23
Extensions du protocole UART
USART
On rend le protocole synchrone en ajoutant une ligne d’horloge,
contrôlé par une des parties
Extensions du protocole UART
Correction d’erreur
• on ajoute 1 bit B[n] à chaque trame
Pn−1
• B[n] = i=0 B[i] mod 2
• À réception, si B[n] n’a pas cette valeur, la trame est erronée.
• Si B[n] a la bonne valeur. . . nombre pair d’erreurs !
(mais la probabilité de 2 erreurs est faible)
nécessité d’un protocole superposé d’acquittement
(parfois, le receveur va accuser réception ou demander le renvoi)
14 / 23
RS232
Une couche physique pour U(S)ART :
• standardise les voltages
• le connecteur et le brochage (pinout)
Autre exemple
Pont USB/USART (FT232RL / Virtual COM Port) 15 / 23
Sur notre carte
Deux options :
• coder le protocole nous même :
É utiliser les GPIOs pour mettre deux pins on/off
É implémenter l’attente de 1/9600 par une boucle
É implémenter fonctions transmit(char c) et char
receive() en suivant le protocole.
16 / 23
Sur notre carte
Deux options :
• coder le protocole nous même :
É utiliser les GPIOs pour mettre deux pins on/off
É implémenter l’attente de 1/9600 par une boucle
É implémenter fonctions transmit(char c) et char
receive() en suivant le protocole.
• utiliser un des périphériques UART embarqué sur le MCU :
+ protocole implémenté en hardware
+ le processeur est déchargé du travail de transmission
(contrôle d’erreur, )
+ on communique avec par lecture/écriture dans des registres
(comme d’habitude)
– le périphérique est relié à des pins prédéfinies
(voir specsheet)
16 / 23
Sur notre carte
3 périphériques USART
(USART1..3)
2 périphériques UART (UART4,5)
USART1
connecté à PA4/PA5
connecté à RX/TX
connecté au ST-Link
transmis à travers l’USB
(port COM virtuel)
communication facilitée
entre ordinateur et MCU
16 / 23
HAL Configuration des USARTs
lib/HAL/stm32f3xx_hal_usart.{c,h}
Périphériques USART1. . .3
Chacun a une dizaine de registres
On va les manipuler à haut niveau, grâce à HAL :
• on consulte la datasheet pour savoir à quelle pins
correspondent les E/S
• on configure le GPIO des pins correspondantes : Alternate
Function USARTn.
• on déclare et remplit une handle USART_HandleTypeDef :
É Instance = USART1. . .3
lib/HAL/stm32f3xx_hal_usart.{c,h}
Handle
Structure qui contient l’état et la configuration actuelle du
périphérique, à passer avec toute communication. (ex : instance,
taille de dernière donnée reçue. . .)
18 / 23
HAL Utilisation des USARTs
lib/HAL/stm32f3xx_hal_usart.{c,h}
Handle
Structure qui contient l’état et la configuration actuelle du
périphérique, à passer avec toute communication. (ex : instance,
taille de dernière donnée reçue. . .)
API synchrone/blocante
Prennent en argument le handle, la donnée, sa taille, et un timeout.
HAL_USART_Transmit() demande au périphérique d’envoyer un
tableau d’octets, et boucle jusqu’à ce que ce soit fait.
HAL_USART_Receive() boucle et surveille le périphérique
jusqu’à ce qu’un message y soit reçu ; copie ce
message dans un tableau.
18 / 23
Problème de l’API synchrone
Exemple
int data;
while(1) {
HAL_USART_Receive(&UsartHandle, &data, 4, 100);
data = LongComputation(data);
HAL_USART_Transmit(&UsartHandle, &data, 4, 100);
blink();
}
Problèmes
• requêtes potentiellement perdues
• tâche “parallèle” impossible
19 / 23
Problème de l’API synchrone
Exemple
int data;
while(1) {
HAL_USART_Receive(&UsartHandle, &data, 4, 100);
data = LongComputation(data);
HAL_USART_Transmit(&UsartHandle, &data, 4, 100);
blink();
}
Problèmes
• requêtes potentiellement perdues
• tâche “parallèle” impossible
interruptions
19 / 23
La librairie HAL
20 / 23
Les périphériques U(S)ART
21 / 23
Les périphériques U(S)ART
21 / 23
Les périphériques U(S)ART
Pour recevoir des trames
1. configurer CR1,2,3 et BRR
(suivant les caractéristiques de la ligne)
2. mettre le bit RE de CR1 à 1
(receiver enable, active l’écoute d’une condition start)
3. attendre que RXNE soit à 1
(données reçues, disponibles dans RDR)
4. lire les N bits reçus dans RDR
5. RXNE se met à 0
(en attente du prochain message)
6. s’il reste des trames à recevoir, GOTO 3.
7. si données arrivent quand RXNE est à 1, on a un overrun
(on n’a pas lu les données assez vite)
22 / 23
Addendum Utiliser scanf() et printf()
23 / 23
Addendum Utiliser scanf() et printf()
23 / 23
Addendum Utiliser scanf() et printf()
Comment faire
• rajouter l’option –specs=nosys.specs aux ARCHFLAGS
(force gcc à ne pas include de libC)
• définir les fonctions de bas niveau (“appels système”)
int _read(int file, char *data, int len)
int _write(int file, char *data, int len)
int file le descripteur de fichier
(ne pas prendre en compte cet argument)
char *data les caractères à lire/écrire
int len le nombre de caractères à lire/écrire
valeur de retour le nombre de caractères effectivement
lus/écrits
23 / 23