Jak poprzednio napisałem Atollic TrueSTUDIO jakoś nie wzbudziło mojego szaleńczego entuzjazmu. Nie pozostaje więc nic innego niż zakasać rękawy i przygotować projekt bez tego narzędzia. W sumie to zestaw nakładek, na eclipse, gcc, gdb, openocd, więc nie powinno być problemu z poradzeniem sobie bez niego.
Na początek kompilator. Pod linuxem jest łatwo - arm-none-eabi-gcc jest dostępny w paczce. Więc wystarczy odpalić:
apt install gcc-arm-none-eabi
I gotowe, kompilator już jest. Pod windowsem można pobrać gcc dla arm-a i zainstalować bez problemu, ale nie mam teraz tego systemu pod ręką, zostanę więc przy linuksie.
Teraz pojawia się problem - jakie opcje do kompilacji są potrzebne. gcc posiada niesamowitą liczbę opcji, na początek to nie ułatwia. Ale skoro TrueStudio sobie radzi, a używa narzędzi open-source to może warto "podpatrzeć" co ono robi. Zaglądam do loga kompilacji przykładowego kodu:
arm-atollic-eabi-gcc -c ../Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_usart.c -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -std=gnu11 -DSTM32F42_43xxx -DUSE_STDPERIPH_DRIVER -DHSE_VALUE=8000000 -DUSE_STM32F429I_DISCO -I../src -I../Libraries/CMSIS/Include -I../Libraries/Device/ST/STM32F4xx/Include -I../Libraries/STM32F4xx_StdPeriph_Driver/inc -I../Utilities/Common -I../Utilities/STM32F429I-Discovery -O0 -ffunction-sections -fdata-sections -g -fstack-usage -Wall -specs=nano.specs -o Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_usart.o
W pierwszej chwili wygląda, że tego sporo, ale wszystkie -I -D oraz ścieżki do plików można pominąć - wtedy zostaje:
arm-atollic-eabi-gcc -c stm32f4xx_usart.c -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -std=gnu11 -O0 -ffunction-sections -fdata-sections -g -fstack-usage -Wall -specs=nano.specs -o stm32f4xx_usart.o
Nie ma co się bać nazwy z "attolic" to i tak zwykły gcc. Zostają więc opcje:
-mthumb
-mcpu=cortex-m4
-mfloat-abi=hard
-mfpu=fpv4-sp-d16
-std=gnu11
-O0
-ffunction-sections
-fdata-sections
-g
-fstack-usage
-Wall
-specs=nano.specs
Warto byłoby dokładnie wszystkie sprawdzić, ale na razie zostawię ten problem "na później".
Jest jeszcze jeden ważny element - linkowanie aplikacji. Znowu zaglądam do logów TrueStudio - tym razem pominę pełną wersję, była bardzo długa, ale po usunięciu plików .o wygląda tak:
arm-atollic-eabi-gcc -o test01.elf -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -T../stm32f4_flash.ld -specs=nosys.specs -static -Wl,-cref,-u,Reset_Handler -Wl,-Map=test01.map -Wl,--gc-sections -Wl,--defsym=malloc_getpagesize_P=0x80 -Wl,--start-group -lc -lm -Wl,--end-group -specs=nano.specs
Czyli użyte są następujące opcje:
-mthumb
-mcpu=cortex-m4
-mfloat-abi=hard
-mfpu=fpv4-sp-d16
-T../stm32f4_flash.ld
-specs=nosys.specs
-static
-Wl,-cref,-u,Reset_Handler
-Wl,-Map=test01.map
-Wl,--gc-sections
-Wl,--defsym=malloc_getpagesize_P=0x80
-Wl,--start-group
-lc
-lm
-Wl,--end-group
-specs=nano.specs
Warto zwrócić uwagę na opcję -T która wskazuje na skrypt linkera stm32f4_flash.ld - będzie nam potrzebny.
Poza tym -specs występuje dwa razu, jak widać autorzy TrueSTUDIO sami się gubią w swoim przerośniętym narzędziu.
Wiadomo już jak TrueSTUDIO kompiluje projekty. Można, a nawet warto najpierw przetestować działanie arm-none-eabi-gcc z linii poleceń. Jednak po chwili staje się to nudne i niewygodne.
Na szczęście dostępne są różne narzędzia wspomagające kompilację kodu. Ja wybrałem starego (nawet bardzo starego), ale dobrego make-a.
Pierwsza wersja mojego Makefile-a wygląda następująco:
Do programowania płytki stm32f429-discovery używam openocd co widać w załączonym pliku. Pod Debianem, na którym pracuję wystarczyło zainstalować gotowy pakiet. OpenOCD jest oczywiście dostępny w innych dystrybucjach oraz systemach, więc pod Windą, czy Mac OS nie powinno być z nim problemów.
Teraz pozostaje zebrać pliki źródłowe. Potrzebujemy:
Pierwsze dwa pliki możemy "podebrać" z TrueSTUDIO, albo lepiej pobrać bibliotekę Cube HAL dla stm32f4: https://www.st.com/en/embedded-software/stm32cubef4.html
Pobierając bibliotekę szybko odkryjemy, że straciliśmy kolejne 2GB przestrzeni dyskowej... Zaczynam mocno podejrzewać, że ST podukuje jakieś układy do dysków twardych i bardzo dba o generowanie zapotrzebowania na nie.
W każdym razie pliki należy skopiować i nieco zmienić pierwszy, czyli startup_stm32f429xx.s. Znajdziemy w nim wywołanie funkcji SystemInit (przed main). Nie mamy tej funkcji zdefiniowanej, więc najlepiej na razie zakomentować linijkę która ją wywołuje.
Przydadzą się również pliki nagłówkowe:
Plik stm32f429xx.h poza włączaniem wspomnianych śmieci stara się również dodać plik system_stm32f4xx.h. Tego pliku nie potrzebujemy, najlepiej więc usunąc linię która się do niego odwołuje.
Na koniec pozostaje napisać pierwszy program i zapisać go jako main.c:
Na początek kompilator. Pod linuxem jest łatwo - arm-none-eabi-gcc jest dostępny w paczce. Więc wystarczy odpalić:
apt install gcc-arm-none-eabi
I gotowe, kompilator już jest. Pod windowsem można pobrać gcc dla arm-a i zainstalować bez problemu, ale nie mam teraz tego systemu pod ręką, zostanę więc przy linuksie.
Teraz pojawia się problem - jakie opcje do kompilacji są potrzebne. gcc posiada niesamowitą liczbę opcji, na początek to nie ułatwia. Ale skoro TrueStudio sobie radzi, a używa narzędzi open-source to może warto "podpatrzeć" co ono robi. Zaglądam do loga kompilacji przykładowego kodu:
arm-atollic-eabi-gcc -c ../Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_usart.c -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -std=gnu11 -DSTM32F42_43xxx -DUSE_STDPERIPH_DRIVER -DHSE_VALUE=8000000 -DUSE_STM32F429I_DISCO -I../src -I../Libraries/CMSIS/Include -I../Libraries/Device/ST/STM32F4xx/Include -I../Libraries/STM32F4xx_StdPeriph_Driver/inc -I../Utilities/Common -I../Utilities/STM32F429I-Discovery -O0 -ffunction-sections -fdata-sections -g -fstack-usage -Wall -specs=nano.specs -o Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_usart.o
W pierwszej chwili wygląda, że tego sporo, ale wszystkie -I -D oraz ścieżki do plików można pominąć - wtedy zostaje:
arm-atollic-eabi-gcc -c stm32f4xx_usart.c -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -std=gnu11 -O0 -ffunction-sections -fdata-sections -g -fstack-usage -Wall -specs=nano.specs -o stm32f4xx_usart.o
Nie ma co się bać nazwy z "attolic" to i tak zwykły gcc. Zostają więc opcje:
-mthumb
-mcpu=cortex-m4
-mfloat-abi=hard
-mfpu=fpv4-sp-d16
-std=gnu11
-O0
-ffunction-sections
-fdata-sections
-g
-fstack-usage
-Wall
-specs=nano.specs
Warto byłoby dokładnie wszystkie sprawdzić, ale na razie zostawię ten problem "na później".
Jest jeszcze jeden ważny element - linkowanie aplikacji. Znowu zaglądam do logów TrueStudio - tym razem pominę pełną wersję, była bardzo długa, ale po usunięciu plików .o wygląda tak:
arm-atollic-eabi-gcc -o test01.elf -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -T../stm32f4_flash.ld -specs=nosys.specs -static -Wl,-cref,-u,Reset_Handler -Wl,-Map=test01.map -Wl,--gc-sections -Wl,--defsym=malloc_getpagesize_P=0x80 -Wl,--start-group -lc -lm -Wl,--end-group -specs=nano.specs
Czyli użyte są następujące opcje:
-mthumb
-mcpu=cortex-m4
-mfloat-abi=hard
-mfpu=fpv4-sp-d16
-T../stm32f4_flash.ld
-specs=nosys.specs
-static
-Wl,-cref,-u,Reset_Handler
-Wl,-Map=test01.map
-Wl,--gc-sections
-Wl,--defsym=malloc_getpagesize_P=0x80
-Wl,--start-group
-lc
-lm
-Wl,--end-group
-specs=nano.specs
Warto zwrócić uwagę na opcję -T która wskazuje na skrypt linkera stm32f4_flash.ld - będzie nam potrzebny.
Poza tym -specs występuje dwa razu, jak widać autorzy TrueSTUDIO sami się gubią w swoim przerośniętym narzędziu.
Wiadomo już jak TrueSTUDIO kompiluje projekty. Można, a nawet warto najpierw przetestować działanie arm-none-eabi-gcc z linii poleceń. Jednak po chwili staje się to nudne i niewygodne.
Na szczęście dostępne są różne narzędzia wspomagające kompilację kodu. Ja wybrałem starego (nawet bardzo starego), ale dobrego make-a.
Pierwsza wersja mojego Makefile-a wygląda następująco:
CROSS_COMPILE=arm-none-eabi- AS=$(CROSS_COMPILE)as CC=$(CROSS_COMPILE)gcc SIZE=$(CROSS_COMPILE)size CFLAGS=-mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -std=gnu11 -O0 \ -ffunction-sections -fdata-sections -g -fstack-usage -Wall -specs=nano.specs LDFLAGS=$(CFLAGS) -Wl,--gc-sections -specs=nosys.specs -Wl,-cref,-u,Reset_Handler \ -Wl,-Map=bin/test01.map -Tsrc/stm32f4_flash.ld all: bin/test01.elf $(SIZE) $< bin/test01.elf: obj/main.o obj/startup_stm32f429xx.o $(CC) $(LDFLAGS) -o $@ $^ obj/main.o: src/main.c $(CC) $(CFLAGS) -o $@ -c $< obj/startup_stm32f429xx.o: src/startup_stm32f429xx.s $(CC) $(CFLAGS) -o $@ -c $< debug: bin/test01.elf openocd -f board/stm32f429discovery.cfg -f interface/stlink-v2.cfg \ -c "init; sleep 200; reset halt; wait_halt; \ flash write_image erase bin/test01.elf; \ reset run; sleep 10; shutdown" clean: rm -f bin/* obj/*
Do programowania płytki stm32f429-discovery używam openocd co widać w załączonym pliku. Pod Debianem, na którym pracuję wystarczyło zainstalować gotowy pakiet. OpenOCD jest oczywiście dostępny w innych dystrybucjach oraz systemach, więc pod Windą, czy Mac OS nie powinno być z nim problemów.
Teraz pozostaje zebrać pliki źródłowe. Potrzebujemy:
- startup_stm32f429xx.s - zawiera kod uruchamiany po resecie mikrokontrolera
- stm32f4_flash.ld - skrypt linkera
- main.c - pierwsza aplikacja
Pierwsze dwa pliki możemy "podebrać" z TrueSTUDIO, albo lepiej pobrać bibliotekę Cube HAL dla stm32f4: https://www.st.com/en/embedded-software/stm32cubef4.html
Pobierając bibliotekę szybko odkryjemy, że straciliśmy kolejne 2GB przestrzeni dyskowej... Zaczynam mocno podejrzewać, że ST podukuje jakieś układy do dysków twardych i bardzo dba o generowanie zapotrzebowania na nie.
W każdym razie pliki należy skopiować i nieco zmienić pierwszy, czyli startup_stm32f429xx.s. Znajdziemy w nim wywołanie funkcji SystemInit (przed main). Nie mamy tej funkcji zdefiniowanej, więc najlepiej na razie zakomentować linijkę która ją wywołuje.
Przydadzą się również pliki nagłówkowe:
- stm32f429xx.h
- cmsis_gcc.h
- core_cmFunc.h
- core_cmSimd.h
- core_cm4.h
- core_cmInstr.h
Plik stm32f429xx.h poza włączaniem wspomnianych śmieci stara się również dodać plik system_stm32f4xx.h. Tego pliku nie potrzebujemy, najlepiej więc usunąc linię która się do niego odwołuje.
Na koniec pozostaje napisać pierwszy program i zapisać go jako main.c:
#include <stdint.h> #include "stm32f429xx.h" int main(int argc, char *argv[]) { volatile uint32_t dly; RCC->AHB1ENR |= RCC_AHB1ENR_GPIOGEN; GPIOG->MODER |= GPIO_MODER_MODE13_0|GPIO_MODER_MODE14_0; while (1) { GPIOG->BSRR = GPIO_BSRR_BS13; GPIOG->BSRR = GPIO_BSRR_BR14; for (dly = 0; dly < 500000; dly++) ; GPIOG->BSRR = GPIO_BSRR_BS14; GPIOG->BSRR = GPIO_BSRR_BR13; for (dly = 0; dly < 500000; dly++) ; } return 0; }