mercredi 13 mars 2013

Cortex M4 - Premiers Pas avec des outils Opensource

Je suis parti à la découverte des micros Cortex M4 lors de l'achat d'une carte de démonstration STM32F3 discovery pour une dizaine d'euros.

Cette "demo board" embarque plusieurs choses très intéressantes, notamment, un MCU STM32F303VCT6 32 bits Cortex M4, un ST-LINK v2 (outil de programmation et de debug), un Gyroscope, Un compas avec un accéléromètre, plusieurs leds et boutons et deux connecteurs mini USB. Bref, tout pour commencer à s’amuser.




Un programme de démonstration tourne déjà sur la carte et permet de s'amuser avec les différents composants (Chenillard, gyroscope et accéléromètre avec la roue de Leds).

Après lecture de la documentation téléchargeable sur le site de ST microelectronics. J'ai fait particulièrement attention aux différents outils de développement proposés avec la carte. 4 choix possibles :


Vous l'aurez compris, j'ai choisi la cinquième option. Elle consiste à utiliser des outils Open source pour toute la chaîne de développement.

Ce premier post sur le cortex M4 va consister à montrer les différents outils nécessaires au développement, à la programmation et au débogage.

  • Création d'une chaîne de compilation croisée GNU custom pour le micro.
  • Création d'un Template de compilation (Makefile, etc ...).
  • Utilisation et comparaison avec une chaîne de compilation croisée GNU téléchargeable.
  • Installation et utilisation de l'outil de programmation sous linux (non-officiel) et sous windows (officiel)
  • Installation et utilisation de l'outil OpenOCD pour le débogage.

CMSIS : Qu'est ce que c'est ?


Avant de répondre à cette question existentielle, on va revenir sur l'archive fournie par ST avec la démo board. Elle fournit les sources de la démo installée sur la carte ainsi que différents exemples sur l'utilisation et l'interfaçage des périphériques du micro.

# cd STM32F3-Discovery_FW_V1.1.0
# ls -al
total 100
drwxrwxr-x  6 sinseman44 sinseman44  4096 2013-02-25 19:30 ./
drwxr-xr-x 17 sinseman44 sinseman44  4096 2013-02-27 21:27 ../
drwxrwxr-x  2 sinseman44 sinseman44  4096 2013-02-25 19:30 _htmresc/
drwxrwxr-x  5 sinseman44 sinseman44  4096 2013-02-25 19:28 Libraries/
-r--r--r--  1 sinseman44 sinseman44 17797 2012-09-07 13:14 MCD-ST Liberty SW License Agreement V2.pdf
drwxrwxr-x  5 sinseman44 sinseman44  4096 2013-02-25 19:28 Project/
-r--r--r--  1 sinseman44 sinseman44 39158 2012-09-27 15:05 Release_Notes.html
drwxrwxr-x  3 sinseman44 sinseman44  4096 2013-02-25 19:30 Utilities/

Dans le dossier Libraries, contient le fameux dossier CMSIS, ainsi que le dossier STM32F30x_StdPeriph_Driv contenant les drivers (sources) des périphériques présents sur la carte et le dossier STM32_USB-FS-Device_Driv contenant la librairie de la pile de communication USB de la carte.

# cd Libraries
total 20
drwxrwxr-x 5 sinseman44 sinseman44 4096 2013-02-25 19:28 ./
drwxrwxr-x 6 sinseman44 sinseman44 4096 2013-02-25 19:30 ../
drwxrwxr-x 9 sinseman44 sinseman44 4096 2013-02-25 19:28 CMSIS/
drwxrwxr-x 4 sinseman44 sinseman44 4096 2013-02-25 19:28 STM32F30x_StdPeriph_Driver/
drwxrwxr-x 4 sinseman44 sinseman44 4096 2013-02-25 19:28 STM32_USB-FS-Device_Driver/

J'ai voulu m’intéresser plus particulièrement au dossier CMSIS parce qu'il a une particularité très intéressante.
CMSIS pour ARM Cortex Microcontroller Software Interface Standard est une couche d'abstraction bas niveau, comprenez hardware, indépendante du constructeur pour les séries de micro contrôleur Cortex. Ce qui signifie, que quelque soit le constructeur de micro contrôleur Cortex M0, Cortex M3 ou Cortex M4 (ST, NXP, etc ...), la couche d'abstraction CMSIS sera, à un ou deux détails près, la même.
Dans le cas de travaux hobbyistes, tels que les miens, ce n'est pas très important, mais pour des sociétés voulant changer de micro contrôleur sur leurs cartes en passant d'un fabricant à un autre pour des raisons de pérennité ou pour passer sur une série plus puissante, cela peut considérablement réduire les coûts de développement.


