Introduction

La carte, le processeur

Vous allez développer sur des cartes STM32 IoT Node. Ces cartes sont basées sur un microcontrôleur de ST, le STM32L475VGT6. Un microcontrôleur est un circuit intégré rassemblant un coeur de processeur ainsi que plusieurs périphériques usuels. En l'occurrence le coeur de processeur est un ARM Cortex M4 associé à plusieurs périphériques, comme des entrées-sorties basiques appelées GPIO (Global Purpose Input Ouput), des bus (I2C, UART, SPI, …), des générateurs PWM, des convertisseurs analogiques-numériques, etc.

Cette carte inclut plusieurs capteurs, dont :

  • des modules de communication radio (WiFi, Bluetooth, SubGHz, …),
  • un transpondeur NFC,
  • deux microphones,
  • un capteur d'humidité et de température,
  • un magnétomètre, un accéléromètre et un gyroscope 3D,
  • un baromètre de précision,
  • un détecteur de distance et de gestes,
  • de l'USB OTG,
  • un bouton poussoir, 
  • des LED,
  • des connecteurs d'expansion pour brancher des cartes additionelles…

Vous trouverez plusieurs documents importants en bas de cette page :

Impératif : téléchargez au moins le manuel de référence du processeur et stockez-le dans votre dépôt git, ce sera votre bible pour le reste de l'UE. Tant que vous y êtes, téléchargez aussi les autres documents…

 

Branchement de la carte

Pour alimenter et débugger la carte, il suffit de brancher un câble micro-USB entre la prise USB Débug de la carte et votre PC. C'est tout !

Note

Procédure de remise à zéro de la carte:

Si votre carte a été utilisée précédemment et que la flash contient un programme, elle peut être dans un état qui complexifie le debug. Pour effacer le contenu de la mémoire flash du microcontrôleur et la remettre dans son état d'origine, voici la procédure à suivre:

  1. brancher la carte
  2. lancer l'outil JLinkExe en ligne de commande
  3. JLinkExe -device STM32L475VG  -speed auto  -if SWD
  4. se connecter
  5. connect
  6. stopper le processeur
  7. halt
  8. effacer la flash
  9. erase
  10. vérifier que ça a fonctionné et quitter
  11. mem32 0 128
    exit

Mapping mémoire

Le mapping mémoire du processeur est disponible en page 75 du reference manual du processeur. Pas la peine de tout lire, pour l'instant retenez juste les emplacements et tailles des éléments suivants :

  • Flash : adresse de début = 0x08000000, taille = 1MB
  • RAM : elle est séparée en deux blocs non contigus :
    • SRAM1 : début = 0x20000000, taille = 96kB
    • SRAM2 : début = 0x10000000, taille = 32kB

Dans un premier temps, le programme qu'on écrira sera logé en RAM. Pour des raisons qu'on verra plus tard, nous allons le loger dans SRAM1. SRAM2 sera réservé pour autre chose (patience petit Padawan).

Outils de débug

La carte de développement intègre une sonde JTAG, ce qui est bien pratique. Elle est disponible sur le connecteur de la figure ci-dessus appelé "USB Débug" (!). Plus exactement, ce connecteur USB vous donne accès à deux choses :

  • la sonde JTAG intégrée
  • un port série sur USB, vu sous Linux comme /dev/ttyACM0 (115200 baud, pas de parité, 8 bits, pas de contrôle de flux)

La sonde JTAG intégrée native est une sonde STLink V2.1.  Nous avons reflashé ces sondes de façon à ce qu'elles se comportent comme des sondes JLink de Segger, qui comptent parmi les sondes les plus efficaces du marché et vous offrent des possibilités de débug qui vous seront bien utiles dans la suite du TP.

Comme pour toutes les sondes JTAG, nous devrons utiliser un "driver" pour faire le pont entre gdb et la sonde. Ce driver s'appelle JLinkGDBServer ou JLinkGDBServerExe en version graphique. Il est disponible ici (pour ceux qui souhaitent travailler sur leur portable). Ce "driver" est installé sur toutes les stations de la A406. Il est aussi disponible dans les paquets de la distribution ArchLinux. Si votre carte n'est reconnue que lorsque vous êtes root, c'est que vous avez probablement oublié d'installer les règles udev nécessaires (cf. fichier README.TXT)

Pilotage de la sonde

