Garden of KnowledgeApplied Sciences › Computer Science › Hardware
February 25, 2026

Systèmes Embarqués

Un système embarqué est un système informatique spécialisé, intégré dans un équipement plus large pour remplir une fonction précise. À la différence d’un ordinateur général, il est contraint en ressources (mémoire, puissance, énergie) et souvent soumis à des exigences temps réel.

Caractéristiques fondamentales§

CaractéristiqueDescription
Ressources limitéesRAM en kilo-octets, Flash en mégaoctets
Temps réelRespect de contraintes temporelles strictes
FiabilitéFonctionnement continu, souvent sans maintenance humaine
Efficacité énergétiqueBatteries, harvesting, modes veille
Interaction matérielleGPIO, ADC, DAC, bus (UART, SPI, I2C, CAN)
Absence d’OS completBare-metal ou RTOS léger

Architecture d’un microcontrôleur§

Un microcontrôleur (MCU) intègre sur une seule puce le processeur, la mémoire et les périphériques.

┌─────────────────────────────────────────────────┐
│              MICROCONTRÔLEUR                     │
│                                                  │
│  ┌──────────┐   ┌──────────┐   ┌─────────────┐  │
│  │   CPU    │   │  Flash   │   │    RAM      │  │
│  │  Core    │   │ (code)   │   │  (données)  │  │
│  └────┬─────┘   │ 256KB    │   │  64KB       │  │
│       │         └──────────┘   └─────────────┘  │
│  ┌────┴──────────────────────────────────────┐   │
│  │              Bus interne (AHB/APB)        │   │
│  └───┬──────┬──────┬──────┬──────┬──────┬───┘   │
│     GPIO  UART   SPI   I2C  Timer  ADC   DMA     │
└─────────────────────────────────────────────────┘

ARM Cortex-M§

Architecture ARM Cortex-M domine le marché des MCUs (STM32, nRF52, RP2040, ESP32).

FamilleCaractéristiquesUsage
Cortex-M0/M0+Ultra-basse consommation, simpleCapteurs, IoT
Cortex-M332 bits, multiplicateur matérielApplications générales
Cortex-M4FPU, DSP, SIMDAudio, traitement signal
Cortex-M7Double issue, cache L1, TCMHaute performance embarquée
Cortex-M33TrustZone (isolation sécurisée)Sécurité IoT

Registres ARM Cortex-M :

Programmation bare-metal (C/C++)§

Sans système d’exploitation, le programme tourne directement sur le matériel.

Vecteur d’interruption et démarrage§

// startup.c — table des vecteurs d'interruption
__attribute__((section(".isr_vector")))
const uint32_t vector_table[] = {
    (uint32_t)&_estack,        // Adresse initiale du stack pointer
    (uint32_t)Reset_Handler,   // Handler de reset (point d'entrée)
    (uint32_t)NMI_Handler,
    (uint32_t)HardFault_Handler,
    // ... autres exceptions
    (uint32_t)SysTick_Handler, // Timer système
    // Interruptions périphériques
    (uint32_t)USART1_IRQHandler,
    (uint32_t)TIM2_IRQHandler,
};

void Reset_Handler(void) {
    // 1. Copier .data (variables initialisées) de Flash vers RAM
    // 2. Mettre .bss (variables non initialisées) à zéro
    // 3. Appeler main()
    SystemInit();
    main();
    while(1); // Ne doit jamais retourner
}

Manipulation de registres matériels§

#include <stdint.h>

// Accès direct aux registres (MMIO — Memory-Mapped I/O)
#define RCC_BASE    0x40021000U
#define GPIOA_BASE  0x48000000U

#define RCC_AHBENR  (*(volatile uint32_t*)(RCC_BASE + 0x14))
#define GPIOA_MODER (*(volatile uint32_t*)(GPIOA_BASE + 0x00))
#define GPIOA_ODR   (*(volatile uint32_t*)(GPIOA_BASE + 0x14))

