18.01.2014

.NET Micro Framework na STM32F429

Jestem w szoku. STMicroelectronics, na swojej stronie, udostępnił paczkę z .NET Micro Framework do płytki STM32F429 Discovery, o której wcześniej wspominałem (Discovery ma przyszłość).

W paczce STSW-STM32141 znajdują się pliki hex (tinybooter, CLR i config) do załadowania, sterownik USB (WinUSB) oraz przykłady w C#. Między innymi obsługa LCD, żyroskopu i ekranu dotykowego.Całość została przygotowana dla NETMF SDK 4.3.

13.01.2014

Parametry msbuild

Kto choć raz skompilował solucję Discovery4 (z minimalnymi parametrami np. msbuild /p:flavor=DEBUG;memory=flash Solutions\Discovery4\dotNetMF.proj) nie mógł się zapewne nadziwić, jak coś można z tych szlaczków, co przelatują na ekranie, wyczytać. Ekran przypomina coś takiego...

.NET MF Compilation
Aha! Nie do końca. Pięć ekranów wcześniej był żółty, a 2 ekrany wcześniej czerwony. Czy idzie to jakoś ogarnąć? Tak. Potrzebne są dodatkowe parametry. Po kolei.

Właściwości projektu to np. /p:flavor=debug;memory=flash. Zamiast debug możemy użyć następujących wartości: instrumented, release, rtm. Do końcowych wersji CLR powinniśmy użyć release lub rtm.

Elementy docelowe projektu to np: /t:build. Jest to domyślna wartość. Pozwala przyrostowo kompilować solucję. Gdy coś testujemy, dodając elementy do solucji, lub wyskoczy błąd kompilacji to ta opcja najszybciej skompiluje nam ponownie. Do czystej kompilacji powinniśmy użyć wartości /t:clean;build.

Plik projektu do kompilacji to np. Solutions\Discovery4\dotNetMF.proj. W tym przypadku zostanie skompilowany TinyBooter, a następnie TinyCLR. Nic nie stoi jednak na przeszkodzie, aby kompilować tylko pojedyncze projekty. Najczęściej kompiluje się TinyCLR. Czyli powinniśmy użyć takiego projektu Solutions\Discovery4\TinyCLR\TinyCLR.proj. Jak chcemy skompilować tylko TinyBooter to Solutions\Discovery4\TinyBooter\TinyBooter.proj.

Teraz opcje loggera. Parametry logowania konsoli określa się przełącznikiem /clp. Na przykład, aby nie pojawiały się na konsoli żadne informacje można użyć /clp:Verbosity=quiet. Przecież i tak nic z tego co w "czarnym okienku" się pojawia nie jesteśmy w stanie ogarnąć. Wartości jakie możemy użyć w verbosity to: quiet, minimal, normal, detailed i diagnostic. Możemy też skorzystać z dodatkowych opcji np. ErrorsOnly, WarningsOnly i Summary. Pierwsze dwa włączają pokazywanie tylko określonych komunikatów, a trzeci wskazuje czy na końcu ma pokazać podsumowanie. Summary działać będzie tylko wówczas, gdy Verbosity>=normal i nie będzie parametrów ErrorsOnly i WarningsOnly. Według mnie najlepszymi parametrami dla loggera konsoli to /clp:ErrorsOnly;Verbosity=quiet.

Jednak na wypadek błędu pasowałoby mieć jakieś informacje, co poszło nie tak. Możemy włączyć logowanie do pliku. Dzięki przełącznikowi /fl w katalogu, z którego odpalamy msbuild, powstanie plik msbuild.log. Dla tego loggera możemy wskazać takie same parametry, jak dla loggera konsolowego np.: /fl /flp:Summary;Verbosity=normal.

Dodatkowe parametry jakie możemy dodać do polecenia to /nologo - nie pokazuje informacji o wersji msbuild i /m - pozwala użyć do kompilacji wiele procesów. Na koniec otrzymamy więc takie polecenie:

msbuild /t:build /p:flavor=release;memory=flash Solutions\Discovery4\TinyCLR\TinyCLR.proj /clp:ErrorsOnly;Verbosity=quiet /fl /flp:Summary;Verbosity=normal /nologo /m

Najlepiej jednak zrobić sobie plik bat w katalogu PK na przykład z taką zawartością:

rem Discovery4 build script
call setenv_gcc 4.6.2 c:\gcc46
msbuild /t:build /p:flavor=release;memory=flash Solutions\Discovery4\TinyCLR\TinyCLR.proj /clp:ErrorsOnly;Verbosity=quiet /fl /flp:Summary;Verbosity=normal /nologo /m
pause

11.01.2014

Pliki *.targets

W podkatalogu tools\Targets MicroFramework PK znajdziemy specjalne pliki *.targets. Co to takiego?

Są to pliki z instrukcjami dla msbuild (zapisane w xmlu), w jaki sposób ma wywoływać zewnętrzne narzędzia kompilacji np. z MDK lub GCC. Czyli np. arm-none-eabi-gcc.exe z chyba 'miliardem' przełączników i opcji.

