Retour à l'accueil

Questions C pour microcontrôleurs

L'article contient des questions clés sur la programmation C pour microcontrôleurs, les systèmes de build, les interruptions et RTOS. La sélection est basée sur de vrais entretiens pour spécialistes middle/senior. Exemples de code et explications de terminologie.

C pour microcontrôleurs : 60+ Questions clés
Advertisement 728x90

Fondamentaux du C embarqué : Questions clés sur la programmation des microcontrôleurs

Les programmeurs de microcontrôleurs doivent maîtriser les spécificités du C dans des contraintes de ressources très serrées. Voici une liste sélectionnée de questions pratiques portant sur la compilation, la mémoire et l'optimisation. Ces sujets reviennent souvent aux entretiens dans les entreprises de systèmes embarqués.

Mots-clés essentiels et leur utilisation

Static limite la visibilité d'une variable au fichier ou à la fonction courante, en préservant les valeurs entre les appels pour les statiques locales. Volatile empêche le compilateur d'optimiser les variables modifiées de l'extérieur (registres, mémoire, interruptions).

Exemple de code problématique :

Google AdInline article slot
int square(volatile int *ptr) {
    return *ptr * *ptr;
}

Ici, volatile ne s'applique qu'au premier déréférencement ; le second pourrait être optimisé. Correction : (ptr) (*ptr).

Const volatile convient aux données externes en lecture seule comme les registres de statut. Register suggère de stocker une variable dans un registre CPU (déprécié en C11). Restrict indique au compilateur que les pointeurs ne se chevauchent pas, favorisant la vectorisation.

Gestion de la mémoire et structures

Les variables globales const vont en mémoire Flash. Pour un tableau constant de 32 Ko rempli de 0xFF, utilisez une section de script de lien avec fill(0xFF).

Google AdInline article slot

Opérations sur bits : tester un bit avec n & (1 << k), effacer avec n & ~(1 << k). Comparaison de flottants : fabs(a - b) < EPSILON.

Les tailles de structures dépendent de l'alignement. Pour

struct Foo {
    int iiii;
    char c;
};

la taille est de 8 octets (4 octets de padding). Empaquetage GCC : __attribute__((packed)).

Google AdInline article slot

Exemples de déclaration de chaînes :

char str5[]={'s','t','r','i','n','g'};  // taille:7 len:6
char *str1="string";                    // taille:4 len:6 (pointeur)
char str3[]="string";                   // taille:7 len:6
char str4[10]="string";                 // taille:10 len:6

Systèmes de build et chaînes d'outils

Les systèmes de build automatisent la compilation, le lien et les dépendances. Make gère les changements de fichiers, tandis que Ninja est plus rapide grâce au parallélisme et à sa simplicité.

VPATH dans GNU Make recherche les sources dans les répertoires indiqués.

Pipeline de code : .c → .i (préprocesseur) → .s (assembleur) → .o → .elf → .bin/.hex.

Désactiver un avertissement GCC : #pragma GCC diagnostic ignored "-Wrestrict".

Réduire le firmware : -ffunction-sections -fdata-sections, ld --gc-sections, et optimisation -Os.

Artefacts de build

  • .o — fichiers objets
  • .elf — exécutable avec symboles
  • .hex/.bin — pour le flashage (hex inclut les adresses)

Binutils : objdump (désassembleur), objcopy (convertisseur), readelf (analyseur ELF).

Vérifier le build : make V=1 ou -n (simulation).

Structures de données et algorithmes

Tampon circulaire — tableau annulaire avec indices tête/queue, contrairement au FIFO qui décale les éléments.

Suppression dans liste chaînée : prev->next = node->next (nécessite prev) ou node->next->prev = node->prev (doubly-linked).

Polymorphisme en C : pointeurs de fonctions dans structs (style vtable).

Tâche sans if/switch :

void print_num(int n) {
    const char *nums[] = {"","Un","Deux"};
    printf("%s", nums[n]);
}

do-while(0) pour macros — itération unique avec plusieurs instructions.

Interruptions et RTOS

Interruption — mécanisme matériel sautant vers un ISR sur un événement. La table de vecteurs contient les adresses des ISR. Cortex-M4 : 12–16 cycles pour l'entrée (sauvegarde contexte).

Flux : matériel sauvegarde PC/LR, charge vecteur, saute à ISR, retourne via POP.

Fonction réentrante — sûre pour appels concurrents (pas de statiques/locaux sans synchro).

Dans RTOS :

  • Thread — unité d'exécution avec sa propre pile
  • Mutex — exclusion mutuelle
  • Sémaphore — compteur d'événements
  • Spinlock — verrou busy-wait

Problème de code : deadlock par ordre de verrou (TâcheA : ma→mb, TâcheB : mb→mc→ma).

Inversion de priorité : tâche haute priorité attend une basse. Solution : héritage de priorité.

Opérations atomiques

Exemple : __atomic_exchange_n(&x, &y, __ATOMIC_SEQ_CST).

Bit-banding — accès direct aux bits sans masques (Cortex-M3/4).

Chaîne d'outils et débogage

ABI — interface binaire (convention d'appel).

Segments : .text (code Flash), .data (RAM initialisée), .bss (RAM zéros), .rodata (constantes Flash).

Développer préprocesseur : gcc -E file.c > expanded.i.

Docs clés : fiche technique, manuel de référence, manuel de programmation, schémas.

Points clés à retenir

  • Volatile est essentiel pour les registres périphériques
  • Les structs empaquetées économisent de la RAM mais ralentissent l'accès
  • RTOS nécessite du code thread-safe et protection des sections critiques
  • Optimisation build : sections + gc-sections
  • Les interruptions utilisent la pile du thread courant

Pour padding 0xFF dans structs : script de lien avec fill ou __attribute__((packed)) + remplissage manuel.

— Editorial Team

Advertisement 728x90

Lire ensuite