Dans le dossier CMSIS, se trouve les sous dossiers :

  • CMSIS-CORE : offre une interface avec l'architecture matérielle du micro contrôleur ainsi que les registres, les définitions des noms, des adresses. Il contient, également, une interface indépendante pour les noyaux temps réel (RTOS) qui inclus des définitions de débogage.
  • CMSIS-DSP : Suite de sources, codées en C, de nombreuses fonctions pour le traitement de signaux basée sur l'architecture Cortex.
  • CMSIS-RTOS API : Interface de programmation standardisé pour les OS temps réel (Thread control, resource, time management, ...)
  • CMSIS-SVD (System View Description) : Fichiers XML contenant une vue complete du micro contrôleur incluant les périphériques externes.

Chaîne de compilation croisée custom


Pour construire notre chaîne de compilation, on va se servir de l'outil Crosstool-NG. Pour ceux qui suivent ce blog, il fait partie de la suite de logiciels contenue dans buildroot.
Cet outil a pour but de construire une chaîne de compilation croisée en fonction des différents paramètres donnés.

Je vous file le fichier de config.

L'archive de l'outil (crosstool-ng-1.18.0.tar.bz2) doit être téléchargée puis installée :
# tar xvjf crosstool-ng-1.18.0.tar.bz2
# cd crosstool-ng-1.18.0
# ./bootstrap
# ./configure
# make
# make install

Puis dans le dossier d'installation de Crosstool-NG, lancer l'outil :
# cd <CROSSTOOL_NG_INSTALL_PATH>
# cd bin
=> Pour ceux qui ont téléchargé le fichier de config
# mv cortexM4_config .config
# ./ct-ng menuconfig

L'un des sous dossiers important est Target options :


Ce sous dossier permet de configurer l'architecture matérielle du micro contrôleur.


Le sous dossier Operating System :

bare-metal signifie que le software est exécuté directement depuis la mémoire vive, sur le système, au lieu d'être chargé en tant que tâche d'un OS.


Le sous dossier C compiler :


Après la configuration, il suffit de lancer la commande pour construire la chaîne de compilation :
# ./ct-ng build

(Attention, cette étape peut-être longue, quelques dizaines de minutes, en fonction des capacités de votre ordinateur)

Une fois la compilation faite, voici le dossier d'installation de cette nouvelle chaîne :
# cd <x-tools>
total 320
dr-xr-xr-x 8 sinseman44 sinseman44   4096 2013-02-27 18:40 ./
drwxr-xr-x 3 sinseman44 sinseman44   4096 2013-02-27 16:34 ../
dr-xr-xr-x 6 sinseman44 sinseman44   4096 2013-02-27 17:58 arm-unknown-eabi/
dr-xr-xr-x 2 sinseman44 sinseman44  12288 2013-02-27 18:40 bin/
-r--r--r-- 1 sinseman44 sinseman44 278144 2013-02-27 18:40 build.log.bz2
dr-xr-xr-x 3 sinseman44 sinseman44   4096 2013-02-27 18:40 include/
dr-xr-xr-x 4 sinseman44 sinseman44   4096 2013-02-27 18:40 lib/
dr-xr-xr-x 3 sinseman44 sinseman44   4096 2013-02-27 18:31 libexec/
dr-xr-xr-x 4 sinseman44 sinseman44   4096 2013-02-27 18:40 share/

Template de compilation


Le Template va permettre de créer un projet générique ou il n'y aura plus qu'à y insérer les sources du projet et à modifier le makefile. Il est basé sur un déjà existant, adapté pour l'occasion :



Voici l'arborescence de notre Template nécessaire pour la compilation :

  • dossier Device : contient le code de démarrage de la carte ainsi que le script de linkage
  • dossier extra : contient les utilitaires nécessaires pour le flashage et le débogage du projet
  • dossier src : contient les fichiers sources du projet
  • dossier inc : contient les headers des fichiers sources
  • Makefile : fichier de compilation

Le dossier Libraries a volontairement disparu puisque je vais utiliser les librairies fournies avec la démo board de chez ST.

Voici l'arborescence après compilation :
  • dossier Device : contient le code de démarrage de la carte ainsi que le script de linkage
  • dossier extra : contient les utilitaires nécessaires pour le flashage et le débogage du projet
  • dossier bins : contient les binaires (fichier HEX, fichier ELF, fichier BIN, fichier MAP, etc ...) générés du projet.
  • dossier inc : contient les headers des fichiers sources
  • dossier deps : contient les dépendances générées lors de la compilation
  • dossier objs : contient les fichiers objets générés lors de la compilation
  • dossier src : contient les fichiers sources du projet
  • Makefile : fichier de compilation
  • libstm32f3.a : librairie statique compilée des sources des périphériques du micro

