Microcontroleur STM32F4

Cours Complet - Systemes Embarques

🎛️ STM32F4xx ⚡ ARM Cortex-M4 📚 Cours: 48h | TP: 24h
🌐

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

📖
Definition Un systeme embarque (embedded system) est un systeme electronique et informatique autonome, dedie a une tache specifique, souvent en temps reel, integre au sein d'un equipement plus large. Il combine du materiel (hardware) et du logiciel (software) pour realiser une fonction precise.

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
💡
Regle pratique Pour une application embarquee, on privilegie un microcontroleur car il integre tout le necessaire sur une seule puce : processeur, memoire, et peripheriques. Cela reduit le cout, la taille du circuit, et la consommation energetique.

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
🎯
Focus du cours : STM32F4 Ce cours se concentre sur la famille STM32F4, basee sur le coeur ARM Cortex-M4 avec unite de calcul flottant (FPU). C'est la gamme haute performance la plus utilisee dans l'industrie et l'enseignement.

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
📖
FPU (Floating Point Unit) L'unite de calcul en virgule flottante permet d'effectuer des operations sur des nombres decimaux (float) directement en materiel, beaucoup plus rapidement qu'en logiciel. Indispensable pour le traitement du signal, les calculs scientifiques, et le controle moteur.
📖
DSP (Digital Signal Processing) Les instructions DSP permettent d'effectuer des operations de traitement du signal (filtrage, FFT, etc.) de maniere optimisee : multiplication-accumulation (MAC), operations SIMD sur des donnees 16 bits empaquetees.

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 :

OffsetVecteurDescription
0x0000Initial SPValeur initiale du Stack Pointer
0x0004ResetAdresse du handler Reset
0x0008NMINon-Maskable Interrupt
0x000CHardFaultErreur materielle grave
0x0010MemManageErreur de protection memoire
0x0014BusFaultErreur de bus
0x0018UsageFaultInstruction invalide
0x002CSVCallAppel systeme (SVC)
0x0038PendSVPending Service Call
0x003CSysTickTimer 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               │
└──────────────┴─────────────┴────────────────────────────────────────┘
                    
💡
Adresses importantes a retenir
  • 0x08000000 : Debut de la Flash (programme)
  • 0x20000000 : Debut de la SRAM (donnees)
  • 0x40000000 : Debut des peripheriques
  • 0xE0000000 : 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

