Integracja Eclipse CDT z CodeSourcery dla ARM Cortex-M3

02-21-2010 przez kwesoly Zostaw odpowiedź »

Dzisiaj gościnny wpis mojego dobrego kolegi – Krzyśka. Dzięki wielkie za chęci i poświęcony czas. Jestem przekonany, że artykuł ten zaoszczędzi wielu nieprzespanych nocy wszystkim amatorom  Cortex’ów.

Wprowadzenie

Celem dzisiejszego wpisu jest prześledzenie i opisanie kroków potrzebnych do konfiguracji Środowiska Eclipse do współpracy z pakietem CodeSourcery Lite. Efektem tego połączenia jest w pełni darmowe (open-source) środowisko programistyczne.

Instalacja Code Sourcery Lite

Na stronie http://www.codesourcery.com/ znajdujemy wersję Lite pakietu.  Ponieważ nawigacja w poszukiwaniu pakietu w wersji darmowej jest jak zwykle „super łatwa” podaję bardziej bezpośredni link do pobierania: http://www.codesourcery.com/sgpp/lite/arm/portal/subscription?@template=lite

Po pobraniu i uruchomieniu aplikacji (w moim przypadku arm-2009q3-68-arm-none-eabi.exe) . W przypadku pakietu Lite wybór wersji (Typical/Custom etc.) jest bez znaczenia. Warto przy wybieraniu ścieżki unikać spacji – proponowane Program Files sprawia problemy w najmniej przewidywalnym momencie. Instalator proponuje nam również dodanie swojego katalogu binarek do zmiennej PATH – warto mu na to pozwolić, gdyż i tak konieczna będzie jego obecność w tej zmiennej. Alternatywa jest ręczna modyfikacja PATH za pomocą ustawień komputera, lub stworzenie pliku bat który modyfikuje PATH i uruchamia nasze środowisko. Biorąc pod uwagę iż pakiet CodeSourcery składa się z plików nie wprowadzających konfliktów nazw (np. cs-make, arm-none-eabi-gcc) zostawienie tego zadania instalatorowi to najlepsze wyjście. Program tworzy niezliczoną ilość ikon, więc najlepiej skierować te zapędy w stronę menu start :)

Instalacja Eclipse

Kolejny krok to pobranie Eclipse IDE ze zintegrowanymi narzędziami do programowania w C/C++. Dokładniejszy opis instalacji tego programu (m.in. instalacja wymaganej Javy, dotyczący użycia MinGW, a nie CodeSourcery) w środowisku Windows można znaleźć np. w tym wpisie: Eclipse CDT – środowisko C/C++ (nie należy się nim w tym przypadku dokładnie kierować, aczkolwiek pozwala poznać podstawowe informacje na temat konfiguracji wspomnianego IDE). W tym przypadku interesuje nas tylko środowisko, więc po prostu pobieramy i rozpakowujemy w wybrane miejsce. Po rozpakowaniu eclipse znalazł się w C:\eclipse, a skrót do eclipse.exe utworzyłem dla wygody na Pulpicie. Po uruchomieniu zostaniemy poproszeni o wybór Workspace – tradycyjnie przypominam o unikaniu spacji.

Wtyczka zarządzająca projektami

Za pomocą wymienionych wyżej narzędzi można już tworzyć projekty – jednak ręczna edycja plików makefile nie jest najwygodniejszym rozwiązaniem. Dlatego kolejnym etapem jest instalacja wtyczki która będzie je automatycznie tworzyć i zarządzać projektem.

Z pośród niewielu istniejących rozwiązań wybrałem GNU ARM Eclipse plugin. Aby go zainstalować wybieramy Help->Install New Software. Update site tego plugina to: http://gnuarmeclipse.sourceforge.net/updates, taki adres wklejamy w „Work with”. Należy zwrócić uwagę na odznaczenie „Group items by category”, ponieważ nasz plugin nie ma przypisanej kategorii. Zaznaczamy plugin  kontynuujemy instalacje. Oczywiście godzimy się na niepodpisane oprogramowanie i restartujemy eclipse zgodnie z sugestią.

Tworzenie pierwszego projektu

Projekty dla platformy ARM są typowymi projektami C/C++. Wybieramy więc File->New->C++ Project. Po wpisaniu dowolnej nazwy wybieramy typ projektu – ARM Cross Target Application->Empty Project. W polu Toolchains wybieramy nasze Sourcery G++ Lite. Kolejnym etapem jest wybranie dwóch możliwych wersji w których nasz program będzie kompilowany – debug, przystosowanej do pracy z JTAG i debugowania na platformie docelowej, i release, działającej z pełną wydajnością ale pozbawionej powyższych możliwości.

Kolejnym etapem jest zebra