Popatrzmy na przykład do pliku Microsoft.Spot.system.mdk.targets. Jest tam pełno elementów xml z przeróżnymi atrybutami (np. Condition). Połapanie się w tym wszystkim nie jest proste. Najciekawsze jest jednak na początku pliku. Jest tam pełno takich linii:

<CC      Condition="'$(COMPILER_TOOL_VERSION)'=='MDK3.1'">"$(MDK_TOOL_PATH)\bin31\armcc.exe"</CC>
<CPP     Condition="'$(COMPILER_TOOL_VERSION)'=='MDK3.1'">"$(MDK_TOOL_PATH)\bin31\armcc.exe"</CPP>
<AS      Condition="'$(COMPILER_TOOL_VERSION)'=='MDK3.1'">"$(MDK_TOOL_PATH)\bin31\armasm.exe"</AS>
<LINK    Condition="'$(COMPILER_TOOL_VERSION)'=='MDK3.1'">"$(MDK_TOOL_PATH)\bin31\armlink.exe"</LINK>
<AR      Condition="'$(COMPILER_TOOL_VERSION)'=='MDK3.1'">"$(MDK_TOOL_PATH)\bin31\armar.exe"</AR>
<FROMELF Condition="'$(COMPILER_TOOL_VERSION)'=='MDK3.1'">"$(MDK_TOOL_PATH)\bin31\fromelf.exe"</FROMELF>

Są to wskazania, gdzie znajdują się poszczególne narzędzia w zależności od wersji MDK. Nazwa elementu to zmienna pod jaką będzie w dalszej części pliku występował dany program. Na przykład wszędzie, gdzie będzie potrzebne wywołanie kompilatora armcc.exe, zostanie wstawione $(CC). Jak łatwo się zorientować możemy użyć tylko niektórych wersji MDK. A są to: 3.1, 3.80a, 4.12, 4.13, 4.54. Dlatego tak ważne jest ustawienie odpowiedniej wersji przy wywołaniu setenv_mdk.cmd.

Ale czy można dodać obsługę nowszej wersji MDK? Na przykład 4.60? Jest jeden problem. W parametrach wywołania konsolidatora (linker), gdzieś około linii 222, jest na stałe wstawiona ścieżka do bibliotek: $(MDK_TOOL_PATH)\RV31\LIB. Wersja 4.60 biblioteki ma w zupełnie innym katalogu: $(MDK_TOOL_PATH)\armcc\lib. Łatwo znaleźć, bo jest to katalog z podkatalogami armlib i cpplib.

Trzeba jakoś to obejść. Najlepiej zdefiniować zmienną dla każdej wersji, która będzie przechowywać tą ścieżkę. Trzeba więc zamienić $(MDK_TOOL_PATH)\RV31\LIB na coś takiego: $(MDKLIB). Trzeba jeszcze do każdej wersji (na początku pliku) dodać taką definicję, umiejętnie zmieniając numerek wersji przy każdej nowej sekcji:

<MDKLIB  Condition="'$(COMPILER_TOOL_VERSION)'=='MDK3.1'">"$(MDK_TOOL_PATH)\rv31\lib"</MDKLIB>

Podobnie dokładamy elementy dla wersji 4.60:

<CC      Condition="'$(COMPILER_TOOL_VERSION)'=='MDK4.60'">"$(MDK_TOOL_PATH)\armcc\bin\armcc.exe"</CC>
<CPP     Condition="'$(COMPILER_TOOL_VERSION)'=='MDK4.60'">"$(MDK_TOOL_PATH)\armcc\bin\armcc.exe"</CPP>
<AS      Condition="'$(COMPILER_TOOL_VERSION)'=='MDK4.60'">"$(MDK_TOOL_PATH)\armcc\bin\armasm.exe"</AS>
<LINK    Condition="'$(COMPILER_TOOL_VERSION)'=='MDK4.60'">"$(MDK_TOOL_PATH)\armcc\bin\armlink.exe"</LINK>
<AR      Condition="'$(COMPILER_TOOL_VERSION)'=='MDK4.60'">"$(MDK_TOOL_PATH)\armcc\bin\armar.exe"</AR>
<FROMELF Condition="'$(COMPILER_TOOL_VERSION)'=='MDK4.60'">"$(MDK_TOOL_PATH)\armcc\bin\fromelf.exe"</FROMELF>
<MDKLIB  Condition="'$(COMPILER_TOOL_VERSION)'=='MDK4.60'">"$(MDK_TOOL_PATH)\armcc\lib"</MDKLIB>

I jeszcze jeden element gdzieś koło linii 77:

<CC_CPP_ASM_INTERLEAVE Condition="'$(COMPILER_TOOL_VERSION)'=='MDK4.60'" ></CC_CPP_ASM_INTERLEAVE>

To wszystko. Można kompilować uruchamiając wcześniej setenv_mdk.cmd 4.60