SourceNomFrequenceCaracteristiques
HSIHigh Speed Internal16 MHzRC interne, moins precis, demarrage rapide
HSEHigh Speed External4-26 MHzQuartz externe, tres precis, utilise pour PLL
LSILow Speed Internal32 kHzRC interne, pour watchdog et RTC
LSELow Speed External32.768 kHzQuartz externe, RTC precis
PLLPhase Locked LoopJusqu'a 180 MHzMultiplie 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 obligatoire des horloges Avant d'utiliser tout peripherique, il faut obligatoirement activer son horloge via le registre RCC. Sans cela, les registres du peripherique ne repondront pas.
/* 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 :

BOOT1BOOT0Mode de demarrageDescription
X0Main FlashDemarre depuis la Flash utilisateur (normal)
01System MemoryDemarre le bootloader ST (pour programmation)
11Embedded SRAMDemarre 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

  1. Selection du MCU : Choisir la reference exacte (ex: STM32F407VGT6)
  2. Configuration du Pinout : Assigner les fonctions aux broches
  3. Configuration de l'horloge : Clock Configuration (Clock Tree)
  4. Configuration des peripheriques : Parametres de chaque module
  5. Generation du code : Projet complet avec initialisation

Onglets principaux de CubeMX

OngletFonction
Pinout & ConfigurationVue du boitier, affectation des pins, configuration des peripheriques
Clock ConfigurationArbre d'horloge graphique, configuration PLL
Project ManagerNom du projet, IDE cible, options de generation
ToolsCalcul 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 */
    /* ... */
}
⚠️
Regle cruciale : USER CODE Ecrivez uniquement entre les balises /* 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

FonctionDescription
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

RaccourciAction
Ctrl+BCompiler le projet (Build)
F11Debuguer (Debug)
Ctrl+F11Executer (Run)
F5Continuer (pendant debug)
F6Step Over (instruction suivante)
F7Step Into (entrer dans fonction)
Ctrl+Shift+BAjouter/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 :

RegistreNomTailleDescription
GPIOx_MODERMode32 bits2 bits/pin : Input(00), Output(01), AF(10), Analog(11)
GPIOx_OTYPEROutput Type16 bits1 bit/pin : Push-Pull(0), Open-Drain(1)
GPIOx_OSPEEDROutput Speed32 bits2 bits/pin : Low(00), Medium(01), High(10), VHigh(11)
GPIOx_PUPDRPull-up/Pull-down32 bits2 bits/pin : None(00), Pull-up(01), Pull-down(10)
GPIOx_IDRInput Data16 bitsLecture seule : etat des entrees
GPIOx_ODROutput Data16 bitsLecture/ecriture : etat des sorties
GPIOx_BSRRBit Set/Reset32 bitsEcriture atomique : bits [15:0]=set, [31:16]=reset
GPIOx_AFRL/HAlternate Function2×32 bits4 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);
    }
}
💡
Anti-rebond (Debouncing) Les boutons mecaniques generent des rebonds (multiple transitions). Utilisez un delai ou un timer pour filtrer les rebonds : 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 :

TypeTimersBitsCanauxFonctionnalites
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.

ConstanteCyclesTemps @21MHzUsage
ADC_SAMPLETIME_3CYCLES30.14 µsSource basse impedance
ADC_SAMPLETIME_15CYCLES150.71 µsUsage general
ADC_SAMPLETIME_28CYCLES281.33 µsUsage general
ADC_SAMPLETIME_84CYCLES844.0 µsHaute impedance
ADC_SAMPLETIME_480CYCLES48022.9 µsTres 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.

BaudrateBits/sTemps par bitUsage typique
96009600 bps104 µsApplications lentes, GPS
1920019200 bps52 µsUsage general
3840038400 bps26 µsUsage general
5760057600 bps17 µsModems
115200115200 bps8.7 µsDebug, standard
230400230400 bps4.3 µsHaute vitesse
921600921600 bps1.1 µsTres 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.

CaracteristiqueTTL (STM32)RS232
Niveau logique HIGH3.3V-3V a -15V
Niveau logique LOW0V+3V a +15V
Distance max~1 m15 m
Debit maxPlusieurs Mbps~115 kbps
⚠️
Adaptateur necessaire Pour connecter un STM32 (niveaux 3.3V) a un port RS232 (niveaux ±12V), il faut un convertisseur de niveau comme le MAX232 ou MAX3232. Ne jamais connecter directement sous peine de detruire le microcontroleur !

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)

USARTTXRXBusAF
USART1PA9PA10APB2AF7
USART2PA2PA3APB1AF7
USART3PB10PB11APB1AF7
USART6PC6PC7APB2AF8

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 pour le retour a la ligne Utilisez \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

ModeVitesse SCLUsage
Standard Mode100 kHzCapteurs, EEPROM, compatible tous
Fast Mode400 kHzUsage courant, bon compromis
Fast Mode Plus1 MHzApplications rapides
High Speed Mode3.4 MHzHaute performance
💡
Resistances Pull-up Les resistances pull-up sont obligatoires car les lignes sont en Open-Drain. Valeurs typiques : 4.7 kΩ pour 100-400 kHz, 2.2 kΩ pour les vitesses superieures. Certaines cartes de developpement les incluent deja.

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

  1. Maitre genere condition START
  2. Maitre envoie adresse esclave + bit R/W = 0 (ecriture)
  3. Esclave repond ACK
  4. Maitre envoie donnees octet par octet
  5. Esclave repond ACK apres chaque octet
  6. Maitre genere condition STOP

Sequence typique de lecture

  1. Maitre genere START + adresse + W (pour envoyer registre)
  2. Maitre envoie adresse du registre a lire
  3. Maitre genere REPEATED START + adresse + R (lecture)
  4. Esclave envoie les donnees
  5. Maitre repond ACK (continuer) ou NACK (arreter)
  6. 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
}
⚠️
Decalage de l'adresse La HAL STM32 attend l'adresse sur 8 bits (adresse 7 bits decalee a gauche + bit R/W). Multipliez toujours l'adresse 7 bits par 2 ou utilisez << 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

AdressePeripherique
0x3C / 0x3DEcran OLED SSD1306
0x50 - 0x57EEPROM 24Cxx
0x68 / 0x69MPU6050, DS1307 RTC
0x76 / 0x77BME280, BMP280
0x27 / 0x3FLCD I2C PCF8574
0x48 - 0x4BADS1115 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

SignalNom completDirection (Maitre)Description
MOSIMaster Out Slave InSortie →Donnees du maitre vers l'esclave
MISOMaster In Slave Out← EntreeDonnees de l'esclave vers le maitre
SCK/SCLKSerial ClockSortie →Horloge generee par le maitre
CS/SS/NSSChip Select / Slave SelectSortie →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) :

ModeCPOLCPHAHorloge au reposEchantillonnage
Mode 000LOWFront montant
Mode 101LOWFront descendant
Mode 210HIGHFront descendant
Mode 311HIGHFront 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
                    
💡
Mode le plus courant Le Mode 0 (CPOL=0, CPHA=0) est le plus utilise. Consultez toujours la datasheet du peripherique pour connaitre le mode requis.

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

CaracteristiqueSPII2C
Nombre de fils4 (MOSI, MISO, SCK, CS)2 (SDA, SCL)
Vitesse max~50 MHz et plus3.4 MHz (High Speed)
DuplexFull duplexHalf duplex
AdressagePar ligne CS (1 par esclave)7/10 bits (127/1024 adresses)
Multi-maitresComplexe a implementerNatif avec arbitrage
ComplexiteSimple (pas de protocole)Plus complexe (ACK, adresses)
ConsommationPlus eleveePlus faible
DistanceCourte (~10 cm)Moyenne (~1 m)
Usage typiqueFlash, SD Card, LCD, ADC rapidesCapteurs, 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)

EtatCAN_HCAN_LDifference (CAN_H - CAN_L)
Recessif (1)2.5 V2.5 V0 V
Dominant (0)3.5 V1.5 V2 V
      Tension
        │
    3.5V├──────────────────────┐
        │      CAN_H           │       CAN_H
    2.5V├──────┐       ┌───────┴───────┐       ┌───────
        │      │       │               │       │
    1.5V├──────┴───────┘               └───────┴───────
        │      CAN_L           CAN_L
        │
        └──────────────────────────────────────────────▶ Temps
              │                │               │
            Dominant         Recessif       Dominant
              (0)              (1)            (0)
                    
⚠️
Transceiver CAN obligatoire Le STM32 possede un controleur CAN mais pas de transceiver. Il faut ajouter un circuit externe (MCP2551, SN65HVD230, TJA1050) pour convertir les niveaux logiques en niveaux differentiels CAN.

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

TypeDescription
Data FrameTrame de donnees (0-8 octets)
Remote FrameDemande de donnees (pas de champ DATA)
Error FrameSignale une erreur detectee
Overload FrameDemande 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
                    
📖
Arbitrage non destructif L'arbitrage CAN est dit "non destructif" car le message du noeud gagnant n'est pas altere. Les noeuds perdants se retirent et retentent automatiquement leur emission.

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

CaracteristiqueUARTI2CSPICAN
Fils2 (TX, RX)2 (SDA, SCL)4 (MOSI, MISO, SCK, CS)2 (CAN_H, CAN_L)
SynchroneNonOuiOuiOui
DuplexFullHalfFullHalf
Vitesse max~1 Mbps3.4 MHz50+ MHz1 Mbps
Distance~15 m (RS232)~1 m~10 cm1 km
TopologiePoint a pointBus (127 max)Point a multipointBus multi-maitres
Detection erreurPariteACKNonCRC, ACK, 5 types
UsageDebug, GPSCapteurs, EEPROMFlash, LCD rapideAutomobile, industrie

Cours Complet STM32F4 - Microcontroleur ARM Cortex-M4

Module S03 : Systemes Embarques | 12 Chapitres | Cours 48h + TP 24h