Partie logicielle

Environnement de travail

La carte du TP

Pour nous simplifier la vie, vous allez travailler sur une carte d'Olimex équipée d'un STM32F407, dont vous trouverez la documentation (schémas et le manuel d'utilisateur) ici.

Le moyen le plus simple pour alimenter cette carte est de la brancher en USB sur votre PC (vous en aurez besoin, de toutes façons). N'oubliez pas de bouger le jumper "POWER_SEL" pour le mettre sur les broches 7 et 8.

Les documentations

En plus des documentation officielles de ST, vous risquez d'avoir besoin de la documentation du coeur Cortex M4 :

Attention, dans la documentation ARM du coeur Cortex, les noms registres sont indiqués en toutes lettres. Par exemple, le SCB est mentionné comme System Control Block, et le registre AIRCR comme Application Interrupt and Reset Control Register !!!

Vous pouvez aussi consulter le Cortex M4 Programming Manual écrit par ST, plus clair et léger que celui d'ARM. Et bien entendu vous aurez besoin du Reference Manual du STM32F407.

Chaîne de compilation

La chaîne de compilation est la même que celle utilisée en SE203 (que vous pouvez donc installer sur votre PC).

Contrairement à SE203, ici les sondes JTAG sont séparées de la carte de Débug. On utilisera des sondes de Segger, qui se comportent exactement comme les sondes intégrées aux cartes utilisées en SE203. Les drivers de sonde sont disponibles ici (J-Link Software and Documentation Pack) ou bien parfois fournis dans votre distribution Linux (un paquet pour ArchLinux est disponible : yaourt -S jlink).

Pour vous faciliter la vie, vous pouvez rajouter dans votre Makefile des cibles de ce genre pour lancer le démon JLink :

startgdbserver:
    @pgrep JLinkGDBServer > /dev/null || JLinkGDBServer -if swd -speed auto -device STM32F407ZG

stopgdbserver:
    -@killall -s JLinkGDBServer

debug: $(ELF) startgdbserver
    $(GDB) $(ELF)

.PHONY: startgdbserver stopgdbserver debug

Assurez vous de comprendre ce que signifient ici @, pgrep, killall et || avant d'utiliser ce code.

Notes diverses

Il n'est pas nécessaire de spécifier l'adresse de démarrage (flash, ram ou bootloader intégré) à la main, le STM32 utilise des jumpers sur la carte pour savoir où il doit booter. La configuration par défaut est en flash, gardez-la.

Travail demandé

Import de ChibiOS et création d'un projet

Récupérez ChibiOS 19.1.3 (la dernière en date) et ajoutez le dans votre dépôt Git. Créez un lien symbolique (ln -s) appelé ChibiOS pointant sur ChibiOS_19.1.3.

Créez un répertoire TP_STM32 qui va contenir le projet du TP au même niveau que ChibiOS. Vous devriez donc avoir l'arborescence suivante :

racine
   ├── ChibiOS (pointe sur ChibiOS_19.1.3)
   ├── ChibiOS_19.1.3
   └── TP_STM32

Dans ChibiOS/ext, décompressez en place lwip-2.0.3_patched.7z et fatfs-0.13-patched.7z puis ajoutez les répertoire lwip et fatfs à votre dépôt Git.

Définition d'une nouvelle "board"

ChibiOS fournit déjà les fichiers de board (board.h et board.c) pour notre carte. Ces fichiers sont faits pour des cartes "prêtes à l'emploi" : les broches ont une fonction par défaut assignée dans le board.h. Ils ont l'inconvénient d'êre difficiles à lire, à comprendre et à débugger.  

Nous allons donc prendre une autre approche :

  1. Les fichiers de board ne contiendront que le strict nécessaire pour que la carte boote sans créer de court-circuits.
  2. L'initialisation des broches pour un périphérique particulier sera faite dans le fichier gérant ce périphérique. Par exemple, pour piloter l'Ethernet, on aura un fichier ethernet.c (par exemple) qui contiendra la fonction ethernet_init. Cette fonction aura pour rôle de configurer les broches reliées au transceiver Ethernet et de lancer les threads nécessaires.

Pour cela :

  1. Lisez le référence manuel du STM32F4 parlant de la configuration des broches (Alternate Fonctions, …)
  2. Copiez le répertoire de board fourni par ChibiOS vers un nouveau répertoire que vous appellerez board_E407
  3. Vous devez donc obtenir l'arborescence suivante :

    racine
       ├── ChibiOS (pointe sur ChibiOS_19.1.3)
       ├── ChibiOS_19.1.3

       └── TP_STM32
           └── board_E407

  4. Modifiez board.h de façon à ce que les seules broches critiques (dont le SWD / JTAG) soient configurées de la façon nécessaire. Les autres broches devront être configurées en entrées flottantes de façon à ne pas créer de court-circuit.

Emplacement de vos sources

Vous mettrez vos sources dans un répertoire src, de façon à ce que votre arborescence soit celle-ci : 

racine
   ├── ChibiOS (pointe sur ChibiOS_19.1.3)
   ├── ChibiOS_19.1.3
   └── TP_STM32
       └── board_E407
       └── src

Vous pouvez récupérer les fichiers Makefile, chconf.h, halconf.h et mcuconf.h d'un exemple simple de ChibiOS prévu pour le même microcontrôleur (STM32F407) n'utilisant qu'un main.c. Modifiez le Makefile pour qu'il aille chercher les sources de ChibiOS dans ../ChibiOS et qu'il inclue le fragment board_E407/board.mk. Placez le main.c de l'exemple dans le répertoire src et nettoyez le de tout contenu afin qu'il n'aille pas modifier des ports d'entrées-sorties inadaptés lors du lancement.

Si l'exemple dont vous partez n'est pas prévu pour la même carte que la vôtre (STM32_E407 d'Olimex), vous devrez configurer ChibiOS pour qu'il configure les variables de PLL du microcontrôleur avec des valeurs compatibles avec les sources d'horloge disponibles sur votre carte de TP. Pour cela, vous pourrez mettre les valeurs suivantes dans votre mcuconf.h :

#define STM32_PLLSRC STM32_PLLSRC_HSE
#define STM32_PLLM_VALUE 12
#define STM32_PLLN_VALUE 336
#define STM32_PLLP_VALUE 2
#define STM32_PLLQ_VALUE 7

Documentation

La documentation par défaut de ChibiOS ne spécifie rien sur les drivers que vous utilisez (ils dépendent du processeur). Pour avoir une documentation sur HAL que vous effectivement utiliser utilisez le script disponible ici : https://github.com/alexispolti/ChibiOS_docgenerator"

Allumage de la LED

En étudiant la PAL de ChibiOS/RT, allumez la LED utilisateur. 

En lisant la documentation sur les timers, faites clignoter la LED à une fréquence de 1Hz.

Ajoutez ensuite la possibilité de contrôler plus finement l'intensité de chaque LED en utilisant du PWM.

UART sur USB / Shell

La carte ne disposant pas de connecteurs ports série, nous allons implémenter un port série sur USB.

En utilisant le bon driver de ChibiOS/RT, configurez le port USB utilisé pour alimenter la carte de façon à ce qu'il soit vu comme un port série.

Rajoutez l'utilisation du shell intégré à ChibiOS/RT pour pouvoir lancer le test de chacune des fonctionnalités demandées dans ce TP.

RTT

Les sondes JTAG/SWD de Segger implémentent un système de communications bidirectionnel avec le système hôte de débug, appelé RTT. Il permet de faire des entrées-sorties à très haute vitesse, ainsi que que de faire du profiling (voir SystemView). Pour cela, aidez-vous des templates fournis par Segger : 

Implémentez un canal (stream) de débug qui passe par le RTT pour débugger facilement la suite du TP. 

Bouton-poussoir

Utilisez le bouton-poussoir WAKEUP (sur PA0) pour allumer / éteindre la LED.  Ajoutez de l'anti-rebond.  C'est une bonne occasion d'utiliser les événements de ChibiOS/RT.

L'utilisation du polling (vérification permanente) n'est pas autorisée. Le changement d'état d'un bouton doit nécessairement être détecté grâce à une interruption.

Ajoutez ensuite la possibilité de contrôler l'intensité lumineuse de la LED en appuyant de façon continue sur le bouton. Pour cela, synthétisez les événements suivants :

  • BUTTON_CLICK : si le bouton est appuyé et relâché en un temps court (à choisir)
  • BUTTON_PRESSED : si le bouton est appuyé plus longtemps que le temps court
  • BUTTON_RELEASED : lorsque BUTTON_PRESSED a été généré et que le bouton est ensuite relâché.

TCP/IP

Configurez le réseau par DHCP (n'oubliez pas de choisir une adresse MAC unique) pour pouvoir faire une requête TCP vers un serveur web. Par exemple, connectez vous sur chibios.org, port 80, et envoyez

GET /dokuwiki/doku.php HTTP/1.0
Host: chibios.org
 

(il y a une ligne vide après la ligne Host)

Envoyez sur le port série la page ainsi récupérée.