void led_init(void) {
    // Activer l'horloge de GPIOA
    RCC_AHBENR |= (1 << 17);

    // Configurer PA5 en sortie (bits 11:10 = 01)
    GPIOA_MODER &= ~(0x3 << 10);  // effacer les 2 bits
    GPIOA_MODER |=  (0x1 << 10);  // mettre à 01 (sortie)
}

void led_toggle(void) {
    GPIOA_ODR ^= (1 << 5);    // XOR sur le bit 5
}

GPIO et interruptions§

// Configurer une interruption externe sur EXTI (STM32)
void button_init(void) {
    // Configurer PA0 en entrée avec pull-up
    GPIOA_MODER &= ~(0x3 << 0);   // mode entrée (00)
    GPIOA_PUPDR |=  (0x1 << 0);   // pull-up (01)

    // Configurer EXTI0 sur GPIOA
    SYSCFG->EXTICR[0] = 0x00;     // PA0 → EXTI0

    // Activer l'interruption sur front descendant
    EXTI->FTSR |= (1 << 0);
    EXTI->IMR  |= (1 << 0);       // démasquer l'interruption

    // Activer dans le NVIC
    NVIC_EnableIRQ(EXTI0_IRQn);
    NVIC_SetPriority(EXTI0_IRQn, 2);
}

// Handler d'interruption
void EXTI0_IRQHandler(void) {
    if (EXTI->PR & (1 << 0)) {
        EXTI->PR = (1 << 0);      // acquitter (écrire 1 pour effacer)
        led_toggle();
    }
}

Bus de communication§

UART (Universal Asynchronous Receiver/Transmitter)§

Communication série asynchrone, point à point.

TX ──→ RX   (données)
RX ←── TX
GND ── GND

Trame : [START(0)] [D0..D7] [PARITY] [STOP(1)]
Débits courants : 9600, 115200, 921600 bauds
// Initialisation UART (registres directs)
void uart_init(uint32_t baudrate) {
    uint32_t clk = 72000000;  // 72 MHz
    USART1->BRR = clk / baudrate;
    USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE;
}

void uart_putchar(char c) {
    while (!(USART1->SR & USART_SR_TXE));  // attendre que TXE soit libre
    USART1->DR = c;
}

SPI (Serial Peripheral Interface)§

Bus synchrone maître/esclave, haute vitesse, full-duplex, 4 fils.

MOSI (Master Out Slave In)
MISO (Master In Slave Out)
SCK  (Clock)
CS   (Chip Select, actif bas)

Modes (CPOL/CPHA) : 0/0, 0/1, 1/0, 1/1 — définissent la polarité et la phase de l’horloge.

I2C (Inter-Integrated Circuit)§

Bus synchrone multi-maître, 2 fils, adressage 7 bits (128 devices) ou 10 bits.

SDA (données, bidirectionnel, open-drain)
SCL (horloge)

Trame : [START] [ADDR 7b] [R/W] [ACK] [DATA] [ACK] ... [STOP]
Vitesses : Standard 100kHz, Fast 400kHz, Fast+ 1MHz

CAN (Controller Area Network)§

Bus différentiel robuste pour environnements industriels et automobiles (sans maître, CSMA/CD-AMP).

RTOS (Real-Time Operating System)§

Un RTOS fournit un ordonnanceur préemptif qui garantit les délais d’exécution des tâches.

Concepts fondamentaux§

Tâches (threads légers) : unité de base d'exécution
Scheduler : répartit le CPU entre tâches selon priorités
Tick : interruption périodique (1ms typiquement) pour le scheduling

Contraintes temps réel :
- Soft real-time : délai préférable mais dépassement tolérable (lecture vidéo)
- Hard real-time : délai absolu (airbag, contrôle industriel)

FreeRTOS§

RTOS open source le plus utilisé sur Cortex-M.

#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "queue.h"

// Déclaration des tâches
void vTask_LED(void *pvParameters);
void vTask_Sensor(void *pvParameters);

// Handle de sémaphore pour synchronisation
SemaphoreHandle_t xSemaphore;

// Queue pour communication inter-tâches
QueueHandle_t xQueue;