Quelques explications sur le fichier de linkage et le code de démarrage :


La séquence de démarrage pour un système "bare-metal" de type ARM est contenu dans un fichier startup.s. Toutes les séquences d'initialisation bas niveau pour le CPU, la carte, écrite en C ou en assembleur, sont présents.
Le script de linkage regroupe les informations du code de démarrage, et définit la "map" mémoire du système cible. Il a comme extention .ld.

Pour les plus courageux, voici un peu de documentation (Building_bare-metal_ARM_with_GNU.pdf) sur le sujet.

Maintenant le fichier de compilation, Makefile. Il faut modifier les variables :

  • SRCS : contient les noms des fichiers sources à compiler.
  • SRCS_PERIPH : contient les noms des fichiers sources des drivers des différents périphériques de la démo board.
  • PROJ_NAME : Le nom du projet qui sera utilisé comme nom de binaires.
  • STD_PERIPH_LIB : Le chemin des librairies fournies avec la démo board.
  • LDSCRIPT_INC : Le chemin du script de linkage.
  • OPENOCD_BOARD_DIR : Le chemin des scripts de configuration de carte pour OpenOCD.
  • OPENOCD_PROC_FILE : Le chemin des directives de lancement d'OpenOCD.
  • TOOLCHAIN : Le chemin de la chaîne de compilation croisée.
  • TOOLCHAIN_TARGET : Le préfixe de la chaîne de compilation croisée.


# put your *.c source files here, make should handle the rest!
SRCS = main.c errno.c stm32f3_discovery.c system_stm32f30x.c

# Periph driver sources
SRCS_PERIPH = stm32f30x_adc.c stm32f30x_can.c stm32f30x_comp.c stm32f30x_crc.c \
     stm32f30x_dac.c stm32f30x_dbgmcu.c stm32f30x_dma.c \
     stm32f30x_exti.c stm32f30x_flash.c stm32f30x_gpio.c \
     stm32f30x_i2c.c stm32f30x_iwdg.c stm32f30x_misc.c stm32f30x_opamp.c \
     stm32f30x_pwr.c stm32f30x_rcc.c stm32f30x_rtc.c stm32f30x_spi.c \
     stm32f30x_syscfg.c stm32f30x_tim.c stm32f30x_usart.c \
     stm32f30x_wwdg.c usb_core.c usb_init.c usb_int.c usb_mem.c \
     usb_regs.c usb_sil.c

# all the files will be generated with this name (main.elf, main.bin, main.hex, etc)
PROJ_NAME=blink_led

# Location of the Libraries folder from the STM32F3 Standard Peripheral Library
STD_PERIPH_LIB=<PATH_TO_LIBRARIES_FILES>/STM32F3-Discovery_FW_V1.1.0/Libraries

# Location of the linker scripts
LDSCRIPT_INC=Device/ldscripts

# location of OpenOCD Board .cfg files (only used with 'make program')
OPENOCD_BOARD_DIR=<PATH_TO_OPENOCD_BOARD_SCRIPT>

# Configuration (cfg) file containing programming directives for OpenOCD
OPENOCD_PROC_FILE=extra/stm32f3-openocd.cfg

# toolchain path
TOOLCHAIN=<PATH_TO_TOOLCHAIN>/gcc-arm-none-eabi-4_7-2012q4/bin

TOOLCHAIN_TARGET=$(TOOLCHAIN)/arm-none-eabi-

# that's it, no need to change anything below this line!

###################################################

CC = $(TOOLCHAIN_TARGET)gcc
GDB = $(TOOLCHAIN_TARGET)gdb
OBJCOPY = $(TOOLCHAIN_TARGET)objcopy
OBJDUMP = $(TOOLCHAIN_TARGET)objdump
SIZE = $(TOOLCHAIN_TARGET)size

LIB = libstm32f3.a

CFLAGS  = -Wall -g -std=c99 -Os  
#CFLAGS += -mlittle-endian -mcpu=cortex-m4 -march=armv7e-m -mthumb
#CFLAGS += -mfpu=fpv4-sp-d16 -mfloat-abi=hard
CFLAGS += -ffunction-sections -fdata-sections

LDFLAGS += -Wl,--gc-sections -Wl,-Map=bins/$(PROJ_NAME).map

###################################################

