28 czerwca 2018

Pierwszy projekt - opcja minimum

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:

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
Pierwszy zawiera definicje rejestrów mikrokontrolera - jest bardzo ważny i wart dodania do projektu. Pozostałe to praktycznie śmieci, o przepraszam biblioteka CMSIS... Są włączane przez pierwszy, więc na razie warto je dodać - w wolnej chwili może uda się ich pozbyć.
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;
}


Brak komentarzy:

Prześlij komentarz