int main(void) {
    // Créer la queue (10 éléments de type float)
    xQueue = xQueueCreate(10, sizeof(float));

    // Créer un sémaphore binaire
    xSemaphore = xSemaphoreCreateBinary();

    // Créer les tâches
    xTaskCreate(
        vTask_LED,        // fonction de la tâche
        "LED",            // nom (debug)
        128,              // taille de la stack (mots de 32 bits)
        NULL,             // paramètre passé à la tâche
        2,                // priorité (plus haute = plus prioritaire)
        NULL              // handle (optionnel)
    );

    xTaskCreate(vTask_Sensor, "Sensor", 256, NULL, 3, NULL);

    // Démarrer l'ordonnanceur (ne retourne jamais)
    vTaskStartScheduler();
}

void vTask_Sensor(void *pvParameters) {
    float valeur;
    for (;;) {
        valeur = lire_capteur();
        // Envoyer dans la queue (bloque 100ms si pleine)
        xQueueSend(xQueue, &valeur, pdMS_TO_TICKS(100));
        vTaskDelay(pdMS_TO_TICKS(50));  // 50ms — yield au scheduler
    }
}

void vTask_LED(void *pvParameters) {
    float valeur;
    for (;;) {
        // Attendre un élément de la queue (bloquant)
        if (xQueueReceive(xQueue, &valeur, portMAX_DELAY)) {
            if (valeur > SEUIL) led_on();
            else                led_off();
        }
    }
}

Primitives de synchronisation§

PrimitiveUsageNotes
Semaphore binaireSignalisation (ISR → tâche)Pas de propriété
Semaphore à compteurRessources multiplesN tokens disponibles
MutexSection critique (tâche ↔ tâche)Propriété + priority inheritance
QueueCommunication inter-tâchesDonnées typées, thread-safe
Event GroupAttendre plusieurs événementsBits de flags
Stream BufferFlux de bytes (UART)Lock-free single reader/writer

Problèmes temps réel courants§

// Priority Inversion : tâche haute priorité bloquée par tâche basse
// → Résolution : Priority Inheritance Protocol (FreeRTOS mutex)

// Deadlock : deux tâches s'attendent mutuellement
// Tâche A : prend mutex1, attend mutex2
// Tâche B : prend mutex2, attend mutex1
// → Résolution : ordre cohérent d'acquisition des mutexes

// Stack overflow (très courant sur MCU avec RAM limitée)
// → Activer configCHECK_FOR_STACK_OVERFLOW dans FreeRTOSConfig.h
void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName) {
    // Traiter l'erreur fatale
    __BKPT(0);   // breakpoint
    while(1);
}

Outils de développement§

OutilUsage
GCC ARM (arm-none-eabi-gcc)Compilateur croisé
OpenOCDInterface JTAG/SWD, débogage
GDBDébogueur (via OpenOCD)
ST-Link / J-LinkSondes de débogage
STM32CubeIDEIDE pour STM32 (Eclipse + HAL)
PlatformIOMulti-plateforme (Arduino, STM32, ESP32)
Segger RTTConsole série via JTAG (ultra-rapide)
Logic AnalyzerAnalyser les signaux UART/SPI/I2C

Considérations IoT et sécurité embarquée§

// Secure Boot : vérifier la signature du firmware avant exécution
// TrustZone (Cortex-M33) : isoler le code sécurisé du non-sécurisé
// Watchdog Timer : redémarrer en cas de blocage
HAL_IWDG_Init(&hiwdg);  // Initialiser le watchdog
HAL_IWDG_Refresh(&hiwdg);  // Rafraîchir régulièrement (sinon reset)

// Ne jamais stocker de clés en clair en Flash
// Utiliser l'OTP (One-Time Programmable) ou un coprocesseur sécurisé (ATECC608)
Menace IoTContre-mesure
Extraction du firmwareDésactiver JTAG en production, chiffrer la Flash
Mise à jour malveillanteOTA signé + Secure Boot
Communication interceptéeTLS mutuellement authentifié (mTLS)
Side-channel (power analysis)Masquage, implémentations constantes en temps
Hardcoded credentialsProvisionnement individuel à la fabrication
—The Gardener