vpath %.a $(STD_PERIPH_LIB)
vpath %.c $(STD_PERIPH_LIB)/STM32F30x_StdPeriph_Driver/src
vpath %.c $(STD_PERIPH_LIB)/STM32_USB-FS-Device_Driver/src
vpath %.c src

ROOT=$(shell pwd)

CFLAGS += -Iinc 
CFLAGS += -I$(STD_PERIPH_LIB) 
CFLAGS += -I$(STD_PERIPH_LIB)/CMSIS/Device/ST/STM32F30x/Include
CFLAGS += -I$(STD_PERIPH_LIB)/CMSIS/Include 
CFLAGS += -I$(STD_PERIPH_LIB)/STM32F30x_StdPeriph_Driver/inc
CFLAGS += -I$(STD_PERIPH_LIB)/STM32_USB-FS-Device_Driver/inc
CFLAGS += -DUSE_STDPERIPH_DRIVER

STARTUP = Device/startup_stm32f30x.s # add startup file to build

OBJS = $(addprefix objs/,$(SRCS:.c=.o))
DEPS = $(addprefix deps/,$(SRCS:.c=.d))

OBJS_PERIPH = $(addprefix objs/,$(SRCS_PERIPH:.c=.o))
DEPS_PERIPH = $(addprefix deps/,$(SRCS_PERIPH:.c=.d))

###################################################

.PHONY: all lib proj program debug clean reallyclean

all: $(LIB) proj

-include $(DEPS)

$(LIB): $(OBJS_PERIPH)
 @echo [AR] $@
 @$(AR) -r $@ $(OBJS_PERIPH)

proj: bins/$(PROJ_NAME).elf

dirs:
 @mkdir -p deps objs bins
 @touch dirs

objs/%.o : %.c dirs
 @echo [OBJ] $<
 @$(CC) $(CFLAGS) -c -o $@ $< -MMD -MF deps/$(*F).d

bins/$(PROJ_NAME).elf: $(OBJS)
 @$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ $(STARTUP) -L$(STD_PERIPH_LIB) -L. -lstm32f3 -L$(LDSCRIPT_INC) -Tstm32f3.ld
 @$(OBJCOPY) -O ihex bins/$(PROJ_NAME).elf bins/$(PROJ_NAME).hex
 @$(OBJCOPY) -O binary bins/$(PROJ_NAME).elf bins/$(PROJ_NAME).bin
 @$(OBJDUMP) -St bins/$(PROJ_NAME).elf > bins/$(PROJ_NAME).lst
 @$(SIZE) bins/$(PROJ_NAME).elf

program: all
 @openocd -f $(OPENOCD_BOARD_DIR)/stm32f3discovery.cfg -f $(OPENOCD_PROC_FILE) -c "stm_flash `pwd`/bins/$(PROJ_NAME).bin" -c shutdown

debug: program
 @$(GDB) -x extra/gdb_cmds bins/$(PROJ_NAME).elf

clean:
 @echo [CLEAN]
 @find ./ -name '*~' | xargs rm -f 
 @rm -rf objs
 @rm -rf deps
 @rm -rf bins
 @rm -f dirs
 @rm -f $(LIB)

reallyclean: clean
 @$(MAKE) -C $(STD_PERIPH_LIB) clean

Deux étapes sont nécessaires pour la compilation du projet, la première, compilation des sources des drivers périphériques et création d'une librairie statique et la deuxième, compilation des sources du projet et linkage avec la librairie statique.

Différentes sous-commandes sont présentes, dans ce Makefile, pour faciliter la compilation du projet, la programmation du micro contrôleur et le débogage de celui-ci.

Compilation du projet :
# make clean all

Programmation de la cible :
# make program

Débogage de la cible :
# make debug

Chaîne de compilation croisée GNU


Bien sur, il n'est pas nécessaire de créer sa propre chaîne de compilation, il est possible d'en télécharger une. Vous en trouverez sur le site de Launchpad.net, rubrique GNU Tools for ARM embedded processors. Les avantages de télécharger la chaîne sont, premièrement, de l'installer sur l'OS que vous souhaitez (Windows, Mac ou Linux), deuxièmement, de pouvoir l'utiliser sur de nombreux micros, tel que Cortex M0, M3, M4, etc ...

Pour connaître toutes les architectures supportées par la chaîne de compilation croisée, il suffit de lancer la commande :