Depuis gdb, il est possible d'envoyer à la sonde des commandes spécifiques, en les préfixant par "monitor" (ou "mon" pour faire plus court) . Voici les commandes les plus utiles pour les sondes JLink :

  • reset : déclenche un reset hardware du processeur et le maintient en pause.
  • halt : met le processeur en pause.
  • endian little : déclare à la sonde que le processeur est câblé pour être en mode little-endian.

Pour lancer / débugger un programme, une procédure typique serait la suivante :

  1. Lancer le driver : JLinkGDBServer -device STM32L475VG -endian little -if SWD -speed auto -ir -LocalhostOnly
  2. Dans un autre terminal, lancer le cross-débugger : arm-none-eabi-gdb xxx.elf (remplacer xxx.elf par le nom du programme que vous voulez débugger)
  3. Dire à gdb qu'on fait du débug distant et sur quel port communiquer avec le driver de sonde : target ext :2331
  4. Transmettre au driver de sonde la commande disant que le processeur est en mode little-endian : mon endian little
  5. Remise à zéro le processeur et le maintenir en pause par mon reset.
  6. Transférer le programme sur la carte : load (ici, gdb se charge de positionner le PC à l'entry point de votre exécutable si celui-ci en a un)
  7. Lancer l'exécution : cont
  8. Débugger de façon normale (si pour avancer d'une instruction assembleur, etc.)

Plutôt que de taper à chaque fois toutes ces commandes, il est préférable de se créer un fichier .gdbinit, qui sera exécuté à chaque lancement de arm-none-eabi-gdb dans le répertoire où ce fichier se trouve.

target ext :2331
mon endian little
mon halt

# interface with asm, regs and cmd windows
define split
  layout split
  layout asm
  layout regs
  focus cmd
end

# interface with C source, regs and cmd windows
define ss
  layout split
  layout src
  layout regs
  focus cmd
end

define flash
  dont-repeat
  mon reset
  load
end

# Usefull function when the processor is in hardfault to see
# where it comes from.
define armex
  printf "EXEC_RETURN (LR):\n",
  info registers $lr
    if ($lr & 0x4)
      printf "Uses MSP 0x%x return.\n", $MSP
      set $armex_base = $MSP
    else
      printf "Uses PSP 0x%x return.\n", $PSP
      set $armex_base = $PSP
    end

    printf "xPSR            0x%x\n", *($armex_base+28)
    printf "ReturnAddress   0x%x\n", *($armex_base+24)
    printf "LR (R14)        0x%x\n", *($armex_base+20)
    printf "R12             0x%x\n", *($armex_base+16)
    printf "R3              0x%x\n", *($armex_base+12)
    printf "R2              0x%x\n", *($armex_base+8)
    printf "R1              0x%x\n", *($armex_base+4)
    printf "R0              0x%x\n", *($armex_base)
    printf "Return instruction:\n"
    x/i *($armex_base+24)
    printf "LR instruction:\n"
    x/i *($armex_base+20)
end

document armex
ARMv7 Exception entry behavior.
xPSR, ReturnAddress, LR (R14), R12, R3, R2, R1, and R0
end

Attention : pour des raisons de sécurité, par défaut les .gdbinit ne sont pas lus. Lisez attentivement le message de arm-none-eabi-gdb après avoir créé le .gdbinit pour voir ce que vous avez à faire pour qu'il soit exécuté.

Attention : ce .gdbinit est à comprendre, pas à recopier bêtement. Surtout si vous comptez suivre SE302 : il faudra l'adapter à vos besoins (vous comprendrez lorsque vous aurez fait la partie sur les IRQ).

Une fois que vous avez ce .gdbinit en place (pensez à le committer), tout ce que vous avez à faire est :

  1. flash, pour charger le programme sur le processeur.
    Si vous avez défini un ENTRY point dans votre script de link, gdb positionne automatiquement le PC à la bonne valeur
  2. cont pour démarrer le programme.

Conseils :

  • Dans votre Makefile, définissez une cible virtuelle qui lance JLinkGDBServer (ou la version graphique) avec les bonnes options
  • À partir de maintenant vous devriez avoir, dans un répertoire nommé TD, un Makefile qui permet de lancer JLinkGDBServer, ainsi qu'un .gdbinit.

L'environnement de débug est en place, on peut maintenant entrer dans le vif du sujet !

Au fait, vous avez pensé à committer / pusher combien de fois ? Une fois que vous pensez avoir terminé cette partie, mettez le tag git INTRO sur le commit de fin, et pushez le par git push --tags.

Attention : lors de la correction du TP, seuls les commit avec les tags précisés ici seront examinés.