Académique Documents
Professionnel Documents
Culture Documents
7 octobre 2020
L’objectif de ce document est d’expliquer comment mettre en œuvre le Cortex A7 sous GNU/Linux
et d’en programmer le Cortex M4 du STM32MP1 afin de les faire communiquer.
L’image GNU/Linux s’exécutant sur le Cortex-A7 du STM32MP1 est issue de Buildroot, dont la
chaı̂ne de compilation croisée est obtenue par
make stm32mp157_dk_defconfig puisque T. Petazzoni de Bootlin 1 a inclus la configuration de cette
plateforme dans Buildroot. Cependant, par rapport à cette documentation qui propose d’utiliser une
branche séparée maintenant (Nov. 2019) obsolète, nous restons sur la branche master de Buildroot (git
checkout master) et configurons
make stm32mp157c_dk2_defconfig 2 Par rapport à la configuration par défaut, nous ajoutons le support
pour WCHAR de la chaı̂ne de compilation croisée ainsi que le serveur ssh dropbear (make linux-menuconfig)
ainsi que éventuellement screen, et vérifions le support de IIO dans le noyau (make linux-menuconfig).
La communication avec le STM32MP157 se fait initialement par le port série virtuel créé sur le
connecteur USB-microB en /dev/ttyACM0. Aprés avoir configuré l’IP statique de l’interface Ethernet
dans /etc/network/interfaces :
auto eth0
iface eth0 inet static
address 192.168.1.30
netmask 255.255.255.0
gateway 192.168.1.1
et ajouté un mot de passe (passwd) à root, la connexion par ssh est fonctionnelle (notamment pour
copier des fichiers par scp).
Nous avons initialement tenté de compiler un programme trivial pour Cortex-M4 et le transférer
depuis le A7 (description de la procédure ci-dessous) pour constater qu’il manque au binaire ELF une
partie de l’entête que sont la table des ressources. N’ayant pas identifié de façon simple d’ajouter cet
entête, et ayant constaté que nombre de projets exploitant le mode de communication A7-M4 (ou MPU-
MCU dans la nomenclature ST) nécessite un environnement exécutif temps-réel, nous nous proposerons
d’exécuter Zephyr sur le M4.
1 Compilation de Zephyr
La nouvelle mode 3 semble être de placer les exécutables compilés par l’utilisateur dans un répertoire
.local. Nous commençons donc par export PATH=$PATH:$HOME/.local/bin
L’installation de Zephyr est très bien décrite sur leur site : après avoir installé leur outil west (il
serait souhaitable de s’affranchir de cette étape en git clonant à la main), nous complétons l’installation
de Zephyr par
Comme nous ne voulons pas encore installer une toolchain de plus puisque notre classique arm-none-eabi-gcc
fonctionne très bien, nous complétons dans le répertoire zephyr la liste des variables d’environnement
de zephyr-env.sh par
export ZEPHYR_TOOLCHAIN_VARIANT=cross-compile
export CROSS_COMPILE=/usr/bin/arm-none-eabi-
1. https://bootlin.com/blog/building-a-linux-system-for-the-stm32mp1-basic-system/
2. modification du 27 octobre 2019 :“configs/stm32mp157 dk : rename to the sm32mp157c dk2”
3. https://docs.zephyrproject.org/latest/getting_started/index.html indique que pip place ses binaires dans ce
répertoire
1
puis nous sourçons ce fichier pour charger les variables d’environnement (à refaire évidemment chaque fois
que nous utiliserons Zephyr dans un nouveau terminal). Dans notre cas, nous utilisons arm-none-eabi-gcc
des paquets Debian/GNU Linux gcc-arm-none-eabi et binutils-arm-none-eabi. À titre d’informa-
tion, ZEPHYR TOOLCHAIN VARIANT doit être une des options parmi celles décrites dans
zephyr/cmake/toolchain/gnuarmemb/.
Nous allons compiler notre premier exemple pour vérifier le bon fonctionnement de la toolchain par
(en partant du répertoire zephyr) :
cd samples/basic/blinky/
mkdir build
cd build
cmake -DBOARD=olimexino_stm32 ../ # commencons simple par une STM32F103
make
cd zephyr
arm-none-eabi-objcopy -O binary zephyr.elf zephyr.bin
stm32flash.sh -g 0x0 -w zephyr.bin /dev/ttyUSB0 # tester sur un board contenant le STM32F103
L’utilisateur possédant une plateforme contenant un STM32F103 pourra valider le bon fonctionne-
ment du code de clignotement de LED. Pour donner une idée de la taille du binaire, cet exemple trivial
occupe 12028 octets.
Bien que cet exemple ne fonctionne pas dans l’émulateur qemu porté au STM32F103 par André
Beckus, Zephyr propose sa propre version de l’émulateur, qui n’est cependant pas très verbeux sur les
accès aux périphériques autres que le port série de communication.
Ainsi, par cmake -DBOARD=qemu cortex m3 dans le répertoire samples/hello world de zephyr nous
obtenons un binaire pour l’émulateur qemu fourni par Zephyr qui répond bien (make run) par
To exit from QEMU enter: ’CTRL+a, x’
[QEMU] CPU: cortex-m3
qemu-system-arm: warning: nic stellaris_enet.0 has no peer
***** Booting Zephyr OS build zephyr-v2.0.0 *****
Hello World! qemu_cortex_m3
QEMU: Terminated
[100%] Built target run
Ce même exemple, hello world, fonctionne sur STM32F4-discovery et affiche sur la broche PA2
(USART TX)
***** Booting Zephyr OS build zephyr-v2.0.0 *****
Hello World! stm32f4_disco
si on compile par cmake -DBOARD=stm32f4\_disco ../ && make && make flash
Maintenant que nous sommes convaincus du bon fonctionnement de Zephyr sur STM32Fx, nous
pouvons sereinement aborder le STM32MP157. Afin de faire clignoter la LED orange connectée sur la
broche 7 du port H 4 , nous considérons le programme blinky modifié de la façon suivante
#i n c l u d e <z e p h y r . h>
#i n c l u d e <d e v i c e . h>
#i n c l u d e <d r i v e r s / g p i o . h>
#d e f i n e LED PORT " GPIOH "
#d e f i n e LED 7
#d e f i n e SLEEP TIME 1000
v o i d main ( v o i d )
{
u32 t cnt = 0 ;
s t r u c t d e v i c e ∗ dev ;
dev = d e v i c e g e t b i n d i n g (LED PORT) ;
g p i o p i n c o n f i g u r e ( dev , LED, GPIO DIR OUT) ;
2
while (1) {
g p i o p i n w r i t e ( dev , LED, c n t % 2 ) ;
c n t ++;
k s l e e p (SLEEP TIME) ;
}
}
Ce programme est compilé pour le STM32MP157 en configurant par cmake -DBOARD=stm32mp157c_dk2 ../.
Le binaire au format ELF généré dans le répertoire zephyr du répertoire de compilation est transféré
(scp après avoir installé dropbear dans Buildroot du MP157 et ajouté un mot de passe à root) dans le
répertoire /lib/firmware (à créer à son premier accès car il n’existe pas par défaut), puis 5
La LED doit clignoter, tel que le prouve jmfriedt.org/MOV_0298.mp4, après chargement du firmware
et dmesg indique
3
2 Accès aux ADCs
ST Microelectronics fournit les pilotes IIO 7 pour accéder aux convertisseurs analogiques numériques
qui sont convenablement définis dans le devicetree 8 . Ainsi, la lecture des mesures se fait trivialement
par
# pwd
/sys/bus/iio/devices/iio:device0
# cat in_voltage0_raw
2704
Plus intéressant, la mesure en continu des échantillons s’obtient en jouant avec un timer pour
déclencher les conversions 9 :
AIN0 et AIN1 sont sur ADC2, d’où l’utilisation de iio:device1. Ces broches sont compatibles sur
les deux broches du milieu (3 et 4) du “petit connecteur compatible Arduino”.
Le format des données issues du /dev/iio* est décrit à 10 comme une mesure interlacée des traces
actives (ici 2) suivi d’un horodatage.
4
Figure 1 – Connexion du port USART3 vers un convertisseur RS232-USB pour observer les trames
émises par le M4.
aux quatre connecteurs USB-A, i.e. du côté du port USB-C d’alimentation, il s’agit de la 3ème broche
la sur le bord de la carte pour la masse et de la quatrième pour USART3/TX : Fig. 3) 11
Le résultat, lors du chargement du programme suivant dans le M4,
#i n c l u d e <z e p h y r . h>
#i n c l u d e <s y s / p r i n t k . h>
#i n c l u d e <d e v i c e . h>
#i n c l u d e <d r i v e r s / g p i o . h>
v o i d main ( v o i d )
{ i n t cnt = 0 ;
s t r u c t d e v i c e ∗ dev ;
dev = d e v i c e g e t b i n d i n g (LED PORT) ;
g p i o p i n c o n f i g u r e ( dev , LED, GPIO DIR OUT) ;
while (1) {
p r i n t k ( " Hello World ! % s \ n " , CONFIG BOARD) ;
g p i o p i n w r i t e ( dev , LED, c n t % 2 ) ;
c n t ++;
k s l e e p (SLEEP TIME) ;
}
}
doit être une LED qui clignote (indiquant que les horloges ont bien été configurées et donc que le
processeur n’a pas cessé son exécution lors de la configuration des périphériques) et l’affichage sur le port
série de
***** Booting Zephyr OS build zephyr-v2.0.0-1957-g2d4d6f05e60e *****
Hello World! stm32mp157c_dk2
Hello World! stm32mp157c_dk2
Hello World! stm32mp157c_dk2
Hello World! stm32mp157c_dk2
4 Communication MPU–MCU
La communication MPU–MCU ne semble pas (encore) officiellement supportée par Zephyr. Nous
devons donc nous appuyer sur la branche d’Arnaud Pouliquen à https://github.com/arnopo/. Pour
ce faire :
1. cloner le dépôt en passant par west qui se chargera ensuite de télécharger toutes les dépendances :
west init -m https://github.com/arnopo/zephyr_stm32mp1.git --mr OpenAMP_rsc_table_sample
11. voir page 10 du schéma de https://www.st.com/content/ccc/resource/technical/layouts_and_diagrams/
schematic_pack/group0/36/8e/ea/7a/ca/ca/4b/e4/mb1272-dk2-c01_schematic/files/MB1272-DK2-C01_Schematic.pdf
pour constater que le brochage de CN2 assigne EXP GPIO14 à la broche 8 tandis que 6 est à la masse, puisque
EXP GPIO14 et USART3 TX sur le schéma de gauche.
5
2. mettre à jour le dépôt
west update
3. effacer le répertoire de cache de Zephyr qui a été source de bien des déboirs
rm -rf $HOME/.cache/zephyr
4. analyser le code disponible dans
zephyr/samples/subsys/ipc/openamp_o_uart/src/remote et le compiler par
mkdir build && cd build && cmake -DBOARD=stm32mp157c_dk2 ../ && make
5. envoyer le fichier .elf résultant dans zephyr sur le STM32MP157 (répertoire /lib/firmware
6. télécharger le module noyau depuis
https://elixir.bootlin.com/linux/latest/source/samples/rpmsg/rpmsg_client_sample.c
(nous avons du copier-coller le code source, n’ayant pas trouvé de solution pour obtenir le code
source sans le formatage HTML !)
7. rédiger le Makefile pour compiler contre le noyau fourni par Buildroot pour le STM32MP157.
Dans notre cas, ce Makefile ressemble à
PATH:=$(PATH):/mnt/sdb2/stm32mp1/buildroot/output/host/usr/bin/
obj-m += rpmsg_client_sample.o
all:
make ARCH=arm CROSS_COMPILE=arm-buildroot-linux-uclibcgnueabihf- -C \
/mnt/sdb2/stm32mp1/buildroot/output/build/linux-custom/ M=$(PWD) modules
clean:
rm *.o *.ko *.mod.c .*.cmd
en supposant que Buildroot se trouve dans /mnt/sdb2/stm32mp1/buildroot/
Une fois ces étapes achevées, nous configurons le cœur M4 comme nous l’avons déjà vu par
echo zephyr_openamp_rsc_table.elf > /sys/class/remoteproc/remoteproc0/firmware
echo start > /sys/class/remoteproc/remoteproc0/state
qui doit se traduire par les messages suivants dans les logs du noyau (dmesg)
[ 105.197021] remoteproc remoteproc0: Booting fw image zephyr_openamp_rsc_table.elf, size 556960
[ 105.213691] rproc-srm-core m4@0:m4_system_resources: bound m4@0:m4_system_resources:serial@4000f00
[ 105.230464] m4@0#vdev0buffer: assigned reserved memory node vdev0buffer@10044000
[ 105.244212] virtio_rpmsg_bus virtio0: creating channel rpmsg-client-sample addr 0x0
[ 105.258162] virtio_rpmsg_bus virtio0: rpmsg host is online
[ 105.269473] m4@0#vdev0buffer: registered virtio0 (type 7)
[ 105.280667] remoteproc remoteproc0: remote processor m4 is now up
Une fois les canaux de communication créés, nous chargeons (insmode) le module noyau rpmsg_client_sample.ko
pour obtenir
6
5 Accès à un périphérique matériel connecté sur bus SPI
Zephyr propose, pour le STM32MP157, le support du bus SPI, et en particulier SPI4 sur les broches
“compatibles Arduino”. Plusieurs octets peuvent être écrits ou lus séquentiellement sur le bus en activant
le signal de Chip Select (Slave Select) automatiquement : nous vérifions que ce signal ne se relève pas
entre chaque octet transmis/lu.
L’exercice porte sur le convertisseur analogique-numérique LTC1407A, sélectionné pour sa capacité
à être déclenché par un signal externe pour mémoriser la tension d’entrée avec une bande passante de
18 GHz. Malgré un débit modeste, ce convertisseur est approprié pour les mesures de RADAR sous
hypothèse de stationnarité de l’environnement pour une mesure stroboscopique.
La connexion se fait de la façon suivante :
v o i d main ( v o i d )
{ struct device ∗ spi ;
s p i = d e v i c e g e t b i n d i n g ( DT SPI 4 NAME ) ;
i f ( ! s p i ) { p r i n t k ( " Could not find SPI driver \ n " ) ; r e t u r n ; }
s t r u c t s p i c o n f i g ∗ r e a d c o n f = &i n r e a d c o n f ;
7
s t r u c t s p i c o n f i g ∗ w r i t e c o n f = &i n w r i t e c o n f ;
u 8 t d j c b t x =0x55 ;
u8 t djcb rx [ 4 ] ;
while (1)
{ i f ( m y s p i r e a d ( s p i , r e a d c o n f , d j c b r x , s i z e o f ( d j c b r x ) ) ) { p r i n t k ( " Read error \ n " ) ; }
e l s e { show array ( djcb rx , s i z e o f ( djcb rx ) ) ; }
}
}
Un exemple de résultat de mesure lorsque nous faisons varier le potentiel d’une alimentation entre
les broches CH1- et CH1+ entre 0 et environ 2 V est fournie dans la Fig. 2.
4000 ’t’
3500
3000
ADC value (bit)
2500
2000
1500
1000
500
0
0 100000 200000 300000 400000 500000 600000
sample number (a.u.)
Figure 2 – Haut : résultat d’une mesure du LTC1407A connecté au port “Arduino” (SPI4) du
STM32MP157. Bas : chronogrammes des transactions sur bus SPI (en vert MISO, en jaune CLK, en
orange NSS connecté à CONV du convertisseur.
Nous constatons que l’envoi des mesures par la console virtuelle (interface trace0) induit de nom-
breuses pertes de données si le débit est aussi élevé que la mesure du convertisseur (quelque dizaines
de kcaractères/seconde). Il faut donc envisager une transaction par RPMSG en double-tampon protétée
par sémaphore pour garantir l’intégrité des messages échangés.
8
6 Lecture/écriture des registres du S2LP par SPI depuis le M4
On prendra soin de déplacer les résistances de CLK et CS# pour router ces signaux vers les broches
du connecteur compatible Arduino du STM32MP157C-DK2 et non vers leur position par défaut qui ne
correspond pas au routage de la carte mère 12 .
#i n c l u d e <e r r n o . h>
#i n c l u d e <z e p h y r . h>
#i n c l u d e <s y s / p r i n t k . h>
#i n c l u d e <d e v i c e . h>
#i n c l u d e <d r i v e r s / s p i . h>
#i n c l u d e <d r i v e r s / g p i o . h>
#d e f i n e N 12
v o i d s h o w a r r a y ( u 8 t ∗ my array , u 8 t a r r a y l e n )
{
u8 t inc ;
f o r ( i n c =0; i n c <a r r a y l e n ; i n c ++) p r i n t k ( " %02 x " , my array [ i n c ] ) ;
pr int k ( "\n" ) ;
}
v o i d main ( v o i d )
{ struct device ∗ spi ;
int k ;
p r i n t k ( " dans le main ( N =% d ) \ n " ,N) ;
s p i = d e v i c e g e t b i n d i n g ( DT SPI 4 NAME ) ;
i f ( ! s p i ) { p r i n t k ( " Could not find SPI driver \ n " ) ; r e t u r n ; }
9
cd /sys/kernel/debug/remoteproc/remoteproc0/
echo stop > /sys/class/remoteproc/remoteproc0/state
echo start > /sys/class/remoteproc/remoteproc0/state
cat trace0
*** Booting Zephyr OS build zephyr-v2.1.0-581-g4e135d76a3c2 ***
dans le main (N=12)
00: 52 00 01 00 0a 00 a2 00 a2 00 a2 00
01: 52 00 01 00 a2 00 a2 00 a2 00 00 00
02: 52 00 01 00 a2 00 a2 00 00 00 42 00
03: 52 00 01 00 a2 00 00 00 42 00 16 00
04: 52 00 01 00 00 00 42 00 16 00 27 00
05: 52 00 01 00 42 00 16 00 27 00 62 00
06: 52 00 01 00 16 00 27 00 62 00 2a 00
07: 52 00 01 00 27 00 62 00 2a 00 b8 00
08: 52 00 01 00 62 00 2a 00 b8 00 00 00
09: 52 00 01 00 2a 00 b8 00 00 00 3f 00
10: 52 00 01 00 b8 00 00 00 3f 00 00 00
11: 52 00 01 00 00 00 3f 00 00 00 83 00
Une fois la configuration validée, nous pouvons émettre en envoyant deux commandes [1, p.42] (bit
de poids le plus fort à 1 pour indiquer que l’octet suivant de la transaction SPI est une commande) :
0x62 passe la transceiver en mode READY et 0x60 le passe en mode émission.
u 8 t cmd1write1 [ 2 ] = { 0 x80 , 0 x62 } ; //CMD=1,W#=0
u 8 t cmd1write2 [ 2 ] = { 0 x80 , 0 x60 } ; //CMD=1,W#=0
qui vaut, avec fXO = 50 MHz de la carte d’évaluation de ST, 834,62 MHz. À l’écart de l’oscillateur local
du récepteur de DVB-T, l’observation semble cohérente avec les attentes.
10
La programmation des registres de confi-
guration de la PLL se traduit bien par un
changement de la fréquence porteuse : dans
cet exemple, nous coupons l’alimentation du
S2-LP pour reconfigurer la fréquence (re-
trait du jumper JP1) – il est probable que
quitter le mode READY avant la program-
mation de la fréquence permettrait d’éviter
de couper l’alimentation. Faire varier de
0x6000 le mot de configuration se traduit
u 8 t b2wr1 [ 4 ] = { 0 x00 , 0 x07 , 0 x87 , 0 x62 } ; // W#=0
c o n s t s t r u c t s p i b u f t x b u f 1 ={. b u f=b2wr1 , . l e n =4};
par une variation de fréquence de 586 kHz,
c o n s t s t r u c t s p i b u f s e t s p i t x 1= en accord avec les observations à l’analyseur
{ . b u f f e r s = &t x b u f 1 , . count = 1 } ; de spectre du récepteur DVB-T (fréquence
s p i t r a n s c e i v e ( s p i , &s p i c o n f , &s p i t x 1 , NULL) ; d’échantillonnage : 1,5 MHz).
Références
[1] S2LP datasheet – Ultra-low power, high performance, sub-1 GHz transceiver (DS11896 - Rev 6 - June
2019)
11