./arm-none-eabi-gcc -print-multi-lib
.;
thumb;@mthumb
fpu;@mfloat-abi=hard
armv6-m;@mthumb@march=armv6s-m
armv7-m;@mthumb@march=armv7-m
armv7e-m;@mthumb@march=armv7e-m
armv7-r/thumb;@mthumb@march=armv7-r
armv7e-m/softfp;@mthumb@march=armv7e-m@mfloat-abi=softfp@mfpu=fpv4-sp-d16
armv7e-m/fpu;@mthumb@march=armv7e-m@mfloat-abi=hard@mfpu=fpv4-sp-d16
armv7-r/thumb/softfp;@mthumb@march=armv7-r@mfloat-abi=softfp@mfpu=vfpv3-d16
armv7-r/thumb/fpu;@mthumb@march=armv7-r@mfloat-abi=hard@mfpu=vfpv3-d16

Les différents types d'architectures sont :
  • Architecture ARMv6-M : Cortex-M0, Cortex-M0+ et Cortex-M1
  • Architecture ARMv7-M : Cortex-M3
  • Architecture ARMv7E-M : Cortex-M4
  • Architecture ARMv7-R : Cortex-R4 (processeur temps-réel)


Cependant, cela implique quelques modifications du Makefile du Template pour préciser le type de micro, ainsi que les options qui vont avec.

# put your *.c source files here, make should handle the rest!
SRCS = main.c errno.c stm32f3_discovery.c system_stm32f30x.c

# Periph driver sources
SRCS_PERIPH = stm32f30x_adc.c stm32f30x_can.c stm32f30x_comp.c stm32f30x_crc.c \
     stm32f30x_dac.c stm32f30x_dbgmcu.c stm32f30x_dma.c \
     stm32f30x_exti.c stm32f30x_flash.c stm32f30x_gpio.c \
     stm32f30x_i2c.c stm32f30x_iwdg.c stm32f30x_misc.c stm32f30x_opamp.c \
     stm32f30x_pwr.c stm32f30x_rcc.c stm32f30x_rtc.c stm32f30x_spi.c \
     stm32f30x_syscfg.c stm32f30x_tim.c stm32f30x_usart.c \
     stm32f30x_wwdg.c usb_core.c usb_init.c usb_int.c usb_mem.c \
     usb_regs.c usb_sil.c

# all the files will be generated with this name (main.elf, main.bin, main.hex, etc)
PROJ_NAME=blink_led

# Location of the Libraries folder from the STM32F3 Standard Peripheral Library
STD_PERIPH_LIB=<PATH_TO_LIBRARIES_FILES>/STM32F3-Discovery_FW_V1.1.0/Libraries

# Location of the linker scripts
LDSCRIPT_INC=Device/ldscripts

# location of OpenOCD Board .cfg files (only used with 'make program')
OPENOCD_BOARD_DIR=<PATH_TO_OPENOCD_BOARD_SCRIPT>

# Configuration (cfg) file containing programming directives for OpenOCD
OPENOCD_PROC_FILE=extra/stm32f3-openocd.cfg

# toolchain path
TOOLCHAIN=<PATH_TO_TOOLCHAIN>/gcc-arm-none-eabi-4_7-2012q4/bin

TOOLCHAIN_TARGET=$(TOOLCHAIN)/arm-none-eabi-

# that's it, no need to change anything below this line!

###################################################

CC = $(TOOLCHAIN_TARGET)gcc
GDB = $(TOOLCHAIN_TARGET)gdb
OBJCOPY = $(TOOLCHAIN_TARGET)objcopy
OBJDUMP = $(TOOLCHAIN_TARGET)objdump
SIZE = $(TOOLCHAIN_TARGET)size

LIB = libstm32f3.a

CFLAGS  = -Wall -g -std=c99 -Os  
CFLAGS += -mlittle-endian -mcpu=cortex-m4 -march=armv7e-m -mthumb
CFLAGS += -mfpu=fpv4-sp-d16 -mfloat-abi=hard
CFLAGS += -ffunction-sections -fdata-sections

LDFLAGS += -Wl,--gc-sections -Wl,-Map=bins/$(PROJ_NAME).map

###################################################

vpath %.a $(STD_PERIPH_LIB)
vpath %.c $(STD_PERIPH_LIB)/STM32F30x_StdPeriph_Driver/src
vpath %.c $(STD_PERIPH_LIB)/STM32_USB-FS-Device_Driver/src
vpath %.c src

ROOT=$(shell pwd)

CFLAGS += -Iinc 
CFLAGS += -I$(STD_PERIPH_LIB) 
CFLAGS += -I$(STD_PERIPH_LIB)/CMSIS/Device/ST/STM32F30x/Include
CFLAGS += -I$(STD_PERIPH_LIB)/CMSIS/Include 
CFLAGS += -I$(STD_PERIPH_LIB)/STM32F30x_StdPeriph_Driver/inc
CFLAGS += -I$(STD_PERIPH_LIB)/STM32_USB-FS-Device_Driver/inc
CFLAGS += -DUSE_STDPERIPH_DRIVER

