Microcontroleur STM32F4
Cours Complet - Systemes Embarques
Chapitre 1 : Introduction aux Systemes Embarques
Architectures, definitions et concepts fondamentaux
🎯 Objectifs du chapitre
- Definir un systeme embarque et ses caracteristiques
- Comprendre les differences entre microprocesseur et microcontroleur
- Identifier les domaines d'application des systemes embarques
- Connaitre les criteres de choix d'un microcontroleur
1.1 Definition d'un Systeme Embarque
Caracteristiques principales
- Dedie : Concu pour une application specifique (contrairement a un PC generaliste)
- Autonome : Fonctionne sans intervention humaine permanente
- Temps reel : Doit repondre dans des delais determines et garantis
- Contraint : Ressources limitees (memoire, puissance, energie)
- Fiable : Fonctionnement continu et robuste requis
- Integre : Fait partie d'un systeme plus large
Exemples de systemes embarques
Automobile
ABS, airbag, injection, GPS, tableau de bord
Telephonie
Smartphones, modems, routeurs
Medical
Pacemaker, IRM, moniteurs
Aeronautique
Pilote automatique, controle moteur
Industriel
Automates, robots, capteurs
Domotique
Thermostats, alarmes, IoT
1.2 Architecture d'un Systeme Embarque
Un systeme embarque typique est compose de plusieurs elements interconnectes :
┌─────────────────────────────────────────────────────────────────────┐
│ SYSTEME EMBARQUE │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌─────────────────────────────────────────┐ │
│ │ CAPTEURS │───▶│ UNITE DE TRAITEMENT │ │
│ │ (Entrees) │ │ ┌─────────────────────────────────┐ │ │
│ │ │ │ │ MICROCONTRÔLEUR / CPU │ │ │
│ │ - Temperature│ │ │ ┌───────┐ ┌───────┐ ┌───────┐ │ │ │
│ │ - Pression │ │ │ │ CPU │ │ RAM │ │ Flash │ │ │ │
│ │ - Position │ │ │ └───────┘ └───────┘ └───────┘ │ │ │
│ │ - Lumiere │ │ │ ┌───────┐ ┌───────┐ ┌───────┐ │ │ │
│ │ - Boutons │ │ │ │ Timer │ │ ADC │ │ UART │ │ │ │
│ └──────────────┘ │ │ └───────┘ └───────┘ └───────┘ │ │ │
│ │ └─────────────────────────────────┘ │ │
│ ┌──────────────┐ │ │ │
│ │ ACTIONNEURS │◀───│ LOGICIEL EMBARQUE │ │
│ │ (Sorties) │ │ ┌─────────────────────────────────┐ │ │
│ │ │ │ │ - Systeme d'exploitation (RTOS) │ │ │
│ │ - Moteurs │ │ │ - Drivers / Pilotes │ │ │
│ │ - LEDs │ │ │ - Application │ │ │
│ │ - Afficheurs │ │ └─────────────────────────────────┘ │ │
│ │ - Relais │ └─────────────────────────────────────────┘ │
│ └──────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ ALIMENTATION │ │
│ │ Batterie / Secteur / Energie solaire │ │
│ └──────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
1.3 Microprocesseur vs Microcontroleur
Il est essentiel de distinguer ces deux composants fondamentaux :
| Critere | Microprocesseur (µP) | Microcontroleur (µC) |
|---|---|---|
| Definition | Unite centrale de traitement seule | Systeme complet sur une puce (SoC) |
| Composants integres | CPU uniquement | CPU + RAM + Flash + Peripheriques |
| Memoire | Externe (sur carte mere) | Interne (integree) |
| Peripheriques | Externes (chipsets) | Integres (GPIO, ADC, UART, etc.) |
| Puissance | Elevee (GHz, multi-coeurs) | Moderee (MHz a quelques GHz) |
| Consommation | Elevee (10-150W) | Faible (µA a quelques mA) |
| Cout | Eleve (+ carte mere) | Faible (0.5€ a 20€) |
| Applications | PC, serveurs, calcul intensif | Embarque, IoT, controle |
| Exemples | Intel Core, AMD Ryzen, ARM Cortex-A | STM32, PIC, AVR, ESP32 |
1.4 Criteres de Choix d'un Microcontroleur
Le choix d'un microcontroleur pour un projet embarque depend de nombreux facteurs :
Criteres techniques
- Architecture : 8, 16 ou 32 bits selon la complexite des calculs
- Frequence : De quelques MHz a plusieurs centaines de MHz
- Memoire Flash : Stockage du programme (Ko a Mo)
- Memoire RAM : Variables et pile d'execution (Ko a centaines de Ko)
- Nombre de GPIO : Entrees/sorties disponibles
- Peripheriques : ADC, DAC, UART, SPI, I2C, CAN, USB, Ethernet
- Timers : Nombre et resolution
- Interruptions : Nombre de sources et niveaux de priorite
- DMA : Transfert de donnees sans CPU
Criteres pratiques
- Consommation : Critique pour applications sur batterie
- Tension d'alimentation : 1.8V, 3.3V, 5V
- Boitier : DIP, QFP, BGA selon le montage
- Temperature de fonctionnement : Industriel (-40°C a +85°C)
- Outils de developpement : IDE, debogueur, programmateur
- Documentation et communaute : Support technique
- Prix et disponibilite : Approvisionnement
Principales familles de microcontroleurs
| Famille | Fabricant | Architecture | Points forts |
|---|---|---|---|
| STM32 | STMicroelectronics | ARM Cortex-M | Large gamme, outils gratuits, ecosysteme riche |
| PIC | Microchip | Proprietaire | Simplicite, faible cout, XC compilers |
| AVR | Microchip (ex-Atmel) | RISC 8 bits | Arduino, simple, bien documente |
| ESP32 | Espressif | Xtensa / RISC-V | WiFi/Bluetooth integre, IoT |
| LPC | NXP | ARM Cortex-M | Performance, USB, Ethernet |
| MSP430 | Texas Instruments | RISC 16 bits | Ultra basse consommation |
1.5 Introduction a la Famille STM32
La famille STM32 de STMicroelectronics est l'une des plus populaires pour les applications embarquees professionnelles. Elle offre une gamme complete basee sur les coeurs ARM Cortex-M.
Gammes STM32
| Gamme | Coeur | Frequence | Positionnement |
|---|---|---|---|
| STM32F0 | Cortex-M0 | 48 MHz | Entree de gamme, remplacement 8 bits |
| STM32F1 | Cortex-M3 | 72 MHz | Usage general, mainstream |
| STM32F3 | Cortex-M4 | 72 MHz | Mixed-signal, ADC haute resolution |
| STM32F4 | Cortex-M4F | 180 MHz | Haute performance, DSP, FPU |
| STM32F7 | Cortex-M7 | 216 MHz | Tres haute performance |
| STM32H7 | Cortex-M7 | 480 MHz | Performance maximale |
| STM32L0/L4/L5 | Cortex-M0+/M4/M33 | 32-110 MHz | Ultra basse consommation |
| STM32G0/G4 | Cortex-M0+/M4 | 64-170 MHz | Nouvelle generation mainstream |
Chapitre 2 : Microprocesseur ARM Cortex-M3/M4
Architecture du coeur processeur
🎯 Objectifs du chapitre
- Comprendre l'architecture ARM et ses avantages
- Connaitre les caracteristiques des coeurs Cortex-M3 et Cortex-M4
- Maitriser l'organisation des registres et modes de fonctionnement
- Comprendre le jeu d'instructions Thumb-2
2.1 Presentation d'ARM
ARM (Advanced RISC Machines) est une societe britannique qui concoit des architectures de processeurs. ARM ne fabrique pas de puces mais vend des licences de ses designs aux fabricants (STMicroelectronics, NXP, Texas Instruments, etc.).
Avantages de l'architecture ARM
- RISC (Reduced Instruction Set Computer) : Jeu d'instructions reduit et optimise
- Efficacite energetique : Excellent rapport performance/consommation
- Scalabilite : Du microcontroleur au serveur
- Ecosysteme : Outils, documentation, communaute immenses
- Standardisation : Code portable entre fabricants
Familles de coeurs ARM
| Famille | Coeurs | Applications |
|---|---|---|
| Cortex-A | A5, A7, A9, A53, A72, A76... | Smartphones, tablettes, serveurs |
| Cortex-R | R4, R5, R7, R8... | Temps reel critique (automobile, disques durs) |
| Cortex-M | M0, M0+, M3, M4, M7, M23, M33... | Microcontroleurs, embarque, IoT |
2.2 Architecture Cortex-M3 et Cortex-M4
Les coeurs Cortex-M3 et Cortex-M4 sont les plus utilises dans les microcontroleurs 32 bits professionnels.
Comparaison Cortex-M3 vs Cortex-M4
| Caracteristique | Cortex-M3 | Cortex-M4 |
|---|---|---|
| Architecture | ARMv7-M | ARMv7E-M |
| Pipeline | 3 etages | 3 etages |
| Jeu d'instructions | Thumb / Thumb-2 | Thumb / Thumb-2 + DSP |
| FPU | Non | Optionnel (simple precision) |
| Instructions DSP | Non | Oui (SIMD, MAC) |
| Performance | 1.25 DMIPS/MHz | 1.25 DMIPS/MHz (+ DSP/FPU) |
| Interruptions | Jusqu'a 240 | Jusqu'a 240 |
2.3 Pipeline et Execution des Instructions
Le Cortex-M4 utilise un pipeline a 3 etages qui permet d'executer plusieurs instructions en parallele :
Cycle 1 Cycle 2 Cycle 3 Cycle 4 Cycle 5 Cycle 6
┌──────┐ ┌──────┐ ┌──────┐
Inst 1 │ FETCH│──▶│DECODE│──▶│EXECUTE│
└──────┘ └──────┘ └──────┘
┌──────┐ ┌──────┐ ┌──────┐
Inst 2 │ FETCH│──▶│DECODE│──▶│EXECUTE│
└──────┘ └──────┘ └──────┘
┌──────┐ ┌──────┐ ┌──────┐
Inst 3 │ FETCH│──▶│DECODE│──▶│EXECUTE│
└──────┘ └──────┘ └──────┘
┌──────┐ ┌──────┐ ┌──────┐
Inst 4 │ FETCH│──▶│DECODE│──▶│EXECUTE│
└──────┘ └──────┘ └──────┘
FETCH : Lecture de l'instruction depuis la memoire
DECODE : Decodage de l'instruction et lecture des operandes
EXECUTE : Execution de l'operation et ecriture du resultat
Grace au pipeline, une instruction peut etre executee a chaque cycle d'horloge (en regime permanent), permettant d'atteindre environ 1.25 DMIPS/MHz.
2.4 Registres du Processeur
Le Cortex-M4 dispose de 16 registres de 32 bits accessibles directement par le programmeur :
┌─────────────────────────────────────────────────────────────┐
│ REGISTRES CORTEX-M4 │
├─────────────────────────────────────────────────────────────┤
│ │
│ R0 ─────────┐ │
│ R1 ─────────┤ │
│ R2 ─────────┤ Registres generaux │
│ R3 ─────────┤ (usage libre, parametres fonctions) │
│ R4 ─────────┤ │
│ R5 ─────────┤ │
│ R6 ─────────┤ │
│ R7 ─────────┤ │
│ R8 ─────────┤ │
│ R9 ─────────┤ │
│ R10 ─────────┤ │
│ R11 ─────────┘ │
│ │
│ R12 ──────────── IP (Intra-Procedure scratch register) │
│ R13 ──────────── SP (Stack Pointer) │
│ R14 ──────────── LR (Link Register - adresse retour) │
│ R15 ──────────── PC (Program Counter) │
│ │
├─────────────────────────────────────────────────────────────┤
│ REGISTRES SPECIAUX │
├─────────────────────────────────────────────────────────────┤
│ xPSR ─────────── Program Status Register │
│ PRIMASK ──────── Masque interruptions (niveau 1) │
│ FAULTMASK ────── Masque fautes (niveau 2) │
│ BASEPRI ──────── Priorite de base des interruptions │
│ CONTROL ──────── Controle du stack et privileges │
│ │
├─────────────────────────────────────────────────────────────┤
│ REGISTRES FPU (si present) │
├─────────────────────────────────────────────────────────────┤
│ S0-S31 ───────── 32 registres simple precision (32 bits) │
│ D0-D15 ───────── 16 registres double precision (64 bits) │
│ FPSCR ────────── Floating-Point Status and Control │
└─────────────────────────────────────────────────────────────┘
Registres speciaux importants
- PC (R15) : Contient l'adresse de l'instruction en cours + 4 (a cause du pipeline)
- SP (R13) : Pointeur de pile, deux piles possibles (MSP et PSP)
- LR (R14) : Stocke l'adresse de retour lors d'un appel de fonction
- xPSR : Contient les flags (N, Z, C, V) et le numero d'exception
2.5 Modes de Fonctionnement
Le Cortex-M4 possede deux modes de fonctionnement et deux niveaux de privilege :
Modes d'execution
- Thread Mode : Mode normal d'execution du programme principal
- Handler Mode : Mode d'execution des gestionnaires d'interruption
Niveaux de privilege
- Privileged : Acces complet a toutes les ressources
- Unprivileged : Acces restreint (protection memoire possible)
RESET
│
▼
┌─────────────────────┐
│ THREAD MODE │
│ (Privileged) │◀─────────────────┐
│ │ │
│ Programme principal│ │
└─────────┬───────────┘ │
│ │
│ Interruption │ Retour
│ │
▼ │
┌─────────────────────┐ │
│ HANDLER MODE │ │
│ (Privileged) │──────────────────┘
│ │
│ Routine interruption│
└─────────────────────┘
2.6 Jeu d'Instructions Thumb-2
Le Cortex-M4 utilise exclusivement le jeu d'instructions Thumb-2, qui combine des instructions 16 bits et 32 bits pour optimiser la densite du code et les performances.
Avantages de Thumb-2
- Densite de code : Instructions 16 bits pour les operations courantes
- Performance : Instructions 32 bits pour les operations complexes
- Pas de changement de mode : Contrairement aux anciens ARM
- Alignement flexible : Code aligne sur 16 bits
Exemples d'instructions
; Instructions arithmetiques ADD R0, R1, R2 ; R0 = R1 + R2 SUB R0, R1, #10 ; R0 = R1 - 10 MUL R0, R1, R2 ; R0 = R1 × R2 MLA R0, R1, R2, R3 ; R0 = R1 × R2 + R3 (Multiply-Accumulate) ; Instructions logiques AND R0, R1, R2 ; R0 = R1 AND R2 ORR R0, R1, R2 ; R0 = R1 OR R2 EOR R0, R1, R2 ; R0 = R1 XOR R2 BIC R0, R1, R2 ; R0 = R1 AND (NOT R2) - Bit Clear ; Instructions de decalage LSL R0, R1, #3 ; R0 = R1 << 3 (decalage gauche) LSR R0, R1, #3 ; R0 = R1 >> 3 (decalage droite logique) ASR R0, R1, #3 ; R0 = R1 >> 3 (decalage droite arithmetique) ; Instructions memoire LDR R0, [R1] ; Charger 32 bits depuis adresse R1 STR R0, [R1] ; Stocker R0 a l'adresse R1 LDRB R0, [R1] ; Charger 8 bits (byte) LDRH R0, [R1] ; Charger 16 bits (half-word) ; Instructions de branchement B label ; Branchement inconditionnel BEQ label ; Branchement si egal (Z=1) BNE label ; Branchement si different (Z=0) BL fonction ; Appel de fonction (sauvegarde LR) BX LR ; Retour de fonction
2.7 Le NVIC (Nested Vectored Interrupt Controller)
Le NVIC est le controleur d'interruptions integre au coeur Cortex-M. Il gere toutes les interruptions du systeme de maniere efficace et deterministe.
Caracteristiques du NVIC
- Jusqu'a 240 interruptions externes configurables
- 16 niveaux de priorite programmables (0 = plus haute)
- Interruptions imbriquees (nested) automatiques
- Tail-chaining : Enchainement optimise des interruptions
- Late arrival : Preemption pendant l'empilement
- Latence deterministe : 12 cycles pour entrer dans le handler
Table des vecteurs d'interruption
La table des vecteurs se trouve au debut de la memoire Flash (adresse 0x00000000) et contient les adresses des handlers :
| Offset | Vecteur | Description |
|---|---|---|
| 0x0000 | Initial SP | Valeur initiale du Stack Pointer |
| 0x0004 | Reset | Adresse du handler Reset |
| 0x0008 | NMI | Non-Maskable Interrupt |
| 0x000C | HardFault | Erreur materielle grave |
| 0x0010 | MemManage | Erreur de protection memoire |
| 0x0014 | BusFault | Erreur de bus |
| 0x0018 | UsageFault | Instruction invalide |
| 0x002C | SVCall | Appel systeme (SVC) |
| 0x0038 | PendSV | Pending Service Call |
| 0x003C | SysTick | Timer systeme |
| 0x0040+ | IRQ0, IRQ1... | Interruptions peripheriques |
Chapitre 3 : Architecture du STM32F4xx
Organisation materielle et cartographie memoire
🎯 Objectifs du chapitre
- Comprendre l'architecture interne du STM32F4
- Maitriser la cartographie memoire et les bus
- Connaitre le systeme d'horloge (RCC)
- Identifier les peripheriques disponibles
3.1 Vue d'ensemble du STM32F4
Le STM32F4 est un microcontroleur complet integrant de nombreux peripheriques autour du coeur Cortex-M4 :
168-180 MHz
Frequence CPU maximale
1-2 Mo Flash
Memoire programme
192-256 Ko SRAM
Memoire donnees
82-140 GPIO
Entrees/Sorties
FPU + DSP
Calcul flottant et signal
3.3V
Alimentation (5V tolerant)
Peripheriques integres typiques (STM32F407)
- Timers : 2 avances (TIM1, TIM8), 4 generaux 32 bits (TIM2, TIM5), 6 generaux 16 bits, 2 basiques
- Communication : 4 USART, 2 UART, 3 SPI, 3 I2C, 2 CAN, 1 USB OTG
- Analogique : 3 ADC 12 bits (24 canaux), 2 DAC 12 bits
- DMA : 2 controleurs DMA (16 canaux total)
- Autres : RTC, Watchdog, CRC, RNG (generateur aleatoire)
3.2 Diagramme Bloc Simplifie
┌────────────────────────────────────────────────────────────────────────────┐
│ STM32F4xx ARCHITECTURE │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ ARM CORTEX-M4 CORE │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────────────┐ │ │
│ │ │ CPU │ │ FPU │ │ MPU │ │ NVIC │ │ │
│ │ │ 168 MHz │ │ Float │ │ Protect │ │ 240 interrupts │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ └──────────────────────┘ │ │
│ └─────────────────────────────┬───────────────────────────────────────┘ │
│ │ │
│ ══════════════════════════════╪════════════════════════════════════════ │
│ AHB Bus Matrix │ (Advanced High-performance Bus) │
│ ══════════════════════════════╪════════════════════════════════════════ │
│ │ │ │ │ │ │
│ ┌────▼────┐ ┌─────▼─────┐ │ ┌─────▼─────┐ ┌────▼────┐ │
│ │ FLASH │ │ SRAM │ │ │ DMA1 │ │ DMA2 │ │
│ │ 1-2 Mo │ │ 192-256Ko │ │ │ 8 streams │ │8 streams│ │
│ └─────────┘ └───────────┘ │ └───────────┘ └─────────┘ │
│ │ │
│ ══════════════════════════════╪════════════════════════════════════════ │
│ AHB1 │ AHB2 │
│ ══════════════════════════════╪════════════════════════════════════════ │
│ │ │ │ │ │ │ │ │ │
│ ┌─▼─┐┌─▼─┐┌─▼─┐┌─▼─┐ │ ┌─▼──┐ ┌──▼──┐ ┌──▼──┐ │
│ │PA ││PB ││PC ││...│ GPIO │ │USB │ │ RNG │ │DCMI │ │
│ └───┘└───┘└───┘└───┘ │ │OTG │ │ │ │ │ │
│ │ └────┘ └─────┘ └─────┘ │
│ ══════════════════════════════╪════════════════════════════════════════ │
│ APB1 (42 MHz max) │ APB2 (84 MHz max) │
│ ══════════════════════════════╪════════════════════════════════════════ │
│ │ │ │ │ │ │ │ │ │ │
│ ┌─▼──┐┌─▼──┐┌─▼──┐┌─▼──┐ │ ┌──▼──┐┌──▼──┐┌──▼──┐┌──▼──┐ │
│ │TIM2││UART││I2C1││SPI2│ │ │TIM1 ││USART││ SPI1││ ADC │ │
│ │-7 ││2-5 ││-3 ││-3 │ │ │TIM8 ││1,6 ││ ││1-3 │ │
│ └────┘└────┘└────┘└────┘ │ └─────┘└─────┘└─────┘└─────┘ │
│ │ │ │
│ ┌──▼──┐ │ │
│ │ CAN │ │ │
│ │ DAC │ │ │
│ └─────┘ │ │
└────────────────────────────────────────────────────────────────────────────┘
3.3 Cartographie Memoire
L'espace d'adressage du Cortex-M4 est de 4 Go (32 bits), divise en regions predefinies :
Adresse Taille Region Contenu
┌──────────────┬─────────────┬────────────────────────────────────────┐
│ 0xFFFFFFFF │ │ │
│ │ 512 Mo │ Vendor-specific │
│ 0xE0100000 │ │ │
├──────────────┼─────────────┼────────────────────────────────────────┤
│ 0xE00FFFFF │ │ Private Peripheral Bus │
│ │ 1 Mo │ (NVIC, SysTick, Debug) │
│ 0xE0000000 │ │ Registres systeme Cortex-M │
├──────────────┼─────────────┼────────────────────────────────────────┤
│ 0xDFFFFFFF │ │ │
│ │ 512 Mo │ External Device │
│ 0xA0000000 │ │ (memoire externe FSMC) │
├──────────────┼─────────────┼────────────────────────────────────────┤
│ 0x9FFFFFFF │ │ │
│ │ 1 Go │ External RAM │
│ 0x60000000 │ │ (SDRAM externe si present) │
├──────────────┼─────────────┼────────────────────────────────────────┤
│ 0x5FFFFFFF │ │ AHB2 Peripherals │
│ │ │ (USB OTG, RNG, DCMI) │
│ 0x50000000 │ 512 Mo │ │
├──────────────┤ Periph. ├────────────────────────────────────────┤
│ 0x4FFFFFFF │ │ AHB1 Peripherals │
│ │ │ (GPIO, DMA, RCC, Flash) │
│ 0x40020000 │ │ │
├──────────────┤ ├────────────────────────────────────────┤
│ 0x4001FFFF │ │ APB2 Peripherals │
│ │ │ (USART1, SPI1, TIM1, ADC) │
│ 0x40010000 │ │ │
├──────────────┤ ├────────────────────────────────────────┤
│ 0x4000FFFF │ │ APB1 Peripherals │
│ │ │ (TIM2-7, UART, I2C, SPI2/3, CAN, DAC) │
│ 0x40000000 │ │ │
├──────────────┼─────────────┼────────────────────────────────────────┤
│ 0x3FFFFFFF │ │ │
│ │ 512 Mo │ SRAM (donnees, variables) │
│ 0x20000000 │ │ 192 Ko pour F407 │
├──────────────┼─────────────┼────────────────────────────────────────┤
│ 0x1FFFFFFF │ │ │
│ │ 512 Mo │ Code (Flash, System memory) │
│ 0x08000000 │ │ Programme utilisateur │
├──────────────┤ ├────────────────────────────────────────┤
│ 0x00000000 │ │ Aliased selon BOOT pins │
└──────────────┴─────────────┴────────────────────────────────────────┘
0x08000000: Debut de la Flash (programme)0x20000000: Debut de la SRAM (donnees)0x40000000: Debut des peripheriques0xE0000000: Registres systeme Cortex-M
3.4 Systeme d'Horloge (RCC)
Le RCC (Reset and Clock Control) gere toutes les horloges du systeme. Une bonne comprehension est essentielle car chaque peripherique necessite que son horloge soit activee.
Sources d'horloge
| Source | Nom | Frequence | Caracteristiques |
|---|---|---|---|
| HSI | High Speed Internal | 16 MHz | RC interne, moins precis, demarrage rapide |
| HSE | High Speed External | 4-26 MHz | Quartz externe, tres precis, utilise pour PLL |
| LSI | Low Speed Internal | 32 kHz | RC interne, pour watchdog et RTC |
| LSE | Low Speed External | 32.768 kHz | Quartz externe, RTC precis |
| PLL | Phase Locked Loop | Jusqu'a 180 MHz | Multiplie la frequence HSI ou HSE |
Configuration PLL
Le PLL permet d'atteindre des frequences elevees a partir de l'oscillateur. La formule est :
/* Formules de calcul du PLL */ f_VCO = f_input × (PLLN / PLLM) // Frequence VCO interne f_PLL = f_VCO / PLLP // Horloge systeme (SYSCLK) f_USB = f_VCO / PLLQ // Horloge USB (doit etre 48 MHz) /* Contraintes */ - PLLM : 2 a 63 (diviseur d'entree) - PLLN : 50 a 432 (multiplicateur) - PLLP : 2, 4, 6 ou 8 (diviseur sortie principale) - PLLQ : 2 a 15 (diviseur USB/SDIO) - f_VCO doit etre entre 100 MHz et 432 MHz /* Exemple : HSE = 8 MHz → SYSCLK = 168 MHz */ PLLM = 8 // 8 MHz / 8 = 1 MHz (entree PLL) PLLN = 336 // 1 MHz × 336 = 336 MHz (VCO) PLLP = 2 // 336 MHz / 2 = 168 MHz (SYSCLK) PLLQ = 7 // 336 MHz / 7 = 48 MHz (USB)
Arbre d'horloge simplifie
HSI (16 MHz) ─────┐
│ ┌─────┐
HSE (8 MHz) ──────┴───▶│ PLL │────▶ PLLCLK (168 MHz)
└─────┘ │
▼
┌────────────┐
HSI ─────────────────────────────┤ SW (MUX) ├───▶ SYSCLK (168 MHz)
HSE ─────────────────────────────┤ │
PLLCLK ──────────────────────────┤ │
└────────────┘
│
┌────────────────┼────────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ AHB /1 │ │ APB1 /4 │ │ APB2 /2 │
│ 168 MHz │ │ 42 MHz │ │ 84 MHz │
└──────────┘ └──────────┘ └──────────┘
│ │ │
CPU, DMA TIM2-7, UART TIM1, SPI1
Flash, SRAM I2C, SPI2/3 USART1, ADC
GPIO CAN, DAC TIM8-11
/* Activation des horloges peripheriques en HAL */ __HAL_RCC_GPIOA_CLK_ENABLE(); // GPIO Port A __HAL_RCC_GPIOB_CLK_ENABLE(); // GPIO Port B __HAL_RCC_GPIOC_CLK_ENABLE(); // GPIO Port C __HAL_RCC_USART2_CLK_ENABLE(); // USART2 __HAL_RCC_I2C1_CLK_ENABLE(); // I2C1 __HAL_RCC_SPI1_CLK_ENABLE(); // SPI1 __HAL_RCC_TIM2_CLK_ENABLE(); // Timer 2 __HAL_RCC_ADC1_CLK_ENABLE(); // ADC1 __HAL_RCC_DAC_CLK_ENABLE(); // DAC __HAL_RCC_CAN1_CLK_ENABLE(); // CAN1 __HAL_RCC_DMA1_CLK_ENABLE(); // DMA1
3.5 Reset et Modes de Demarrage
Sources de Reset
- Power-on Reset (POR) : A la mise sous tension
- External Reset : Pin NRST maintenu bas
- Software Reset : Via le registre AIRCR
- Independent Watchdog (IWDG) : Timer non rafraichi
- Window Watchdog (WWDG) : Timer hors fenetre
- Low-Power Management : Sortie de mode STANDBY
Modes de demarrage (Boot)
Les pins BOOT0 et BOOT1 determinent la source de demarrage :
| BOOT1 | BOOT0 | Mode de demarrage | Description |
|---|---|---|---|
| X | 0 | Main Flash | Demarre depuis la Flash utilisateur (normal) |
| 0 | 1 | System Memory | Demarre le bootloader ST (pour programmation) |
| 1 | 1 | Embedded SRAM | Demarre depuis la RAM (pour debug) |
Chapitre 4 : Environnement STM32CubeIDE
Outils de developpement et configuration graphique
🎯 Objectifs du chapitre
- Installer et configurer STM32CubeIDE
- Utiliser STM32CubeMX pour la configuration graphique
- Comprendre la structure d'un projet HAL
- Maitriser le cycle de developpement (compilation, debug)
4.1 Presentation des Outils STM32
STMicroelectronics fournit un ecosysteme complet et gratuit pour le developpement STM32 :
STM32CubeIDE
IDE complet base sur Eclipse. Integre editeur, compilateur (GCC), debogueur, et CubeMX. C'est l'outil recommande.
STM32CubeMX
Outil de configuration graphique. Genere le code d'initialisation des peripheriques a partir d'une interface visuelle.
HAL Library
Hardware Abstraction Layer. Bibliotheque de fonctions pour acceder aux peripheriques de maniere portable.
Documentation
Reference Manual, Datasheet, Application Notes disponibles sur st.com
Alternatives a STM32CubeIDE
- Keil MDK-ARM : IDE professionnel (payant, version gratuite limitee a 32 Ko)
- IAR Embedded Workbench : IDE professionnel (payant)
- PlatformIO + VS Code : Extension populaire, gratuite
- SW4STM32 : Ancien IDE gratuit (remplace par CubeIDE)
4.2 Configuration avec STM32CubeMX
STM32CubeMX permet de configurer visuellement tous les aspects du microcontroleur :
Etapes de configuration
- Selection du MCU : Choisir la reference exacte (ex: STM32F407VGT6)
- Configuration du Pinout : Assigner les fonctions aux broches
- Configuration de l'horloge : Clock Configuration (Clock Tree)
- Configuration des peripheriques : Parametres de chaque module
- Generation du code : Projet complet avec initialisation
Onglets principaux de CubeMX
| Onglet | Fonction |
|---|---|
| Pinout & Configuration | Vue du boitier, affectation des pins, configuration des peripheriques |
| Clock Configuration | Arbre d'horloge graphique, configuration PLL |
| Project Manager | Nom du projet, IDE cible, options de generation |
| Tools | Calcul de consommation, verification des conflits |
4.3 Structure d'un Projet HAL
Un projet genere par CubeMX a une structure standardisee :
/* Arborescence typique d'un projet STM32CubeIDE */ MonProjet/ ├── Core/ │ ├── Inc/ // Headers utilisateur │ │ ├── main.h │ │ ├── stm32f4xx_hal_conf.h // Configuration HAL │ │ └── stm32f4xx_it.h // Prototypes handlers IT │ │ │ └── Src/ // Sources utilisateur │ ├── main.c // Programme principal │ ├── stm32f4xx_it.c // Handlers d'interruption │ ├── stm32f4xx_hal_msp.c // Init bas niveau (MSP) │ ├── syscalls.c // Appels systeme │ ├── sysmem.c // Gestion memoire │ └── system_stm32f4xx.c // Init systeme │ ├── Drivers/ │ ├── CMSIS/ // Definitions ARM standard │ │ ├── Device/ST/STM32F4xx/ │ │ └── Include/ │ │ │ └── STM32F4xx_HAL_Driver/ // Bibliotheque HAL │ ├── Inc/ // Headers HAL │ └── Src/ // Sources HAL │ ├── MonProjet.ioc // Fichier configuration CubeMX ├── STM32F407VGTX_FLASH.ld // Script de linkage └── startup_stm32f407vgtx.s // Code de demarrage (assembleur)
4.4 Structure du fichier main.c
/* main.c - Structure typique */ #include "main.h" /* USER CODE BEGIN PV - Variables privees */ uint32_t counter = 0; /* USER CODE END PV */ /* Prototypes des fonctions privees */ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_USART2_UART_Init(void); int main(void) { /* Reset de tous les peripheriques, init Flash et SysTick */ HAL_Init(); /* Configuration de l'horloge systeme */ SystemClock_Config(); /* Initialisation des peripheriques configures */ MX_GPIO_Init(); MX_USART2_UART_Init(); /* USER CODE BEGIN 2 - Initialisation utilisateur */ // Votre code d'initialisation ici /* USER CODE END 2 */ /* Boucle principale infinie */ while (1) { /* USER CODE BEGIN 3 - Code principal */ HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); HAL_Delay(500); // Delai 500 ms /* USER CODE END 3 */ } } /** * @brief Configuration de l'horloge systeme */ void SystemClock_Config(void) { /* Code genere par CubeMX - Ne pas modifier */ /* ... */ }
/* USER CODE BEGIN */ et /* USER CODE END */. Tout code en dehors sera ecrase lors de la regeneration avec CubeMX !
4.5 Bibliotheque HAL
La HAL (Hardware Abstraction Layer) est la bibliotheque officielle de ST pour programmer les STM32. Elle offre une API portable entre les differentes familles.
Avantages de la HAL
- Abstraction : Code independant des registres materiels
- Portabilite : Meme API pour STM32F4, F7, L4, etc.
- Documentation : Bien documentee avec exemples
- Support : Maintenue et mise a jour par ST
Fonctions HAL courantes
| Fonction | Description |
|---|---|
| HAL_Init() | Initialise HAL, Flash, SysTick |
| HAL_Delay(ms) | Delai bloquant en millisecondes |
| HAL_GetTick() | Retourne le temps en ms depuis le demarrage |
| HAL_GPIO_Init() | Configure un port GPIO |
| HAL_GPIO_WritePin() | Ecrit sur une broche |
| HAL_GPIO_ReadPin() | Lit l'etat d'une broche |
| HAL_GPIO_TogglePin() | Inverse l'etat d'une broche |
| HAL_UART_Transmit() | Envoie des donnees par UART |
| HAL_UART_Receive() | Recoit des donnees par UART |
| HAL_ADC_Start() | Demarre une conversion ADC |
| HAL_ADC_GetValue() | Lit le resultat ADC |
| HAL_TIM_Base_Start() | Demarre un timer |
| HAL_TIM_PWM_Start() | Demarre une sortie PWM |
4.6 Cycle de Developpement
┌─────────────────────────────────────────────────────────────────────────┐
│ CYCLE DE DEVELOPPEMENT STM32 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ 1. SPEC │────────▶│ 2. CONFIG │────────▶│ 3. CODE │ │
│ │ Cahier des │ │ STM32CubeMX │ │ Editeur C │ │
│ │ charges │ │ Pinout+Clock│ │ main.c │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ 6. DEPLOY │◀────────│ 5. DEBUG │◀────────│ 4. BUILD │ │
│ │ Production │ │ ST-Link │ │ Compilation │ │
│ │ sur cible │ │ Breakpoints │ │ arm-gcc │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │ │ │ │
│ │ │ │ │
│ └────────────────────────┼────────────────────────┘ │
│ │ │
│ ┌─────▼─────┐ │
│ │ ITERER │ │
│ │ Corriger │ │
│ │ Ameliorer│ │
│ └───────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
Raccourcis clavier STM32CubeIDE
| Raccourci | Action |
|---|---|
Ctrl+B | Compiler le projet (Build) |
F11 | Debuguer (Debug) |
Ctrl+F11 | Executer (Run) |
F5 | Continuer (pendant debug) |
F6 | Step Over (instruction suivante) |
F7 | Step Into (entrer dans fonction) |
Ctrl+Shift+B | Ajouter/retirer un breakpoint |
Chapitre 5 : Interfaces d'E/S Numeriques (GPIO)
Configuration et programmation des entrees/sorties
🎯 Objectifs du chapitre
- Comprendre l'organisation et la structure des GPIO
- Maitriser les differents modes de configuration
- Programmer les GPIO avec la HAL et en acces direct aux registres
- Configurer les interruptions externes (EXTI)
5.1 Organisation des GPIO
Les GPIO (General Purpose Input/Output) sont les broches d'entree/sortie numeriques du microcontroleur. Sur le STM32F4, elles sont organisees en ports de 16 broches chacun.
Nomenclature
/* Format : P + Lettre_Port + Numero_Pin */ PA0 = Port A, Broche 0 // Pins 0 a 15 PB5 = Port B, Broche 5 PC13 = Port C, Broche 13 // Souvent le bouton USER sur Nucleo PD12 = Port D, Broche 12 // LED verte sur Discovery /* STM32F407 : Ports A a I (9 ports × 16 pins = 144 pins max) Mais le nombre reel depend du boitier (64 a 176 pins) */
Caracteristiques electriques
- Tension : 0V (LOW) a 3.3V (HIGH)
- 5V tolerant : La plupart des pins acceptent 5V en entree
- Courant de sortie : Jusqu'a 25 mA par pin
- Courant total : Limite a 120 mA pour tout le boitier
- Impedance d'entree : Tres haute (CMOS)
- Pull-up/Pull-down internes : ~40 kΩ
5.2 Modes de Configuration
Chaque broche GPIO peut etre configuree dans l'un des 4 modes principaux :
Mode Entree (Input)
/* La broche lit l'etat logique externe */ VCC │ ┌─────┴─────┐ │ Pull-up │ (optionnel, ~40kΩ interne) │ (interne) │ └─────┬─────┘ │ Signal ────────►├────────► Registre IDR (lecture) externe │ ┌─────┴─────┐ │ Pull-down │ (optionnel) └─────┬─────┘ │ GND GPIO_MODE_INPUT : Entree numerique - GPIO_NOPULL : Haute impedance (flottant) - GPIO_PULLUP : Resistance pull-up interne activee - GPIO_PULLDOWN : Resistance pull-down interne activee
Mode Sortie (Output)
/* La broche impose un etat logique */ GPIO_MODE_OUTPUT_PP : Push-Pull (le plus courant) ┌─────────────────────────────────────┐ │ VCC │ │ │ │ │ ┌────┴────┐ │ │ │ P-MOS │◀── ODR=1 → ON │ │ └────┬────┘ │ │ ├───────────► Sortie │ │ ┌────┴────┐ │ │ │ N-MOS │◀── ODR=0 → ON │ │ └────┬────┘ │ │ │ │ │ GND │ └─────────────────────────────────────┘ → Peut fournir ET absorber du courant GPIO_MODE_OUTPUT_OD : Open-Drain ┌─────────────────────────────────────┐ │ (pull-up externe) │ │ │ │ │ ├───────────► Sortie │ │ ┌────┴────┐ │ │ │ N-MOS │◀── ODR=0 → ON │ │ └────┬────┘ (tire a GND)│ │ │ │ │ GND │ └─────────────────────────────────────┘ → Ne peut que tirer a la masse (necessite pull-up externe) → Utilise pour I2C, bus partages
Mode Fonction Alternee (Alternate Function)
/* La broche est controlee par un peripherique interne */ GPIO_MODE_AF_PP : Alternate Function Push-Pull GPIO_MODE_AF_OD : Alternate Function Open-Drain Exemples d'utilisation : - USART TX/RX → AF7 pour USART1/2/3 - SPI SCK/MOSI/MISO → AF5 pour SPI1/2 - I2C SDA/SCL → AF4 (toujours en Open-Drain) - Timer PWM → AF1/AF2/AF3 selon le timer - USB, CAN, etc.
Mode Analogique
/* La broche est connectee a l'ADC ou DAC */ GPIO_MODE_ANALOG : Mode analogique - Desactive le buffer numerique - Reduit la consommation - Obligatoire pour ADC et DAC
5.3 Registres GPIO
Chaque port GPIO possede un ensemble de registres de configuration et de donnees :
| Registre | Nom | Taille | Description |
|---|---|---|---|
| GPIOx_MODER | Mode | 32 bits | 2 bits/pin : Input(00), Output(01), AF(10), Analog(11) |
| GPIOx_OTYPER | Output Type | 16 bits | 1 bit/pin : Push-Pull(0), Open-Drain(1) |
| GPIOx_OSPEEDR | Output Speed | 32 bits | 2 bits/pin : Low(00), Medium(01), High(10), VHigh(11) |
| GPIOx_PUPDR | Pull-up/Pull-down | 32 bits | 2 bits/pin : None(00), Pull-up(01), Pull-down(10) |
| GPIOx_IDR | Input Data | 16 bits | Lecture seule : etat des entrees |
| GPIOx_ODR | Output Data | 16 bits | Lecture/ecriture : etat des sorties |
| GPIOx_BSRR | Bit Set/Reset | 32 bits | Ecriture atomique : bits [15:0]=set, [31:16]=reset |
| GPIOx_AFRL/H | Alternate Function | 2×32 bits | 4 bits/pin : selection AF0-AF15 |
Exemple de configuration directe par registres
/* Configuration de PA5 en sortie Push-Pull (LED) */ // 1. Activer l'horloge GPIOA RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN; // 2. Configurer PA5 en sortie (MODER5 = 01) GPIOA->MODER &= ~(0x3 << (5 * 2)); // Effacer bits 10-11 GPIOA->MODER |= (0x1 << (5 * 2)); // Mettre 01 (sortie) // 3. Type Push-Pull (OTYPER5 = 0) GPIOA->OTYPER &= ~(1 << 5); // 4. Vitesse Low (OSPEEDR5 = 00) GPIOA->OSPEEDR &= ~(0x3 << (5 * 2)); // 5. Pas de pull-up/pull-down (PUPDR5 = 00) GPIOA->PUPDR &= ~(0x3 << (5 * 2)); /* Utilisation */ GPIOA->ODR |= (1 << 5); // LED ON GPIOA->ODR &= ~(1 << 5); // LED OFF GPIOA->ODR ^= (1 << 5); // Toggle // Methode atomique avec BSRR (recommandee) GPIOA->BSRR = (1 << 5); // LED ON (bit 5 de BS) GPIOA->BSRR = (1 << (5 + 16)); // LED OFF (bit 21 de BR)
5.4 Configuration avec HAL
/* Configuration d'une LED (PA5) et d'un bouton (PC13) avec HAL */ GPIO_InitTypeDef GPIO_InitStruct = {0}; /* Activer les horloges des ports */ __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); /* Configuration LED - PA5 en sortie Push-Pull */ GPIO_InitStruct.Pin = GPIO_PIN_5; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* Configuration Bouton - PC13 en entree avec pull-up */ GPIO_InitStruct.Pin = GPIO_PIN_13; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); /* Utilisation */ // Allumer la LED HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); // Eteindre la LED HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET); // Inverser l'etat HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); // Lire le bouton (actif bas) if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_RESET) { // Bouton appuye HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); }
5.5 Interruptions Externes (EXTI)
Les EXTI (External Interrupt) permettent de declencher des interruptions sur changement d'etat des GPIO, evitant le polling permanent.
Configuration d'une interruption sur bouton
/* Configuration PC13 avec interruption sur front descendant */ GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOC_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_13; GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; // Interruption front descendant GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); /* Configurer et activer l'interruption dans le NVIC */ HAL_NVIC_SetPriority(EXTI15_10_IRQn, 2, 0); // Priorite 2 HAL_NVIC_EnableIRQ(EXTI15_10_IRQn); /* Modes d'interruption disponibles */ GPIO_MODE_IT_RISING // Front montant GPIO_MODE_IT_FALLING // Front descendant GPIO_MODE_IT_RISING_FALLING // Les deux fronts
Handler d'interruption
/* Dans stm32f4xx_it.c */ void EXTI15_10_IRQHandler(void) { HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13); } /* Callback utilisateur dans main.c */ void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (GPIO_Pin == GPIO_PIN_13) { // Action lors de l'appui sur le bouton HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); } }
static uint32_t last_press = 0;
if (HAL_GetTick() - last_press > 200) { /* action */ }
last_press = HAL_GetTick();
Chapitre 6 : Interfaces Timers/Counters
Temporisation, comptage, PWM et capture
🎯 Objectifs du chapitre
- Comprendre l'architecture des timers STM32
- Configurer un timer en mode base de temps
- Generer des signaux PWM
- Utiliser les modes capture et comparaison
6.1 Types de Timers
Le STM32F4 dispose de plusieurs types de timers avec des fonctionnalites differentes :
| Type | Timers | Bits | Canaux | Fonctionnalites |
|---|---|---|---|---|
| Avances | TIM1, TIM8 | 16 | 4 | PWM complementaire, dead-time, break, controle moteur |
| Generaux 32-bit | TIM2, TIM5 | 32 | 4 | Compteur 32 bits, capture, PWM, encodeur |
| Generaux 16-bit | TIM3, TIM4 | 16 | 4 | Capture, PWM, encodeur |
| Generaux | TIM9-TIM14 | 16 | 1-2 | PWM simple, capture |
| Basiques | TIM6, TIM7 | 16 | 0 | Base de temps uniquement, trigger DAC |
6.2 Architecture d'un Timer
┌─────────────────────────────────────────────────────────────────────────┐
│ ARCHITECTURE TIMER │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ Horloge APB ┌──────────┐ ┌──────────┐ │
│ (fAPB) ────▶│ PSC │───▶│ CNT │───▶ Evenements │
│ │ Prescaler│ │ Compteur │ (Update, CC) │
│ └──────────┘ └──────────┘ │
│ │ │ ▲ │
│ │ │ │ │
│ ▼ ▼ │ │
│ ┌────────────────────┐ │ │
│ │ ARR │─┘ │
│ │ Auto-Reload (max) │ Quand CNT = ARR → Reset │
│ └────────────────────┘ │
│ │
│ Canaux de sortie : │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ CCR1 │ CCR2 │ CCR3 │ CCR4 │ Capture/Compare Registers │ │
│ └────────────────────────────────────────────────────────────────┘ │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ CH1 │ │ CH2 │ │ CH3 │ │ CH4 │ Sorties PWM / Captures │
│ └──────┘ └──────┘ └──────┘ └──────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Registres principaux
- PSC (Prescaler) : Divise l'horloge d'entree (0 a 65535)
- CNT (Counter) : Compteur actuel
- ARR (Auto-Reload Register) : Valeur maximale du compteur
- CCRx (Capture/Compare Register) : Valeur de comparaison pour chaque canal
6.3 Formules de Calcul
/* Formules fondamentales des timers */ // Frequence apres prescaler f_timer = f_APB / (PSC + 1) // Periode d'overflow (temps entre deux resets) T_overflow = (ARR + 1) / f_timer = (ARR + 1) × (PSC + 1) / f_APB // Frequence d'overflow f_overflow = f_APB / ((PSC + 1) × (ARR + 1)) /* Exemple : Interruption toutes les 1 seconde */ // APB1 = 84 MHz pour TIM2-7 (avec prescaler x2 si APB1 div > 1) // On veut T = 1s, donc f = 1 Hz // Methode : choisir PSC pour avoir f_timer facile a diviser PSC = 8399 // f_timer = 84 MHz / 8400 = 10 kHz ARR = 9999 // f_overflow = 10 kHz / 10000 = 1 Hz /* Exemple : PWM a 1 kHz avec resolution 1000 niveaux */ // On veut f_PWM = 1 kHz et 1000 niveaux de duty cycle // f_PWM = f_APB / ((PSC+1) × (ARR+1)) ARR = 999 // 1000 niveaux (0 a 999) PSC = 83 // f_timer = 84 MHz / 84 = 1 MHz // f_PWM = 1 MHz / 1000 = 1 kHz ✓ // Duty cycle Duty = CCR / (ARR + 1) × 100% CCR = 500 // Duty = 500/1000 = 50%
6.4 Mode Base de Temps avec Interruption
/* Configuration TIM2 pour interruption periodique de 1 seconde */ TIM_HandleTypeDef htim2; void MX_TIM2_Init(void) { __HAL_RCC_TIM2_CLK_ENABLE(); htim2.Instance = TIM2; htim2.Init.Prescaler = 8399; // 84 MHz / 8400 = 10 kHz htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 9999; // 10 kHz / 10000 = 1 Hz htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; HAL_TIM_Base_Init(&htim2); // Configurer l'interruption HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0); HAL_NVIC_EnableIRQ(TIM2_IRQn); // Demarrer le timer avec interruption HAL_TIM_Base_Start_IT(&htim2); } /* Handler d'interruption (dans stm32f4xx_it.c) */ void TIM2_IRQHandler(void) { HAL_TIM_IRQHandler(&htim2); } /* Callback utilisateur (dans main.c) */ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == TIM2) { // Execute toutes les secondes HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); } }
6.5 Generation PWM
Le PWM (Pulse Width Modulation) permet de generer un signal carre avec un rapport cyclique variable, utilise pour le controle de moteurs, LEDs, etc.
PWM Mode 1 : Sortie HIGH quand CNT < CCR
ARR ─────────────────────────────────────────────────────
│
CCR ─┼─────────────┐ ┌─────────────┐
│ │ │ │
0 ─┴─────────────┴───────────┴─────────────┴───────────
Sortie:
┌─────────────┐ ┌─────────────┐
HIGH │ │ │ │
LOW ┘ └───────────┘ └───────────
│◄── Duty ──►│
│◄────────── Periode ────────►│
Duty Cycle = CCR / (ARR + 1) × 100%
/* Configuration PWM sur TIM3 Channel 1 (PA6) */ TIM_HandleTypeDef htim3; TIM_OC_InitTypeDef sConfigOC; void MX_TIM3_PWM_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; // Activer les horloges __HAL_RCC_TIM3_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); // Configurer PA6 en Alternate Function (TIM3_CH1) GPIO_InitStruct.Pin = GPIO_PIN_6; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Alternate = GPIO_AF2_TIM3; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // Configuration Timer - PWM 1 kHz htim3.Instance = TIM3; htim3.Init.Prescaler = 83; // 84 MHz / 84 = 1 MHz htim3.Init.CounterMode = TIM_COUNTERMODE_UP; htim3.Init.Period = 999; // 1 MHz / 1000 = 1 kHz htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; HAL_TIM_PWM_Init(&htim3); // Configuration du canal PWM sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 500; // Duty cycle 50% sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1); // Demarrer le PWM HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1); } /* Modifier le duty cycle en temps reel */ void SetDutyCycle(uint16_t duty) // duty: 0-1000 { __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, duty); } // Exemples d'utilisation SetDutyCycle(0); // 0% SetDutyCycle(250); // 25% SetDutyCycle(500); // 50% SetDutyCycle(750); // 75% SetDutyCycle(1000); // 100%
Chapitre 7 : Convertisseur Analogique-Numerique (ADC)
Acquisition et numerisation des signaux analogiques
🎯 Objectifs du chapitre
- Comprendre le principe de conversion analogique-numerique
- Configurer l'ADC du STM32F4
- Realiser des conversions simples et continues
- Utiliser le DMA pour les acquisitions rapides
7.1 Principe de la Conversion A/N
L'ADC (Analog to Digital Converter) convertit une tension analogique en une valeur numerique proportionnelle.
Tension d'entree Valeur numerique
VREF (3.3V) ─────────────────── 4095 (0xFFF)
│ │
│ │
│ ┌────────────────┐ │
Vin ─┼───▶│ ADC │──────┼──▶ Valeur
│ │ 12 bits │ │ numerique
│ └────────────────┘ │
│ │
0V ──┴───────────────────────────── 0 (0x000)
Formule de conversion :
ADC_Value = (Vin / VREF) × 4095
Vin = (ADC_Value / 4095) × VREF
Resolution = VREF / 4096 = 3.3V / 4096 ≈ 0.8 mV
Caracteristiques de l'ADC STM32F4
12 bits
Resolution (0-4095)
2.4 MSPS
Vitesse max
16 canaux
Par ADC (+ internes)
- 3 ADC independants (ADC1, ADC2, ADC3)
- Tension d'entree : 0V a VREF (generalement 3.3V)
- Modes : Simple, Continu, Scan, Discontinu
- Declenchement : Logiciel ou hardware (Timer, EXTI)
- Canaux internes : Temperature, VREFINT, VBAT
7.2 Configuration et Utilisation
/* Configuration ADC1 Channel 0 (PA0) - Conversion simple */ ADC_HandleTypeDef hadc1; ADC_ChannelConfTypeDef sConfig; void MX_ADC1_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; // Activer les horloges __HAL_RCC_ADC1_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); // Configurer PA0 en mode analogique GPIO_InitStruct.Pin = GPIO_PIN_0; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // Configuration ADC hadc1.Instance = ADC1; hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; hadc1.Init.Resolution = ADC_RESOLUTION_12B; hadc1.Init.ScanConvMode = DISABLE; // Un seul canal hadc1.Init.ContinuousConvMode = DISABLE; // Conversion unique hadc1.Init.DiscontinuousConvMode = DISABLE; hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc1.Init.NbrOfConversion = 1; hadc1.Init.DMAContinuousRequests = DISABLE; hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV; HAL_ADC_Init(&hadc1); // Configuration du canal sConfig.Channel = ADC_CHANNEL_0; sConfig.Rank = 1; sConfig.SamplingTime = ADC_SAMPLETIME_84CYCLES; HAL_ADC_ConfigChannel(&hadc1, &sConfig); } /* Fonction de lecture ADC */ uint16_t ReadADC(void) { uint16_t adc_value; HAL_ADC_Start(&hadc1); // Demarrer conversion HAL_ADC_PollForConversion(&hadc1, 100); // Attendre fin adc_value = HAL_ADC_GetValue(&hadc1); // Lire resultat HAL_ADC_Stop(&hadc1); // Arreter ADC return adc_value; } /* Conversion en tension */ float ADC_to_Voltage(uint16_t adc_value) { return ((float)adc_value / 4095.0f) * 3.3f; } /* Utilisation */ uint16_t raw = ReadADC(); float voltage = ADC_to_Voltage(raw); // En volts
7.3 Temps d'Echantillonnage
Le temps d'echantillonnage determine la duree pendant laquelle l'ADC capture le signal avant conversion. Un temps plus long est necessaire pour les sources a haute impedance.
| Constante | Cycles | Temps @21MHz | Usage |
|---|---|---|---|
ADC_SAMPLETIME_3CYCLES | 3 | 0.14 µs | Source basse impedance |
ADC_SAMPLETIME_15CYCLES | 15 | 0.71 µs | Usage general |
ADC_SAMPLETIME_28CYCLES | 28 | 1.33 µs | Usage general |
ADC_SAMPLETIME_84CYCLES | 84 | 4.0 µs | Haute impedance |
ADC_SAMPLETIME_480CYCLES | 480 | 22.9 µs | Tres haute impedance |
/* Temps total de conversion */ T_conv = T_sampling + 12 cycles (conversion successive approximation) // Exemple avec 84 cycles de sampling a 21 MHz T_conv = (84 + 12) / 21 MHz = 4.57 µs f_max = 1 / T_conv ≈ 219 kSPS
Chapitre 8 : Convertisseur Numerique-Analogique (DAC)
Generation de signaux analogiques
🎯 Objectifs du chapitre
- Comprendre le principe de conversion N/A
- Configurer le DAC du STM32F4
- Generer des tensions de sortie precises
- Creer des formes d'onde (sinus, triangle)
8.1 Caracteristiques du DAC STM32F4
Le DAC (Digital to Analog Converter) genere une tension analogique proportionnelle a une valeur numerique.
12 bits
Resolution (0-4095)
2 canaux
DAC1 (PA4), DAC2 (PA5)
- Tension de sortie : 0V a VREF (3.3V)
- Impedance de sortie : ~15 kΩ (utiliser buffer operationnel pour charge)
- Temps de stabilisation : ~3 µs
- Declenchement : Logiciel, Timer, EXTI
- Generateurs integres : Bruit, Triangle
/* Formule de conversion */ V_out = (DAC_Value / 4095) × VREF // Exemples avec VREF = 3.3V DAC_Value = 0 → V_out = 0 V DAC_Value = 2048 → V_out = 1.65 V DAC_Value = 4095 → V_out = 3.3 V // Resolution Resolution = 3.3V / 4096 ≈ 0.8 mV
8.2 Configuration et Utilisation
/* Configuration DAC Channel 1 (PA4) */ DAC_HandleTypeDef hdac; DAC_ChannelConfTypeDef sConfig; void MX_DAC_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; // Activer les horloges __HAL_RCC_DAC_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); // Configurer PA4 en mode analogique GPIO_InitStruct.Pin = GPIO_PIN_4; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // Configuration DAC hdac.Instance = DAC; HAL_DAC_Init(&hdac); // Configuration du canal sConfig.DAC_Trigger = DAC_TRIGGER_NONE; // Pas de trigger sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; HAL_DAC_ConfigChannel(&hdac, &sConfig, DAC_CHANNEL_1); // Demarrer le DAC HAL_DAC_Start(&hdac, DAC_CHANNEL_1); } /* Fonction pour definir la tension de sortie */ void DAC_SetVoltage(float voltage) { uint16_t dac_value; // Limiter entre 0 et 3.3V if (voltage < 0) voltage = 0; if (voltage > 3.3f) voltage = 3.3f; // Convertir en valeur DAC dac_value = (uint16_t)((voltage / 3.3f) * 4095); HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, dac_value); } /* Exemples d'utilisation */ DAC_SetVoltage(0.0f); // 0 V DAC_SetVoltage(1.65f); // 1.65 V (milieu) DAC_SetVoltage(2.5f); // 2.5 V DAC_SetVoltage(3.3f); // 3.3 V (max)
Chapitre 9 : Interface USART - Transmission Serie Asynchrone
Communication RS232 et protocole serie
🎯 Objectifs du chapitre
- Comprendre le principe de la transmission serie asynchrone
- Maitriser le protocole RS232 et ses parametres
- Configurer l'USART du STM32F4
- Implementer la communication bidirectionnelle
9.1 Principe de la Transmission Serie Asynchrone
La transmission serie asynchrone transmet les donnees bit par bit sur une seule ligne, sans signal d'horloge partage. L'emetteur et le recepteur doivent etre configures avec les memes parametres.
┌─────────────────────────────────────────────────────────────────────────┐
│ CONNEXION UART SIMPLE │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ DEVICE 1 │ │ DEVICE 2 │ │
│ │ (STM32) │ TX ────────────▶│ │ │
│ │ │◀──────────── RX │ (PC/MCU) │ │
│ │ │ │ │ │
│ │ GND ─┼─────────────────────────┼─ GND │ │
│ └──────────────┘ └──────────────┘ │
│ │
│ Note: TX d'un appareil connecte au RX de l'autre (croisement) │
│ │
└─────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ FORMAT D'UNE TRAME UART │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ Idle Start Data Bits Parity Stop │
│ (HIGH) Bit D0 D1 D2 D3 D4 D5 D6 D7 (opt) Bit │
│ │ │ │ │ │ │ │ │ │ │ │ │
│ ──────┐ │ │ │ │ │ │ │ │ │ ┌───│
│ HIGH │ │ │ │ │ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │ │ │ │ │ │
│ LOW └──────┴────┴────┴────┴────┴────┴────┴────┴──────────┴─────┘ │
│ │
│ - Start Bit : Toujours 0 (LOW) - signale le debut │
│ - Data Bits : 8 bits (ou 7, 9) - LSB en premier │
│ - Parity : Optionnel - detection d'erreur simple │
│ - Stop Bit : 1 ou 2 bits a HIGH - signale la fin │
│ │
└─────────────────────────────────────────────────────────────────────────┘
9.2 Parametres de Communication
Baudrate (Vitesse de transmission)
Le baudrate definit le nombre de bits transmis par seconde. Les deux appareils doivent utiliser le meme baudrate.
| Baudrate | Bits/s | Temps par bit | Usage typique |
|---|---|---|---|
| 9600 | 9600 bps | 104 µs | Applications lentes, GPS |
| 19200 | 19200 bps | 52 µs | Usage general |
| 38400 | 38400 bps | 26 µs | Usage general |
| 57600 | 57600 bps | 17 µs | Modems |
| 115200 | 115200 bps | 8.7 µs | Debug, standard |
| 230400 | 230400 bps | 4.3 µs | Haute vitesse |
| 921600 | 921600 bps | 1.1 µs | Tres haute vitesse |
Format de donnees courant
/* Configuration standard "8N1" */ - 8 bits de donnees - No parity (pas de parite) - 1 stop bit /* Autres configurations possibles */ 7E1 : 7 bits, Even parity, 1 stop 8E1 : 8 bits, Even parity, 1 stop 8O1 : 8 bits, Odd parity, 1 stop 8N2 : 8 bits, No parity, 2 stop bits
Parite
- None : Pas de bit de parite
- Even (Paire) : Le bit de parite rend le nombre total de 1 pair
- Odd (Impaire) : Le bit de parite rend le nombre total de 1 impair
9.3 Norme RS232
La norme RS232 definit l'interface electrique pour la communication serie. Elle utilise des niveaux de tension differents du TTL/CMOS.
| Caracteristique | TTL (STM32) | RS232 |
|---|---|---|
| Niveau logique HIGH | 3.3V | -3V a -15V |
| Niveau logique LOW | 0V | +3V a +15V |
| Distance max | ~1 m | 15 m |
| Debit max | Plusieurs Mbps | ~115 kbps |
Connecteur DB9 RS232
/* Brochage connecteur DB9 (vue cote cable) */
┌───────────────────────┐
│ 1 2 3 4 5 │
│ ○ ○ ○ ○ ○ │
│ ○ ○ ○ ○ │
│ 6 7 8 9 │
└───────────────────────┘
Pin 2 : RXD (Receive Data)
Pin 3 : TXD (Transmit Data)
Pin 5 : GND (Ground)
Pin 7 : RTS (Request To Send) - controle de flux
Pin 8 : CTS (Clear To Send) - controle de flux
9.4 USART du STM32F4
Le STM32F4 possede plusieurs USART/UART avec des fonctionnalites avancees :
- USART1, USART2, USART3 : Complets avec support synchrone
- UART4, UART5 : Asynchrone uniquement
- USART6 : Complet
Fonctionnalites
- Full-duplex (emission et reception simultanees)
- Baudrate programmable jusqu'a plusieurs Mbps
- Parite programmable (paire, impaire, aucune)
- 1 ou 2 stop bits
- Controle de flux materiel (RTS/CTS)
- Mode DMA pour transferts sans CPU
- Interruptions sur TX/RX/Erreurs
Pins USART (exemples STM32F4)
| USART | TX | RX | Bus | AF |
|---|---|---|---|---|
| USART1 | PA9 | PA10 | APB2 | AF7 |
| USART2 | PA2 | PA3 | APB1 | AF7 |
| USART3 | PB10 | PB11 | APB1 | AF7 |
| USART6 | PC6 | PC7 | APB2 | AF8 |
9.5 Configuration et Programmation USART
/* Configuration USART2 a 115200 bauds, 8N1 */ UART_HandleTypeDef huart2; void MX_USART2_UART_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; // Activer les horloges __HAL_RCC_USART2_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); // Configurer PA2 (TX) et PA3 (RX) en Alternate Function GPIO_InitStruct.Pin = GPIO_PIN_2 | GPIO_PIN_3; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Alternate = GPIO_AF7_USART2; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // Configuration UART huart2.Instance = USART2; huart2.Init.BaudRate = 115200; huart2.Init.WordLength = UART_WORDLENGTH_8B; huart2.Init.StopBits = UART_STOPBITS_1; huart2.Init.Parity = UART_PARITY_NONE; huart2.Init.Mode = UART_MODE_TX_RX; huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart2.Init.OverSampling = UART_OVERSAMPLING_16; HAL_UART_Init(&huart2); } /* Transmission bloquante */ char message[] = "Hello STM32!\r\n"; HAL_UART_Transmit(&huart2, (uint8_t*)message, strlen(message), 1000); /* Reception bloquante */ uint8_t rx_buffer[100]; HAL_UART_Receive(&huart2, rx_buffer, 10, 5000); // 10 octets, timeout 5s /* Transmission d'un seul caractere */ uint8_t ch = 'A'; HAL_UART_Transmit(&huart2, &ch, 1, 100);
9.6 Reception par Interruption
La reception par interruption est recommandee pour ne pas bloquer le programme principal.
/* Configuration reception par interruption */ uint8_t rx_byte; uint8_t rx_buffer[256]; uint16_t rx_index = 0; void StartUARTReception(void) { // Configurer l'interruption NVIC HAL_NVIC_SetPriority(USART2_IRQn, 0, 0); HAL_NVIC_EnableIRQ(USART2_IRQn); // Demarrer la reception d'un octet HAL_UART_Receive_IT(&huart2, &rx_byte, 1); } /* Handler d'interruption (stm32f4xx_it.c) */ void USART2_IRQHandler(void) { HAL_UART_IRQHandler(&huart2); } /* Callback de reception (main.c) */ void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if (huart->Instance == USART2) { // Stocker l'octet recu rx_buffer[rx_index++] = rx_byte; // Verifier fin de ligne ou buffer plein if (rx_byte == '\n' || rx_index >= 255) { rx_buffer[rx_index] = '\0'; // Terminer la chaine // Traiter la commande recue... rx_index = 0; } // Relancer la reception HAL_UART_Receive_IT(&huart2, &rx_byte, 1); } }
9.7 Fonction printf via UART
Il est pratique de rediriger printf() vers l'UART pour le debug :
/* Redirection de printf vers UART2 */ /* Ajouter dans main.c ou syscalls.c */ #include <stdio.h> // Necessaire pour la redirection int __io_putchar(int ch) { HAL_UART_Transmit(&huart2, (uint8_t*)&ch, 1, 100); return ch; } int _write(int file, char *ptr, int len) { HAL_UART_Transmit(&huart2, (uint8_t*)ptr, len, 1000); return len; } /* Utilisation */ int valeur = 42; float tension = 3.14; printf("Valeur: %d\r\n", valeur); printf("Tension: %.2f V\r\n", tension); printf("ADC: %04X\r\n", adc_value); // Hexadecimal
\r\n (Carriage Return + Line Feed) pour assurer la compatibilite avec tous les terminaux serie (Windows, Linux, Mac).
Chapitre 10 : Interface I2C
Bus de communication multi-maitres/multi-esclaves
🎯 Objectifs du chapitre
- Comprendre le protocole I2C et son fonctionnement
- Maitriser l'adressage et le format des trames
- Configurer l'I2C du STM32F4
- Communiquer avec des peripheriques I2C
10.1 Presentation du Bus I2C
L'I2C (Inter-Integrated Circuit), invente par Philips, est un bus serie synchrone bidirectionnel utilisant seulement 2 fils. Il permet de connecter plusieurs peripheriques sur le meme bus.
2 fils
SDA (donnees) + SCL (horloge)
127 adresses
7 bits (ou 1024 en 10 bits)
Caracteristiques principales
- Synchrone : Horloge partagee (SCL) generee par le maitre
- Multi-maitres : Plusieurs maitres possibles sur le bus
- Multi-esclaves : Jusqu'a 127 peripheriques (adressage 7 bits)
- Bidirectionnel : Meme ligne pour lecture et ecriture
- Open-drain : Necessite des resistances pull-up
┌─────────────────────────────────────────────────────────────────────────┐
│ TOPOLOGIE BUS I2C │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ VCC (3.3V) │
│ │ │ │
│ ┌┴┐┌┴┐ │
│ 4.7kΩ │ ││ │ 4.7kΩ (Resistances Pull-up) │
│ └┬┘└┬┘ │
│ ┌──────────────┼──┼──────────────┬────────────────┐ │
│ SDA ─────┤ │ │ │ │ │
│ │ │ │ │ │ │
│ SCL ─────┼──────────────┼──┤ │ │ │
│ │ │ │ │ │ │
│ ┌────┴────┐ ┌────┴──┴───┐ ┌────┴────┐ ┌──────┴─────┐ │
│ │ MAÎTRE │ │ ESCLAVE │ │ ESCLAVE │ │ ESCLAVE │ │
│ │ STM32 │ │ 0x3C │ │ 0x50 │ │ 0x68 │ │
│ │ │ │ (OLED) │ │ (EEPROM)│ │ (MPU6050)│ │
│ └─────────┘ └───────────┘ └─────────┘ └────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
10.2 Vitesses de Communication
| Mode | Vitesse SCL | Usage |
|---|---|---|
| Standard Mode | 100 kHz | Capteurs, EEPROM, compatible tous |
| Fast Mode | 400 kHz | Usage courant, bon compromis |
| Fast Mode Plus | 1 MHz | Applications rapides |
| High Speed Mode | 3.4 MHz | Haute performance |
10.3 Protocole et Format des Trames
┌─────────────────────────────────────────────────────────────────────────┐
│ TRAME I2C - ECRITURE │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ │START│ ADRESSE 7 bits │R/W│ACK│ DATA │ACK│ DATA │ACK│STOP│ │
│ │ S │ A6 A5 A4 A3 A2 A1 A0│ 0 │ A │ D7...D0 │ A │ D7...D0 │ A │ P │ │
│ │
│ START : SDA passe a LOW pendant que SCL est HIGH │
│ STOP : SDA passe a HIGH pendant que SCL est HIGH │
│ R/W : 0 = Ecriture (Master → Slave), 1 = Lecture (Slave → Master) │
│ ACK : 0 = Acknowledged (OK), 1 = NACK (erreur ou fin) │
│ │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ Exemple : Ecrire 0x55 a l'adresse 0x3C │
│ │
│ START │ 0 0 1 1 1 1 0 │ 0 │ACK│ 0 1 0 1 0 1 0 1 │ACK│ STOP │
│ │ 0x3C (7 bits) │ W │ │ 0x55 │ │ │
│ │
│ Note: L'adresse envoyee est (0x3C << 1) | 0 = 0x78 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Sequence typique d'ecriture
- Maitre genere condition START
- Maitre envoie adresse esclave + bit R/W = 0 (ecriture)
- Esclave repond ACK
- Maitre envoie donnees octet par octet
- Esclave repond ACK apres chaque octet
- Maitre genere condition STOP
Sequence typique de lecture
- Maitre genere START + adresse + W (pour envoyer registre)
- Maitre envoie adresse du registre a lire
- Maitre genere REPEATED START + adresse + R (lecture)
- Esclave envoie les donnees
- Maitre repond ACK (continuer) ou NACK (arreter)
- Maitre genere STOP
10.4 Configuration I2C STM32F4
/* Configuration I2C1 sur PB6 (SCL) et PB7 (SDA) */ I2C_HandleTypeDef hi2c1; void MX_I2C1_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; // Activer les horloges __HAL_RCC_I2C1_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); // Configurer PB6 (SCL) et PB7 (SDA) en Open-Drain GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7; GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; // Open-Drain obligatoire! GPIO_InitStruct.Pull = GPIO_PULLUP; // Pull-up interne GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Alternate = GPIO_AF4_I2C1; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); // Configuration I2C hi2c1.Instance = I2C1; hi2c1.Init.ClockSpeed = 100000; // 100 kHz Standard Mode hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; hi2c1.Init.OwnAddress1 = 0; // Adresse si esclave hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; HAL_I2C_Init(&hi2c1); }
10.5 Communication I2C avec HAL
/* Fonctions I2C principales */ #define DEVICE_ADDR 0x3C // Adresse 7 bits du peripherique /* Ecrire des donnees vers un esclave */ uint8_t tx_data[] = {0x00, 0xAE}; // [registre, valeur] HAL_I2C_Master_Transmit(&hi2c1, DEVICE_ADDR << 1, // Decalage a gauche! tx_data, 2, // 2 octets 100); // Timeout 100ms /* Lire des donnees depuis un esclave */ uint8_t rx_data[6]; HAL_I2C_Master_Receive(&hi2c1, DEVICE_ADDR << 1 | 0x01, // Bit R/W = 1 rx_data, 6, // 6 octets 100); /* Ecrire dans un registre specifique */ uint8_t reg_addr = 0x20; uint8_t value = 0x77; HAL_I2C_Mem_Write(&hi2c1, DEVICE_ADDR << 1, reg_addr, // Adresse du registre I2C_MEMADD_SIZE_8BIT, // Taille adresse: 8 bits &value, 1, // 1 octet 100); /* Lire un registre specifique */ uint8_t temp_data[2]; HAL_I2C_Mem_Read(&hi2c1, DEVICE_ADDR << 1, 0x00, // Registre a lire I2C_MEMADD_SIZE_8BIT, temp_data, 2, // 2 octets 100); /* Verifier si un peripherique est present */ if (HAL_I2C_IsDeviceReady(&hi2c1, DEVICE_ADDR << 1, 3, 100) == HAL_OK) { // Peripherique detecte a l'adresse DEVICE_ADDR }
<< 1.
10.6 Scanner I2C
Utile pour trouver les adresses des peripheriques connectes :
/* Fonction pour scanner le bus I2C */ void I2C_Scanner(void) { uint8_t devices_found = 0; printf("Scanning I2C bus...\r\n"); for (uint8_t addr = 0x08; addr < 0x78; addr++) { if (HAL_I2C_IsDeviceReady(&hi2c1, addr << 1, 1, 10) == HAL_OK) { printf("Device found at 0x%02X\r\n", addr); devices_found++; } } printf("Scan complete. %d device(s) found.\r\n", devices_found); }
Adresses I2C courantes
| Adresse | Peripherique |
|---|---|
| 0x3C / 0x3D | Ecran OLED SSD1306 |
| 0x50 - 0x57 | EEPROM 24Cxx |
| 0x68 / 0x69 | MPU6050, DS1307 RTC |
| 0x76 / 0x77 | BME280, BMP280 |
| 0x27 / 0x3F | LCD I2C PCF8574 |
| 0x48 - 0x4B | ADS1115 ADC |
Chapitre 11 : Interface SPI
Communication serie synchrone haute vitesse
🎯 Objectifs du chapitre
- Comprendre le fonctionnement du bus SPI
- Maitriser les modes de polarite et phase (CPOL/CPHA)
- Configurer le SPI du STM32F4
- Communiquer avec des peripheriques SPI
11.1 Presentation du Bus SPI
Le SPI (Serial Peripheral Interface) est un bus serie synchrone full-duplex developpe par Motorola. C'est le protocole le plus rapide des bus serie couramment utilises.
4 fils
MOSI, MISO, SCK, CS
Tres rapide
Jusqu'a 50+ MHz
Full-duplex
TX et RX simultanes
Signaux SPI
| Signal | Nom complet | Direction (Maitre) | Description |
|---|---|---|---|
| MOSI | Master Out Slave In | Sortie → | Donnees du maitre vers l'esclave |
| MISO | Master In Slave Out | ← Entree | Donnees de l'esclave vers le maitre |
| SCK/SCLK | Serial Clock | Sortie → | Horloge generee par le maitre |
| CS/SS/NSS | Chip Select / Slave Select | Sortie → | Selection de l'esclave (actif bas) |
┌─────────────────────────────────────────────────────────────────────────┐
│ TOPOLOGIE BUS SPI │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ │
│ │ MAÎTRE │ │
│ │ (STM32) │ │
│ └──────┬───────┘ │
│ │ │
│ ┌───────────────┼───────────────┬───────────────┐ │
│ │ │ │ │ │
│ MOSI MISO SCK CS0 CS1 CS2 │
│ │ │ │ │ │ │ │
│ │ ┌──────────┼───────────────┼─────────┤ │ │ │
│ ▼ │ │ │ │ │ │ │
│ ──┬────┼──────────┼───────────────┼─────────┼────┼────┼── │
│ │ │ │ │ │ │ │ │
│ ┌────┴────┴───┐ ┌────┴────┴───┐ ┌────┴────┴───┐ │
│ │ ESCLAVE 1 │ │ ESCLAVE 2 │ │ ESCLAVE 3 │ │
│ │ (Flash) │ │ (ADC) │ │ (LCD) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ Note: Un seul CS actif (LOW) a la fois pour selectionner l'esclave │
│ │
└─────────────────────────────────────────────────────────────────────────┘
11.2 Modes SPI (CPOL/CPHA)
Le SPI definit 4 modes de fonctionnement bases sur la polarite de l'horloge (CPOL) et la phase d'echantillonnage (CPHA) :
| Mode | CPOL | CPHA | Horloge au repos | Echantillonnage |
|---|---|---|---|---|
| Mode 0 | 0 | 0 | LOW | Front montant |
| Mode 1 | 0 | 1 | LOW | Front descendant |
| Mode 2 | 1 | 0 | HIGH | Front descendant |
| Mode 3 | 1 | 1 | HIGH | Front montant |
MODE 0 (CPOL=0, CPHA=0) - Le plus courant
─────────────────────────────────────────
SCK ____┌──┐__┌──┐__┌──┐__┌──┐__┌──┐__┌──┐__┌──┐__┌──┐____
│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
MOSI/ ────X──┴──X──┴──X──┴──X──┴──X──┴──X──┴──X──┴──X──┴────
MISO D7 D6 D5 D4 D3 D2 D1 D0
▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲
│ │ │ │ │ │ │ │
Echantillonnage sur front MONTANT
MODE 3 (CPOL=1, CPHA=1)
─────────────────────────────────────────
SCK ────┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌────
└──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘
MOSI/ ────X──┴──X──┴──X──┴──X──┴──X──┴──X──┴──X──┴──X──┴────
MISO D7 D6 D5 D4 D3 D2 D1 D0
▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲
│ │ │ │ │ │ │ │
Echantillonnage sur front MONTANT
11.3 Configuration SPI STM32F4
/* Configuration SPI1 - Mode Master */ /* PA5=SCK, PA6=MISO, PA7=MOSI, PA4=CS (GPIO manuel) */ SPI_HandleTypeDef hspi1; void MX_SPI1_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; // Activer les horloges __HAL_RCC_SPI1_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); // Configurer PA5 (SCK), PA6 (MISO), PA7 (MOSI) en AF GPIO_InitStruct.Pin = GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF5_SPI1; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // Configurer PA4 (CS) en sortie GPIO GPIO_InitStruct.Pin = GPIO_PIN_4; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // CS desactive au depart (HIGH) HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); // Configuration SPI hspi1.Instance = SPI1; hspi1.Init.Mode = SPI_MODE_MASTER; hspi1.Init.Direction = SPI_DIRECTION_2LINES; // Full duplex hspi1.Init.DataSize = SPI_DATASIZE_8BIT; hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; // CPOL = 0 hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; // CPHA = 0 hspi1.Init.NSS = SPI_NSS_SOFT; // CS manuel hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16; // ~5 MHz hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; hspi1.Init.TIMode = SPI_TIMODE_DISABLE; hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; HAL_SPI_Init(&hspi1); }
Calcul du Baudrate SPI
/* SPI1 est sur APB2 (84 MHz max) */ f_SPI = f_APB2 / Prescaler Prescaler = 2, 4, 8, 16, 32, 64, 128, 256 // Exemples avec APB2 = 84 MHz SPI_BAUDRATEPRESCALER_2 → 42 MHz SPI_BAUDRATEPRESCALER_4 → 21 MHz SPI_BAUDRATEPRESCALER_8 → 10.5 MHz SPI_BAUDRATEPRESCALER_16 → 5.25 MHz SPI_BAUDRATEPRESCALER_32 → 2.625 MHz
11.4 Communication SPI avec HAL
/* Macros pour le Chip Select */ #define CS_LOW() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET) #define CS_HIGH() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET) /* Transmission seule */ uint8_t tx_data[] = {0x9F}; // Commande CS_LOW(); HAL_SPI_Transmit(&hspi1, tx_data, 1, 100); CS_HIGH(); /* Reception seule */ uint8_t rx_data[4]; CS_LOW(); HAL_SPI_Receive(&hspi1, rx_data, 4, 100); CS_HIGH(); /* Transmission et reception simultanees (Full Duplex) */ uint8_t tx_buf[4] = {0x9F, 0x00, 0x00, 0x00}; uint8_t rx_buf[4]; CS_LOW(); HAL_SPI_TransmitReceive(&hspi1, tx_buf, rx_buf, 4, 100); CS_HIGH(); /* Exemple: Lire ID d'une memoire Flash SPI */ uint8_t Flash_ReadID(void) { uint8_t cmd = 0x9F; // Commande JEDEC ID uint8_t id[3]; CS_LOW(); HAL_SPI_Transmit(&hspi1, &cmd, 1, 100); HAL_SPI_Receive(&hspi1, id, 3, 100); CS_HIGH(); // id[0] = Manufacturer, id[1] = Type, id[2] = Capacity return id[0]; }
11.5 Comparaison SPI vs I2C
| Caracteristique | SPI | I2C |
|---|---|---|
| Nombre de fils | 4 (MOSI, MISO, SCK, CS) | 2 (SDA, SCL) |
| Vitesse max | ~50 MHz et plus | 3.4 MHz (High Speed) |
| Duplex | Full duplex | Half duplex |
| Adressage | Par ligne CS (1 par esclave) | 7/10 bits (127/1024 adresses) |
| Multi-maitres | Complexe a implementer | Natif avec arbitrage |
| Complexite | Simple (pas de protocole) | Plus complexe (ACK, adresses) |
| Consommation | Plus elevee | Plus faible |
| Distance | Courte (~10 cm) | Moyenne (~1 m) |
| Usage typique | Flash, SD Card, LCD, ADC rapides | Capteurs, EEPROM, OLED |
Chapitre 12 : Bus CAN
Controller Area Network - Communication automobile et industrielle
🎯 Objectifs du chapitre
- Comprendre l'architecture et le principe du bus CAN
- Identifier la connectique et les niveaux electriques
- Maitriser la structure des trames de donnees et de controle
- Connaitre l'identifiant, l'arbitrage et le protocole d'echange
12.1 Introduction au Bus CAN
Le CAN (Controller Area Network) est un protocole de communication serie developpe par Bosch dans les annees 1980 pour l'industrie automobile. Il est devenu un standard ISO (ISO 11898) utilise dans de nombreux domaines.
Caracteristiques principales
2 fils
CAN_H et CAN_L (differentiel)
1 Mbps
Vitesse max (High Speed)
Multi-maitres
Tous les noeuds peuvent emettre
- Robuste : Transmission differentielle, immunite au bruit
- Fiable : Detection d'erreurs integree (CRC, ACK, bit stuffing)
- Deterministe : Arbitrage non destructif base sur la priorite
- Broadcast : Tous les noeuds recoivent tous les messages
- Distance : Jusqu'a 1 km a 50 kbps, 40 m a 1 Mbps
Applications du CAN
- Automobile : Moteur, ABS, airbag, tableau de bord, OBD-II
- Industriel : CANopen, DeviceNet (automates, capteurs)
- Medical : Equipements hospitaliers
- Aeronautique : Avionique
- Marine : NMEA 2000 (navigation)
12.2 Architecture et Connectique
┌─────────────────────────────────────────────────────────────────────────┐
│ TOPOLOGIE BUS CAN │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ Terminaison Terminaison │
│ 120Ω 120Ω │
│ ┌───┐ ┌───┐ │
│ ───┤ ├──┬───────┬───────┬───────┬───────┬───────┬──────┤ ├─── │
│ └───┘ │ │ │ │ │ │ └───┘ │
│ CAN_H ────┼───────┼───────┼───────┼───────┼───────┼───────────── │
│ │ │ │ │ │ │ │
│ CAN_L ────┼───────┼───────┼───────┼───────┼───────┼───────────── │
│ │ │ │ │ │ │ │
│ ┌──┴──┐ ┌──┴──┐ ┌──┴──┐ ┌──┴──┐ ┌──┴──┐ ┌──┴──┐ │
│ │Node1│ │Node2│ │Node3│ │Node4│ │Node5│ │Node6│ │
│ │ ECU │ │Capt.│ │Motor│ │Dash │ │ ABS │ │Airbag│ │
│ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ │
│ │
│ Note: Resistances de terminaison 120Ω aux deux extremites │
│ Cable torsade, longueur totale depend du debit │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Niveaux electriques (CAN High Speed - ISO 11898-2)
| Etat | CAN_H | CAN_L | Difference (CAN_H - CAN_L) |
|---|---|---|---|
| Recessif (1) | 2.5 V | 2.5 V | 0 V |
| Dominant (0) | 3.5 V | 1.5 V | 2 V |
Tension
│
3.5V├──────────────────────┐
│ CAN_H │ CAN_H
2.5V├──────┐ ┌───────┴───────┐ ┌───────
│ │ │ │ │
1.5V├──────┴───────┘ └───────┴───────
│ CAN_L CAN_L
│
└──────────────────────────────────────────────▶ Temps
│ │ │
Dominant Recessif Dominant
(0) (1) (0)
12.3 Structure des Trames CAN
Le protocole CAN definit plusieurs types de trames. La plus importante est la trame de donnees :
Trame de Donnees (Data Frame)
┌─────────────────────────────────────────────────────────────────────────┐
│ TRAME DE DONNEES CAN 2.0A (Standard) │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ │SOF│ IDENTIFIANT │RTR│IDE│r0│ DLC │ DATA (0-8 octets) │ CRC │
│ │ 1 │ 11 bits │ 1 │ 1 │1 │ 4 bits│ 0-64 bits │15+1+1 │
│ │
│ │ACK│ EOF │ IFS │ │
│ │ 2 │ 7 │ 3 │ │
│ │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ SOF : Start Of Frame (bit dominant, synchronisation) │
│ ID : Identifiant du message (11 bits = 0-2047, definit la priorite) │
│ RTR : Remote Transmission Request (0=Data, 1=Remote) │
│ IDE : Identifier Extension (0=Standard 11 bits, 1=Extended 29 bits) │
│ r0 : Reserve (dominant) │
│ DLC : Data Length Code (0-8, nombre d'octets de donnees) │
│ DATA: Donnees utiles (0 a 8 octets) │
│ CRC : Cyclic Redundancy Check (15 bits + delimiteur) │
│ ACK : Acknowledgement (2 bits, confirme par les recepteurs) │
│ EOF : End Of Frame (7 bits recessifs) │
│ IFS : Inter-Frame Space (3 bits, espacement entre trames) │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Trame Etendue CAN 2.0B
La version etendue utilise un identifiant de 29 bits au lieu de 11 bits, permettant plus de messages uniques (2^29 = 536 millions).
Autres types de trames
| Type | Description |
|---|---|
| Data Frame | Trame de donnees (0-8 octets) |
| Remote Frame | Demande de donnees (pas de champ DATA) |
| Error Frame | Signale une erreur detectee |
| Overload Frame | Demande de delai entre trames |
12.4 Identifiant et Arbitrage
L'identifiant joue deux roles fondamentaux :
- Identification du message : Il identifie le type de donnees (ex: vitesse moteur, temperature...)
- Priorite : Plus l'ID est bas, plus la priorite est haute
Mecanisme d'arbitrage non destructif
Quand plusieurs noeuds emettent simultanement, l'arbitrage se fait bit a bit :
Arbitrage bit a bit
Bus CAN ────────────────────────────────────────────────
Noeud A ID = 0x100 = 001 0000 0000
(ID:0x100) Bit: 0 0 1 ←── Perd l'arbitrage (lit 0, a envoye 1)
↓ ↓ ↓
─────┬───┬───┬───
│ 0 │ 0 │ 1 │ ← Continue a lire, arrete d'emettre
└───┴───┴───┘
Noeud B ID = 0x080 = 000 1000 0000
(ID:0x080) Bit: 0 0 0 ←── Gagne (ID plus bas = prioritaire)
↓ ↓ ↓
─────┬───┬───┬───
│ 0 │ 0 │ 0 │ ← Continue a emettre
└───┴───┴───┘
Bus reel: ─────┬───┬───┬───
│ 0 │ 0 │ 0 │ (Dominant gagne sur recessif)
└───┴───┴───┘
→ Le bit DOMINANT (0) l'emporte toujours sur le bit RECESSIF (1)
→ L'ID le plus bas est donc le plus prioritaire
12.5 Protocole d'Echange et Filtrage
Communication Broadcast
En CAN, tous les noeuds recoivent tous les messages. Chaque noeud decide localement quels messages il accepte grace aux filtres d'acceptance.
┌─────────────────────────────────────────────────────────────────────────┐
│ FILTRAGE DES MESSAGES CAN │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ Emetteur envoie: ID = 0x123, Data = "Temperature = 25°C" │
│ │
│ ─────────────────────────────────────────────────────────────── │
│ │ │ │ │ │
│ ┌──┴──┐ ┌──┴──┐ ┌──┴──┐ ┌──┴──┐ │
│ │Node1│ │Node2│ │Node3│ │Node4│ │
│ │Filtre│ │Filtre│ │Filtre│ │Filtre│ │
│ │0x1xx│ │0x200│ │0x123│ │0x4xx│ │
│ └──┬──┘ └──┬──┘ └──┬──┘ └──┬──┘ │
│ │ │ │ │ │
│ ✓ ✗ ✓ ✗ │
│ Accepte Rejete Accepte Rejete │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Detection d'erreurs
Le CAN integre 5 mecanismes de detection d'erreurs :
- Bit Error : Difference entre bit emis et bit lu
- Stuff Error : Plus de 5 bits consecutifs identiques
- CRC Error : Erreur de checksum
- Form Error : Violation du format de trame
- ACK Error : Pas d'acquittement recu
12.6 Configuration CAN STM32F4
/* Configuration CAN1 sur PA11 (RX) et PA12 (TX) */ /* Necessite un transceiver externe (MCP2551, TJA1050...) */ CAN_HandleTypeDef hcan1; CAN_FilterTypeDef canFilter; void MX_CAN1_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; // Activer les horloges __HAL_RCC_CAN1_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); // Configurer PA11 (RX) et PA12 (TX) GPIO_InitStruct.Pin = GPIO_PIN_11 | GPIO_PIN_12; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Alternate = GPIO_AF9_CAN1; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // Configuration CAN - 500 kbps (APB1 = 42 MHz) // Baudrate = APB1 / (Prescaler × (1 + BS1 + BS2)) // 500k = 42M / (6 × (1 + 7 + 6)) = 42M / 84 = 500 kbps hcan1.Instance = CAN1; hcan1.Init.Prescaler = 6; hcan1.Init.Mode = CAN_MODE_NORMAL; hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ; hcan1.Init.TimeSeg1 = CAN_BS1_7TQ; hcan1.Init.TimeSeg2 = CAN_BS2_6TQ; hcan1.Init.TimeTriggeredMode = DISABLE; hcan1.Init.AutoBusOff = ENABLE; hcan1.Init.AutoWakeUp = DISABLE; hcan1.Init.AutoRetransmission = ENABLE; hcan1.Init.ReceiveFifoLocked = DISABLE; hcan1.Init.TransmitFifoPriority = DISABLE; HAL_CAN_Init(&hcan1); // Configuration du filtre (accepter tous les messages) canFilter.FilterBank = 0; canFilter.FilterMode = CAN_FILTERMODE_IDMASK; canFilter.FilterScale = CAN_FILTERSCALE_32BIT; canFilter.FilterIdHigh = 0x0000; canFilter.FilterIdLow = 0x0000; canFilter.FilterMaskIdHigh = 0x0000; canFilter.FilterMaskIdLow = 0x0000; canFilter.FilterFIFOAssignment = CAN_RX_FIFO0; canFilter.FilterActivation = ENABLE; HAL_CAN_ConfigFilter(&hcan1, &canFilter); // Demarrer le CAN HAL_CAN_Start(&hcan1); }
12.7 Emission et Reception CAN
/* Envoi d'un message CAN */ CAN_TxHeaderTypeDef TxHeader; uint8_t TxData[8]; uint32_t TxMailbox; void CAN_SendMessage(uint16_t id, uint8_t *data, uint8_t len) { TxHeader.StdId = id; // Identifiant standard 11 bits TxHeader.ExtId = 0; // Non utilise en mode standard TxHeader.IDE = CAN_ID_STD; // Format standard TxHeader.RTR = CAN_RTR_DATA; // Trame de donnees TxHeader.DLC = len; // Nombre d'octets (0-8) TxHeader.TransmitGlobalTime = DISABLE; for (int i = 0; i < len; i++) { TxData[i] = data[i]; } HAL_CAN_AddTxMessage(&hcan1, &TxHeader, TxData, &TxMailbox); } /* Reception d'un message CAN */ CAN_RxHeaderTypeDef RxHeader; uint8_t RxData[8]; void CAN_ReceiveMessage(void) { if (HAL_CAN_GetRxFifoFillLevel(&hcan1, CAN_RX_FIFO0) > 0) { HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &RxHeader, RxData); printf("CAN Rx: ID=0x%03lX, DLC=%d, Data=", RxHeader.StdId, RxHeader.DLC); for (int i = 0; i < RxHeader.DLC; i++) { printf("%02X ", RxData[i]); } printf("\r\n"); } } /* Exemple d'utilisation */ uint8_t speed_data[2] = {0x00, 0x50}; // Vitesse = 80 km/h CAN_SendMessage(0x123, speed_data, 2);
12.8 Resume Comparatif des Protocoles
| Caracteristique | UART | I2C | SPI | CAN |
|---|---|---|---|---|
| Fils | 2 (TX, RX) | 2 (SDA, SCL) | 4 (MOSI, MISO, SCK, CS) | 2 (CAN_H, CAN_L) |
| Synchrone | Non | Oui | Oui | Oui |
| Duplex | Full | Half | Full | Half |
| Vitesse max | ~1 Mbps | 3.4 MHz | 50+ MHz | 1 Mbps |
| Distance | ~15 m (RS232) | ~1 m | ~10 cm | 1 km |
| Topologie | Point a point | Bus (127 max) | Point a multipoint | Bus multi-maitres |
| Detection erreur | Parite | ACK | Non | CRC, ACK, 5 types |
| Usage | Debug, GPS | Capteurs, EEPROM | Flash, LCD rapide | Automobile, industrie |