Inhaltsverzeichnisarm-none-eabi-gcc toolchainEs ist wie immer im Leben - alles eigentlich ganz einfach, wenn man weiß, wie es geht. In diesem Fall hat es mich allerdings vier Tage gekostet, eben dies heraus zu finden. Abstrcact:Es geht darum, die Software-Beispiele, die ST für das STM32F429I-DISCO anbietet mit der ARM-GCC-Toolchain (arm-none-eabi) zu kompilieren. Vorgesehen ist eigentlich, dass man dafür irgendwelche kommerziellen Toolchains/IDEs verwendet und das ist auch einigermaßen dokumentiert. Für andere Boards, gibt es fertige Beispiele mit passenden Makefiles für den GCC, aber für das STM32F429I-DISCO konnte ich nirgendwo etwas passendes finden. Die LösungMan braucht kein Make-File (auch wenn das vielleicht vieles einfacher und schneller macht). Man kann folgenden einfachen Befehl nutzen, um mit GCC die Beispiel-Projekte zu kompilieren: arm-none-eabi-gcc -Wall -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard -nostdlib \ -I../../../Libraries/CMSIS/Device/ST/STM32F4xx/Include -I../../../Libraries/CMSIS/Include \ -I../../../Utilities/STM32F429I-Discovery -I../../../Libraries/STM32F4xx_StdPeriph_Driver/inc \ -I./ -T TrueSTUDIO/LTDC_Display_2Layers/STM32F429ZI_FLASH.ld -o display.elf \ -DUSE_STDPERIPH_DRIVER \ ../../../Libraries/CMSIS/Device/ST/STM32F4xx/Source/Templates/gcc_ride7/startup_stm32f429_439xx.s *.c \ ../../../Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_gpio.c \ ../../../Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_rcc.c \ ../../../Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_ltdc.c \ ../../../Utilities/STM32F429I-Discovery/stm32f429i_discovery_lcd.c \ ../../../Utilities/STM32F429I-Discovery/stm32f429i_discovery_sdram.c \ ../../../Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_spi.c \ ../../../Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_dma2d.c \ ../../../Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_fmc.c \ ../../../Utilities/STM32F429I-Discovery/stm32f429i_discovery_ioe.c \ ../../../Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_i2c.c \ ../../../Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_dma.c Ja, das ist ein Befehl… - wie man sieht ist dieser Befehl für das Beispiel LTDC_Display_2Layers und wegen eines Fehlers in dem Beispiel von ST (aktuelle Version STM32F429I-Discovery_FW_V1.0.1) compiliert es nicht, aber dazu später mehr. Der Eintrag -T TrueSTUDIO/LTDC_Display_2Layers/STM32F429ZI_FLASH.ld muss für die anderen Beispiele entsprechend angepasst werden und unter Umständen braucht man da auch noch andere Bibliotheken. Das so entstandene .elf-binary muss noch ein bisschen massiert werden: arm-none-eabi-objcopy -O binary display.elf display.bin
Und schon fällt ein binary heraus, das wir direkt an die passende Stelle in den Flash schreiben können: st-flash write display.bin 0x8000000
LTDC_Display_2LayersDieses Beispiel zeigt zwei Bilder, die etwas unbeholfen über den TFT holpern - oder würde das zeigen, wenn ST da ordentlichen Code geschrieben hätte. @ST: Es gibt Betriebssysteme mit Case-Sensitiven Dateisystemen. Man muss also eine kleine Änderung in der main.h vornehmen: #include "ST_logo1.h" #include "ST_logo2.h" wird zu #include "st_logo1.h" #include "st_logo2.h" Und schon klappt es wie oben beschrieben. Eigene Bilder darstellenDie beiden ST-Logos sind … auch schön. Ein Blick in st_logo1.h zeigt, dass da offenbar die Daten des Bildes einfach als 19200 32-Bit-HEX-Werte des Bitmap übergeben werden. Aus der main.c kann man dann noch entnehmen, dass es sich offenbar um RGB565 handelt. Es werden also für jedes Pixel zwei Byte übergeben mit dem Aufbau rrrrrggg gggbbbbb. Also jeweils 5 Bit Rot, 6 Bit Grün und 5 Bit Blauwert. Das Display hat eine Auflösung von 320×240 Pixel, die beiden Bilder haben jeweils halbe Display-Höhe, also eine Größe von 240×160 Pixel und wie es der Zufall will kommt das auch recht gut hin: 240 * 160 * 2 Byte = 19200 * 32 Bit. Also braucht man jetzt nur noch ein Bild der passenden Größe und muss die Pixel noch passend rechnen: import sys from PIL import Image im = Image.open(sys.argv[1]) im_list = [] n = 0 for i in range(im.size[1]): for j in range(im.size[0]): r, g, b, a = im.getpixel((j,i)) val = int(r * ((1 << 5) - 1) / 255) << 11 val += int(g * ((1 << 6) - 1) / 255) << 5 val += int(b * ((1 << 5) - 1) / 255) if n % 2 == 0: im_list.append(val) else: im_list[-1] += val << 16 n += 1 print (",\n".join(map(lambda x: "0x%08X" % (x,), im_list))) Die Ausgabe garniert man noch mit den passenden Kopf- und Fußzeilen aus den bestehenden st_logo1.h bzw. st_logo2.h und schon hat man da was eigenes - Holleri du dödl di, diri diri dudl dö! Linux auf dem STM32F429IUnter https://github.com/jserv/stm32f429-linux-builder gibt es eine sehr einfache Anleitung, wie man Linux auf dem STM32F429I-DISCO zum laufen bringt. Unter Debian Squeeze lässt sich die aktuelle Version von OpenOCD nicht ohne weiteres installieren, da libusb zu alt ist, aber für Arch Linux funktioniert die Anleitung problemlos. Das Makefile lädt Sourcen für U-Boot, uCLinux und eine Busybox-Umgebung nach. Das fertige System bootet innerhalb von etwa 2 Sekunden in eine Shell auf der Seriellen Schnittstelle auf PC10 (TXD) und PC11 (RXD). Umgebungsvariablen für die Toolchain setzenUm gezielt Änderungen an U-Boot, Kernel oder Busybox vornehmen zu können oder eigene kompilieren zu können müssen ein paar Umgebungsvariablen gesetzt werden. Dazu sollte man sich ein kleines Skript als vars.sh erstellen (Pfade müssen natürlich angepasst werden):
KernelMan kann die Kernel-Config recht einfach für die eigenen Belange anpassen, sollte sich allerdings vor Augen halten, dass von den 8MB RAM mit Minimalsystem schon nur noch 4MB verfügbar sind. . vars.sh cd $INSTALL_PATH/uclinux make -C $INSTALL_PATH/uclinux O=$INSTALL_PATH/out/kernel menuconfig Hier tue man, was getan werden muss … und hernach: make -C $INSTALL_PATH/uclinux O=$INSTALL_PATH/out/kernel xipImage modules cat $INSTALL_PATH/uclinux/arch/arm/boot/tempfile \ $INSTALL_PATH/out/kernel/arch/arm/boot/xipImage > $INSTALL_PATH/out/kernel/arch/arm/boot/xipImage.bin $INSTALL_PATH/out/uboot/tools/mkimage -x -A arm -O linux -T kernel -C none -a 0x08020040 -e 0x08020041 \ -n "Linux-2.6.33-arm1" -d $INSTALL_PATH/out/kernel/arch/arm/boot/xipImage.bin \ $INSTALL_PATH/out/kernel/arch/arm/boot/xipuImage.bin cd $INSTALL_PATH Jetzt kann man den neuen Kernel auf das Board übertragen. Eigene ModuleWie man Module für den Linux Kernel schreibt erfährt man im schönen Buch Linux Device Drivers. Folgendes Beispiel basiert auf einem Beispiel aus Kapitel 2 der dritten Ausgabe:
Beide Dateien legt man passender Weise in ein Verzeichnis mit dem Namen stm32f4_blink und wechselt in dieses Verzwichnis. Kompilieren kann man das ganze dann mit folgenden Befehlen: . ${HOME}/stm32f4/stm32f429-linux-builder/vars.sh make -C $INSTALL_PATH/uclinux O=$INSTALL_PATH/out/kernel M=`pwd` modules Die entstehende .ko-Datei kann man zum Test einfach per rx auf das Board übertragen und dann mit insmod laden: Welcome to ____ _ _ / __| ||_| _ _| | | | _ ____ _ _ _ _ | | | | | | || | _ \| | | |\ \/ / | |_| | |__| || | | | | |_| |/ \ | ___\____|_||_|_| |_|\____|\_/\_/ | | |_| For further information check: http://www.uclinux.org/ Jan 1 00:00:01 login[27]: root login on 'ttyS2' ~ # cd /var/ /var # rx stm32f4_blink.ko C /var # insmod stm32f4_blink.ko Starting blink module /var # lsmod Module Size Used by Not tainted stm32f4_blink 524 0 ext2 33828 1 mbcache 2320 1 ext2 /var # rmmod stm32f4_blink No more blinking busyboxDas Vorgehen für die Busybox ist im wesentlichen das gleiche wie beim Kernel. Es lohnt z.B. das programm rx (Miscellaneous Utilities) mit in die Busybox hinein zu nehmen, um im laufenden System per X-Modem-Protokoll Dateien in die Ramdisk übertragen zu können. . vars.sh make -C $INSTALL_PATH/busybox-1.22.1 O=$INSTALL_PATH/out/busybox menuconfig make -C $INSTALL_PATH/out/busybox CFLAGS="-march=armv7-m -mtune=cortex-m4 -mlittle-endian -mthumb \ -Os -ffast-math -ffunction-sections -fdata-sections -Wl,--gc-sections -fno-common \ --param max-inline-insns-single=1000 -Wl,-elf2flt=-s -Wl,-elf2flt=16384" SKIP_STRIP=y \ CONFIG_PREFIX=$INSTALL_PATH/out/romfs install Bootloader, Kernel und ROMFS installierenEs ist sicherlich auch möglich, einzelne Teile zu installieren, ich mach das aber bisher immer komplett, wie es auch make install aus stm32f429-linux-builder tut: . vars.sh cp -af $INSTALL_PATH/rootfs/* $INSTALL_PATH/out/romfs cp -f $INSTALL_PATH/out/kernel/fs/ext2/ext2.ko $INSTALL_PATH/out/romfs/lib/modules cp -f $INSTALL_PATH/out/kernel/fs/mbcache.ko $INSTALL_PATH/out/romfs/lib/modules cd $INSTALL_PATH/out && genromfs -v -V "ROM Disk" -f romfs.bin -x placeholder -d $INSTALL_PATH/out/romfs 2> $INSTALL_PATH/out/romfs.map cd $INSTALL_PATH/ Jetzt auf dem Board den RESET Knopf drücken und loslassen, sobald make install läuft make install |