STARTUP = Device/startup_stm32f30x.s # add startup file to build

OBJS = $(addprefix objs/,$(SRCS:.c=.o))
DEPS = $(addprefix deps/,$(SRCS:.c=.d))

OBJS_PERIPH = $(addprefix objs/,$(SRCS_PERIPH:.c=.o))
DEPS_PERIPH = $(addprefix deps/,$(SRCS_PERIPH:.c=.d))

###################################################

.PHONY: all lib proj program debug clean reallyclean

all: $(LIB) proj

-include $(DEPS)

$(LIB): $(OBJS_PERIPH)
 @echo [AR] $@
 @$(AR) -r $@ $(OBJS_PERIPH)

proj: bins/$(PROJ_NAME).elf

dirs:
 @mkdir -p deps objs bins
 @touch dirs

objs/%.o : %.c dirs
 @echo [OBJ] $<
 @$(CC) $(CFLAGS) -c -o $@ $< -MMD -MF deps/$(*F).d

bins/$(PROJ_NAME).elf: $(OBJS)
 @$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ $(STARTUP) -L$(STD_PERIPH_LIB) -L. -lstm32f3 -L$(LDSCRIPT_INC) -Tstm32f3.ld
 @$(OBJCOPY) -O ihex bins/$(PROJ_NAME).elf bins/$(PROJ_NAME).hex
 @$(OBJCOPY) -O binary bins/$(PROJ_NAME).elf bins/$(PROJ_NAME).bin
 @$(OBJDUMP) -St bins/$(PROJ_NAME).elf > bins/$(PROJ_NAME).lst
 @$(SIZE) bins/$(PROJ_NAME).elf

program: all
 @openocd -f $(OPENOCD_BOARD_DIR)/stm32f3discovery.cfg -f $(OPENOCD_PROC_FILE) -c "stm_flash `pwd`/bins/$(PROJ_NAME).bin" -c shutdown

debug: program
 @$(GDB) -x extra/gdb_cmds bins/$(PROJ_NAME).elf

clean:
 @echo [CLEAN]
 @find ./ -name '*~' | xargs rm -f 
 @rm -rf objs
 @rm -rf deps
 @rm -rf bins
 @rm -f dirs
 @rm -f $(LIB)

reallyclean: clean
 @$(MAKE) -C $(STD_PERIPH_LIB) clean

Programmation du micro


La sonde JTAG est directement intégrée sur la carte de démo via un micro stlink v2. Sous windows, les drivers de cette sonde sont directement téléchargeable sur le site de chez ST. Par contre sous linux, c'est un peu plus galère, surtout si vous utilisez, comme moi, une machine virtuelle.
Sur virtualbox, ça ne fonctionne juste pas !!! Par contre, sur VMWare, cela fonctionne moyennant un ajout dans les règles udev.

Dans le dossier /etc/udev/rules.d, il faut rajouter la règle S49-stlinkv2.rules :
# cd /etc/udev/rules.d/
# sudo touch S49-stlinkv2.rules
# vim touch S49-stlinkv2.rules

et copier le texte ci-dessous :
# stm32 discovery boards, with onboard st/linkv2
# ie, STM32L, STM32F4.
# STM32VL has st/linkv1, which is quite different

SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3748", \
    MODE:="0666", \
    SYMLINK+="stlinkv2_%n"

# If you share your linux system with other users, or just don't like the
# idea of write permission for everybody, you can replace MODE:="0666" with
# OWNER:="yourusername" to create the device owned by you, or with
# GROUP:="somegroupname" and mange access using standard unix groups.


Windows


Le logiciel windows s'appelle STM32 ST-LINK Utility et permet de programmer les cibles STM32 Cortex sans trop de soucis. Après avoir installer les drivers de la sonde JTAG, il suffit de lancer le logiciel.


L'onglet Target permet de connecter la carte puis de la programmer. Il accepte comme fichier d'entrée le binaire ".HEX".


Je ne vais pas trop m'attarder sur le logiciel Windows. Passons maintenant aux choses sérieuses.

Linux



Le premier outil utilisé pour la programmation du micro s'appelle stlink, du même nom que la sonde JTAG de la carte. Les sources disponibles sous github (ci-dessous) permettent de compiler les outils sous Linux.

Repository des utilitaires de programmation pour la sonde JTAG stlink v2 pour les micros cortex de chez STM32 :