nie podstawowych elementów potrzebnych do kompilacji i linkowania. W zależności od użytego mikrokontrolera mogą występować różnice w poniższych plikach. Te zostały przygotowane dla uC STM32F103RB.

  • skryptu linkera (pliku o rozszerzeniu *.ld, zawierającym informacje jak „poskładać” kolejne pliki *.o z kompilatora w nasz plik wynikowy – czyli elf /hex)
    plik ten zawiera informacje o rozmieszczeniu danych w pamięci, oraz przede wszystkim informacje o samej pamięci – początek, koniec pamięci RAM, ROM etc.
    Obszerną dokumentacje możemy znaleźć w plikach zainstalowanych z CodeSourcery (./share/doc/arm-arm-none-eabi/pdf/ld.pdf)
  • pliku startup (czyli pliku który po skompilowaniu będzie uruchamiany po zresetowaniu procesora. Jego zawartość to Reset_Handler, zajmujący się inicjalizacją zmiennych, kopiowaniem danych FLASH->RAM dla zmiennych zainicjalizowanych, oraz uruchomieniem konstruktorów obiektów globalnych (tylko C++), funkcji main, a na koniec destruktorów obiektów globalnych(tylko C++)).
    Z uwagi na złożoność asemblera procesorów Cortex-M3 warto skorzystać z gotowego pliku – np. zamieszczonego tutaj, stworzonego przez Freddiego Chopina.
  • Informacje o położeniu głównego stosu i o wektorach przerwań
    Mikrokontroler  Cortex-M3 zaraz po uruchomieniu ładuje do rejestru MSP (Main Stack Pointer) wartość spod adresu 0×00000000.  Kolejna niezbędna informacja to adres funkcji inicjalizującej – Reset_Handler pochodzącej z naszego startup’u. Adres ten musi znaleźć się pod adresem 0×00000004. Pozostałe adresy w tym wektorze to procedury obsługi przerwań. W naszym przypadku wykorzystaliśmy plik vectors.c, również stworzony przez Freddiego. Poprawiono tylko nazwy metod – teraz są w pełni zgodne (-; z standardem CMSIS.

Przydatne są rownież biblioteki – przede wszystkim CMSIS zawierający define’y rejestrów naszego mikrokontrolera, oraz biblioteka peryferiów STM32F10x_StdPeriph_Lib

Wszystkie powyższe pliki można pobrać klikając tutaj – Podstawowe pliki projektu ARM Cortex-M3 STM32

W tym momencie zakładam, że w Eclipse wyświetla nam się projekt C++, pliki po pobraniu zostały rozpakowane i przeciągnięte do naszego projektu. W tej chwili okno mojego projektu wygląda tak jak na obrazkach po lewej. Oczywiście samo dodanie plików do projektu to zbyt mało aby móc zacząć pracować nad samym programem. W celu czysto doświadczalnym w tej chwili stwórzmy plik main.cpp (File->New->Source File, zwróćmy uwagę aby umieścić ten plik w głównym katalogu projektu). Jedynym plikiem związanym z naszymi bibliotekami jaki będziemy include’ować jest plik stm32f10x_conf.h, znajdujący się w głównym katalogu projektu. Za jego pośrednictwem uzyskamy dostęp do całej reszty biblioteki pobranej ze strony ST. Podsumowując, stworzony plik main cpp wygląda teraz tak:

/*
 * Podstawowy plik wykorzystujący biblioteki dla STM32
 */
#include
#include 

int main() {

	return 0;
}

Jego kompilacja generuje błędy, związane z includowaniem plików nie podając ich pełnych ścieżek. Na szczęście nazwy plików są na tyle jednoznaczne i unikalne ze można je bez obaw dodać do domyślnie w danym projekcie przeszukiwanych ścieżek (odpowiednik przełącznika -I przy kompilacji). Ponieważ przyszłe projekty chcemy stworzyć poprzez proste skopiowanie bieżącego „szablonu”, warto podać ścieżki w takiej formie aby nie nastręczało to trudności. W tym celu często będziemy korzystać z ręcznie wpisanych ścieżek, gdyż te uzyskane poprzez wybranie odpowiednich katalogów zawierają nazwę projektu.

Aby edytować wspomniane ścieżki oraz zmieniać ustawienia kompilatora/linkera należy kliknąć w Project->Properties, następnie wybrać C/C++ Build -> Settings. Na wstępie z bieżącej konfiguracji Debug warto przełączyć się w [ All configurations ], pozwoli to nie dublować opisanej niżej pracy.

  • Ustawienia preprocesora C. W zakładce ARM Sourcery Windows GCC C Compiler->Preprocessor dodajemy symbole (plus przy opcjach -D): USE_STDPERIPH_DRIVER (jeśli chcemy używać bibliotek stm32) oraz STM32F10X_MD (obowiązkowo, definiujemy rodzaj mikrokontrolera – Medium Density Line w tym wypadku). Ustawienia które tu podajemy umożliwiaja nie edytowanie bibliotecznego pliku stm32f10x.h.
  • Ustawienia kompilatora C. W zakładce ARM Sourcery Windows GCC C Compiler->Directories dodajemy (każdą osobno) następujace ścieżki:
    „${CWD}/../”, „${CWD}/../Libraries/CMSIS/Core/CM3″ oraz „${CWD}/../Libraries/STM32F10x_StdPeriph_Driver/inc”. Zmienna CWD czyli Current Working Directory to przy kompilacji zawsze katalog Debug/Release projektu, więc taka konstrukcja pozwala zawsze skorzystać z właściwego katalogu.
    Z kolei w zakładce ARM Sourcery Windows GCC C Compiler->Optimization zaznaczamy Function sections (-ffunction-sections) i Data Sections  (-fdata-sections). Moja wersja wtyczki posiada błąd – zamiast Data Sections powtórzono Function Sections.
  • Powyższe kroki aplikujemy również dla kompilatora C++ (analogiczne zakładki w kategorii ARM Sourcery Windows GCC C++ Compiler)
  • Skrypt linkera. Plik ten (stm32f103rb_rom.ld) znajduje się w katalogu Setup. Aby był używany  Po przełączeniu wybieramy ARM Sourcery Windows GCC C++ Linker -> General i w pole „Script file -T” wpisujemy wpisujemy „..\Setup\stm32f103rb_rom.ld”. Dodatkowo zaznaczamy „Remove unused sections (-XLinker –gc-sections)” (pozwoli to usunąć zbędne sekcje które powstają z każdej kompilowanej a nie używanej funkcji).

Po zastosowaniu powyższych ustawień będzie można budować obie wersje projektu. Tworzenie przy kompilacji sekcji dla każdej funkcji, i usuwanie zbędnych przy linkowaniu gwarantuje nam rozsądną wielkość pliku wynikowego, także w trybie Debug – dzięki temu bez problemu przeprowadzimy testy za pomocą JTAGa na docelowym układzie.

Po zastosowaniu powyższych ustawień budowanie projektu (Ctrl+B) powinno przebiec bez zakłóceń.

Pliki projektu wraz z ustawieniami, do użycia np. na innym komputerze można wyeksportować. Wybieramy File->Export.  Następnie zaznaczamy General->Archive File i przechodzimy dalej. Zgodnie z własnym uznaniem wybieramy nazwę i rodzaj tworzonego archiwum, po czym kończymy eksport.

Podsumowanie

Stworzyliśmy szablon projektu, integrując pliki dostarczone przez STMicroelectronic, z plikami z strony www.freddiechopin.info. Takie połączenie to solidna podstawa do budowania dowolnej wielkości aplikacji an platformę STM32. Gotowy szablon można pobrać stąd: Szablon projektu dla Cortex-M3 STM32 F103RB

„${CWD}/../
Reklama

8 komentarzy

  1. Rychu pisze:

    Czy tak skonfigurowane środowisko posiada automatyczne uzupełnianie kodo tj. coś w stylu Intellisense ?

  2. admin pisze:

    Tak, eclipse posiada Content Assist. Sam przekopuje wszystkie katalogi z include’ami, oraz pliki projektu i tworzy sobie własny indeks wszystkich funkcji, stałych, zmiennych, klas, namespace’ów itd. i potem automatycznie podpowiada (inteligentnie, czyli w zależności od położenia kursora w kodzie podpowiada tylko nazwy elementów które mogą być użyte w danym miejscu, ze względu na zakres ich ważności) w czasie pisania kodu. Jego ustawienia można znaleźć w „Window->Preferences…->C/C++->Editor->Content Assist”. Można tam ustawić np. po ilu milisekundach od wstawienia operatora „::”, „.”, „->” ma wyświetlać listę podpowiedzi. Listę podpowiedzi można zawsze wywołać samemu skrótem „Ctrl+Space”. Dodatkowo warto przejrzeć opcje Indexer’a w „Window->Preferences…->C/C++->Indexer”.

  3. Rychu pisze:

    Dziękuje za odpowiedź.

  4. FAzi pisze:

    Witam wszystko fajnie opisane tylko pytanie z mojej strony. Gdzie wpisać -lm żeby działały funkcje takie jak sqrt pow itd. no i czy ma ktoś jakiś taki zgrabny plik syscalls żeby można było normalnie korzystać z sprintf’a i jemu podobnych.

  5. Proponuję aktualizację plików z moich przykładów na „nowszą” wersję (wraz z update’em powyższego opisu) [;

  6. admin pisze:

    Dzięki wielkie za cynk Freddie :) Zaraz się wezmę za te Twoje nowe plikczki i zobacze co tam nowego w nich piszczy :)

  7. wilku pisze:

    A ja mam drobny problem. Przerobiłem krok po kroku opis i tak:
    1. Przy budowaniu projektu wywalało mi masę błędów w startup-ie dla IAR. Wywaliłem folder bo i tak nie będzie używany.
    2. Pojawiły się błędy w pliku startup_stm32f10x_ld: w g_pfnVectors: nie trawił wpisów ’0′, poprawiłem na .word 0 jak w pozostałych.
    3. Wywaliłem pliki startup dla ARM.
    4. W plikach startup dla GCC wywala mi błąd w kodzie:
    Default_Handler:
    Infinite_Loop:
    b Infinite_Loop
    .size Default_Handler, .-Default_Handler

    bład: multiple definition of `Default_Handler’ dokładniena „b Infinite_Loop” i z tym już nie wiem co zrobić :)

Dodaj komentarz