Installation des outils :
# sudo apt-get install libusb-1.0 libusb-1.0-dev pkg-config autotools
# git clone git://github.com/texane/stlink.git stlink
# cd stlink
# ./autogen.sh
# ./configure
# make

Deux utilitaires sont compilés :
  • st-flash : un outil de manipulation de la flash
  • st-utils : un serveur GDB (non abordé dans ce tutoriel)

Voici quelques exemples de commandes pour le flashage du binaire fraîchement compilé :

Commande de lecture de 4096 octets de la flash du micro, à partir de l'adresse 0x8000000, dans le fichier out.bin
# ./st−flash read out.bin 0x8000000 4096

Commande d'écriture du fichier in.bin dans la flash du micro à l'adresse 0x8000000
# ./st−flash write in.bin 0x8000000

PS : L'adresse 0x8000000 correspond à l'adresse de début de la plage mémoire (0x8000000 à 0x8040000 => 256 KOctets) de la flash interne du micro d'après le mapping mémoire de la datasheet.

OpenOCD (Open On-Chip Debugger)


OpenOCD est un logiciel qui permet de débugger/programmer un code s'exécutant sur un processeur en utilisant l'interface JTAG. Ce logiciel libre fait l'intermédiaire entre le logiciel de debug et l'interface matérielle qui permet l'accès au JTAG.

Il offre trois interfaces d'utilisation :
  • Un serveur GDB, permettant l'utilisation de gnu debugger
  • Une interface telnet pour passer directement des commandes
  • Une interface TCL, permettant d'utiliser ce langage de script

OpenOCD reconnait de nombreux adaptateur JTAG :
  • Interfaces parallèles
  • Interface USB (FTDI, ...)

Installation de l'outil 


Récupération des sources d'openocd :
# git clone git://git.code.sf.net/p/openocd/code openocd-code

Compilation et installation :
# ./bootstrap
# ./configure --enable-maintainer-mode --enable-stlink
# make
# make install

Programmation grâce à OpenOCD et au Template du projet



On reprend en détail la partie programmation du micro avec le makefile :

program: all
 @openocd -f $(OPENOCD_BOARD_DIR)/stm32f3discovery.cfg -f $(OPENOCD_PROC_FILE) -c "stm_flash `pwd`/bins/$(PROJ_NAME).bin" -c shutdown

Il lance l'utilitaire OpenOCD avec comme configuration de carte stm32f3discovery.cfg, comme directives de programmation stm32f3-openocd.cfg et deux commandes (première pour la programmation et la deuxième pour la fermeture de la communication).

le fichier stm32f3-openocd.cfg, on retrouve, comme sur l'autre outil, une écriture en flash à l'adresse de début 0x08000000 :
init

proc stm_flash {IMGFILE} {
        reset halt
        sleep 100
        wait_halt 2
        flash write_image erase $IMGFILE 0x08000000
        sleep 100 
        verify_image $IMGFILE 0x08000000
        sleep 100
        reset run
}

proc stm_erase {} {
        reset halt
        sleep 100
        stm32f1x mass_erase 0
        sleep 100
}

Pour programmer le micro avec le programme fraîchement compilé, on lance la commande :
# make program
Open On-Chip Debugger 0.7.0-dev-00167-g57aa19f (2013-03-04-14:27)
Licensed under GNU GPL v2
For bug reports, read
 http://openocd.sourceforge.net/doc/doxygen/bugs.html
srst_only separate srst_nogate srst_open_drain connect_deassert_srst
Info : This adapter doesn't support configurable speed
Info : STLINK v2 JTAG v16 API v2 SWIM v0 VID 0x0483 PID 0x3748
Info : Target voltage: 2.878032
Info : stm32f3x.cpu: hardware has 6 breakpoints, 4 watchpoints
stm_erase
target state: halted
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x0800040c msp: 0x20008000
auto erase enabled
Info : device id = 0x10036422
Info : flash size = 256kbytes
wrote 4096 bytes from file /home/sinseman44/cortex_M4/stm32f3_blink_led/bins/blink_led.bin in 0.938627s (4.262 KiB/s)
verified 2216 bytes in 0.278803s (7.762 KiB/s)
shutdown command invoked


Débogage grâce à OpenOCD et au Template du projet


Attention : Le débogage, pour le moment n'est possible que si on utilise la chaîne de compilation croisée téléchargée sur le site de Launchpad, suite à un bug sur la version de GDB de crosstool-NG.

On reprend en détail la partie débogage du micro avec le makefile :
debug: program
 @$(GDB) -x extra/gdb_cmds bins/$(PROJ_NAME).elf

Il lance la commande de débogage arm-none-eabi-gdb avec comme fichier de configuration gdb-cmds et le binaire à déboguer.
GDB communique avec OpenOCD de deux façons différentes :
  • une connexion par socket TCP/IP.
    • exemple : target remote localhost:3333
  • une connexion par pipe. Ça a l'avantage que GDB à la main sur OpenOCD et peut l'arrêter à tout  moment.
    • exemple : target remote | openocd -c "gdb_port pipe; log_output openocd.log"

Le fichier de configuration gdb-cmds :
target remote | openocd -f /usr/share/openocd/scripts/board/stm32f0discovery.cfg -c "gdb_port pipe; log_output openocd.log"
monitor reset halt
load

La commande à lancer pour le débogage est la suivante :
#make debug
Open On-Chip Debugger 0.7.0-dev-00167-g57aa19f (2013-03-04-14:27)
Licensed under GNU GPL v2
For bug reports, read
 http://openocd.sourceforge.net/doc/doxygen/bugs.html
srst_only separate srst_nogate srst_open_drain connect_deassert_srst
Info : This adapter doesn't support configurable speed
Info : STLINK v2 JTAG v16 API v2 SWIM v0 VID 0x0483 PID 0x3748
Info : Target voltage: 2.900648
Info : stm32f3x.cpu: hardware has 6 breakpoints, 4 watchpoints
stm_erase
target state: halted
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x08000458 msp: 0x20008000
auto erase enabled
Info : device id = 0x10036422
Info : flash size = 256kbytes
wrote 4096 bytes from file /home/sinseman44/cortex_M4/stm32f3_blink_led/bins/blink_led.bin in 1.038872s (3.850 KiB/s)
verified 2216 bytes in 0.353893s (6.115 KiB/s)
shutdown command invoked
GNU gdb (GNU Tools for ARM Embedded Processors) 7.4.1.20121207-cvs
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=i686-linux-gnu --target=arm-none-eabi".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/sinseman44/cortex_M4/stm32f3_blink_led/bins/blink_led.elf...done.
Open On-Chip Debugger 0.7.0-dev-00167-g57aa19f (2013-03-04-14:27)
Licensed under GNU GPL v2
For bug reports, read
 http://openocd.sourceforge.net/doc/doxygen/bugs.html
srst_only separate srst_nogate srst_open_drain connect_deassert_srst
0x00000000 in ?? ()
target state: halted
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x0800040c msp: 0x20008000
Loading section .isr_vector, size 0x188 lma 0x8000000
Loading section .text, size 0x6d4 lma 0x8000188
Loading section .data, size 0x4c lma 0x800085c
Start address 0x800040d, load size 2216
Transfer rate: 2 KB/sec, 738 bytes/write.
(gdb) b main
Breakpoint 1 at 0x80001a0: file src/main.c, line 30.
(gdb) continue
Continuing.
Note: automatically using hardware breakpoints for read-only addresses.

Breakpoint 1, main () at src/main.c:30
30 {  

La petite astuce qui tue pour avoir le multi-windows sous GDB : CTRL x puis a :
┌──src/main.c───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
   │22      }                                                                                                                                                  │
   │23                                                                                                                                                         │
   │24      /**                                                                                                                                                │
   │25        * @brief  Main program.                                                                                                                          │
   │26        * @param  None                                                                                                                                   │
   │27        * @retval None                                                                                                                                   │
   │28        */                                                                                                                                               │
   │29      int main(void)                                                                                                                                     │
B+>│30      {                                                                                                                                                  │
   │31        /* SysTick end of count event each 10ms */                                                                                                       │
   │32        RCC_GetClocksFreq(&RCC_Clocks);                                                                                                                  │
   │33        SysTick_Config(RCC_Clocks.HCLK_Frequency / 100);                                                                                                 │
   │34                                                                                                                                                         │
   │35        /* Initialize LEDs and User Button available on STM32F3-Discovery board */                                                                       │
   │36        STM_EVAL_LEDInit(LED3);                                                                                                                          │
   │37        STM_EVAL_LEDInit(LED4);                                                                                                                          │
   │38        STM_EVAL_LEDInit(LED5);                                                                                                                          │
   │39        STM_EVAL_LEDInit(LED6);                                                                                                                          │
   │40        STM_EVAL_LEDInit(LED7);                                                                                                                          │
   └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
remote Remote target In: main                                                                                                          Line: 30   PC: 0x80001a0 
(gdb) cont
Continuing.
Note: automatically using hardware breakpoints for read-only addresses.

Breakpoint 1, main () at src/main.c:30
(gdb) 



Aucun commentaire:

Enregistrer un commentaire