egy mobil robot építésének története

Robotkocsi

Robotkocsi

Ahol bonyolódik a szoftver...

... elkél a debugger

2018. február 09. - dralisz82

A kezdeti, összedobott program elég kaotikusnak tűnt, így átszerveztem egy picit.
Külön osztályokba szerveztem a hajtásvezérlést, a lámpák kezelését, szenzorokat, stb. Minden osztályt egy .cpp és egy hozzá tartozó header fájlban implementáltam.
Ez a rész nem is okozott gondot, de a parancsértelmező kibővítése, hogy karakterek helyett parancsszavakkal lehessen irányítani az autót, sehogy sem akart működni.
Itt határoztam el, hogy kilépek a webes fejlesztőkörnyezet kezdeti kényelméből és egy debuggert is tartalmazó desktop környezetben folytatom a fejlesztést.

Az mbed környezetből szerencsére könnyen exportálhatjuk a projektünket, sőt, meglepett, hogy nem csak a Kinetis Design Studio-t választhatjuk, hanem rögtön több desktop fejlesztőkörnyezet közül is választhatunk.
A Keil v5-tel már volt dolgom korábban, így a KDS projekt mellett egy Keil projektet is generáltattam. A KDS-t mindenképp ki akartam próbálni, hogy a Linuxos laptopomon is legyen egy fejlesztőkörnyezet.

Kinetis Design Studio

A Kinetis Design Studio egy Eclipse alapú keretrendszer, de rá kellett jönnöm, hogy önmagában nem használható, bár ott van az arm-gcc toolchain, úgyhogy teljesen nem vagyunk elveszve.
Az egy dolog, hogy az exportált projektet sima C++ projektként importálva értelmetlen elérési utakkal prefixálta az összes header fájlra hivatkozást a kódban, de ezek javítása után sem sikerült továbblépni az object fájlok buildelésénél.

SDK és egyéb kezdeti nehézségek

Ahhoz, hogy tényleg használni tudjuk a Studiot, le kell tölteni a Kinetis SDK-t, amiből egy 1.x-es és egy 2.x-es sorozat is van.
Letöltöttem az NXP oldaláról két fájlt is, amik azt állították magukról, hogy ők az SDK, de amikor 1.x-es projektet hoztam volna létre a Studioban, arra panaszkodott a varázsló, hogy 2.x-es SDK-m van, amikor 2.x-eset, akkor arra, hogy 1.x-es.

Kis kutakodás után rájöttem, hogy nekem a https://www.nxp.com/ksdk oldalon a Downloads szekcióban elérhető Kinetis SDK Builder opcióra van szükségem, ami egy webes eszköz, ahol összeállíthatom a számomra megfelelő SDK-t.
Végigverekedtem magam az SDK Builder-en, majd a végén megint belefutottam egy zsákutcába:
"Jumpstart your configuration" gombra kattintva példaprogramot is választhatunk, majd nincs tovább, nem tudunk semmit letölteni.
Nyomtam egy "vissza" gombot a böngészőben, és voila, ahol az előbb még semmi sem volt, feltűnt egy "Request Build" gomb.
Erre kattintva végre legenerálhatjuk az SDK-t, amit remélhetőleg a Kinetis Design Studio is fel fog ismerni.
Miután frissítettem a profilomat, adtam egy egysoros leírást a projektről, a letöltés link is aktivizálódott.

Letöltöttem és kicsomagoltam az SDK-t az /opt/Freescale könyvtárba a KDS_v3 könyvtár mellé.
A KDS-ben új "Kinetis SDK 2.x Projekt létrehozására kattintva rögtön feltűnik az elérhető SDK-k között az imént kicsomagolt példány, tehát ráéreztem, hogy hová érdemes kitömöríteni.

Ámokfutás az online környezetből átemelt projekttel

Új projekt létrehozása helyett importáltam az online környezetből exportált projektemet, de a kapott projekt teljesen töröttnek tűnt. Szinte egyetlen includehoz sem passzolt az mbed library fájlszerkezete. Kézzel pedig reménytelennek tűnt mindent jó helyre rakni: egy include kijavítása után, újrafordításkor jött a következő hiba, majd a következő, és a következő, így itt egy hosszabb szünet következett a fejlesztésben.

Időközben frissült az mbed OS, valószínűleg az webes környezetben található exportereket is frissítették, ráadásul találtam egy fórumban egy utalást arra, hogy érdemes a webes projektünkben a felhasznált könyvtárakra jobbklikkelve egy frissítést nyomni, és a frissített projektből exportálás valóban ígéretes eredményt adott. Az mbed és az mbed-rtos könyvtárak struktúrája végre rendezettnek tűnt.

Libraryk frissítése után...

Importálás után nem látszottak nagyobb hibák a struktúrában, a fordítás is azonnal elindult a Build gombra kattintva.
Egyedül egy apró hiba jelentkezett: a 'MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE' was not declared hibaüzenetet kaptam a soros kommunikációért felelős driver fileokban.
Ez a paraméter pedig szerepel a projekt gyökerében lévő mbed_config.h fájlban, de úgy tűnik, hogy ezt elfelejtették includeolni a megfelelő helyen.
Mivel az érintett forrásfájlok mind includeolták a "platform/platform.h"-t, ezért abba szúrtam be egy #include "mbed_config.h"-t, ami megoldotta a problémát.

Innentől az összes forrásfájl sikeresen lefordult, a linker hívása azonban még tartogatott meglepetéseket:

ld:mbed/TARGET_K64F/TOOLCHAIN_GCC_ARM/MK64FN1M0xxx12.ld:66: ignoring invalid character `#' in expression
ld:mbed/TARGET_K64F/TOOLCHAIN_GCC_ARM/MK64FN1M0xxx12.ld:66: syntax error

A 66. sor titka

Gyors kereséssel sikerült tippeket kapnom:
https://github.com/ARMmbed/mbed-os/issues/3958
https://github.com/ARMmbed/mbed-os/issues/4044

A 66. sorban egy if feltétel található, és láthatók még defineok és egyéb preprocesszálást igénylő utasítások is a linker szkript fájlban. Az ld linker azonban nem végez preprocesszálást.
A hibára rákeresve kiderül, hogy a KDS exporter hibája, hogy olyan projektet generál, amiben nem történik meg ennek a fájlnak az előfeldolgozása.
Az eclipse_gcc_arm és make_gcc_arm exporterekben időközben javították a hibát, így ezekkel is exportáltam a projektet, majd az így kapott zip fájlokban található Makefile-ban megtaláltam a megoldást.
Ebből egy saját, kézzel futtatandó Makefile-t készítettem az alábbi tartalommal a projektem gyökerébe:

ARMPATH = '/opt/Freescale/KDS_v3/toolchain/bin/'

LINKER_SCRIPT = mbed/TARGET_K64F/TOOLCHAIN_GCC_ARM/MK64FN1M0xxx12.ld

PREPROC = '$(ARMPATH)arm-none-eabi-cpp' '-E' '-P' '-Wl,--gc-sections' '-Wl,--wrap,main' '-Wl,--wrap,_malloc_r' '-Wl,--wrap,_free_r' '-Wl,--wrap,_realloc_r' '-Wl,--wrap,_memalign_r' '-Wl,--wrap,_calloc_r' '-Wl,--w
rap,exit' '-Wl,--wrap,atexit' '-Wl,-n' '-mcpu=cortex-m4' '-mthumb' '-mfpu=fpv4-sp-d16' '-mfloat-abi=softfp'

 

$(LINKER_SCRIPT): $(LINKER_SCRIPT)p
@$(PREPROC) $< -o $@

A MK64FN1M0xxx12.ld fájlt átneveztem MK64FN1M0xxx12.ldp-re, ahol a p végződés utal arra, hogy preprocesszálandó, de ami a lényeg, hogy ne találja meg az Eclipse, így nem maradhatott .ld kiterjesztésű.
Majd meghívtam a /opt/Freescale/KDS_v3/bin/make parancsot és már létre is jött egy szuper linker szkript az eredeti helyén és névvel.
Ezután újra a Build gombra kattintva sikerrel vettem ezt az akadályt is.

Célegyenes

...Hogy jöjjön a következő:

arm-none-eabi-g++: error: unrecognized command line option '--gc-sections'

A Project Properties -> C/C++ Build -> Settings -> Cross ARM C++ Linker -> General paraméterek között kivettem a pipát a Remove unused sections (-Xlinker --gc-sections) opció mellől, majd jöhetett az újabb próbálkozás a Build gombbal.

Itt már célegyenesben éreztem magam, csak abban nem voltam biztos, hogy hogyan fogok beérni a célba:

mbed/TARGET_K64F/TOOLCHAIN_GCC_ARM/mbed_sdk_boot.o: In function `__wrap_main':
mbed_sdk_boot.c:(.text.__wrap_main+0xa): undefined reference to `__real_main' 

Újabb gyors keresés után úgy tűnik, hogy az okozhatja a problémát, ha a mbed_retarget.o fájlra nem hivatkozunk a linkelés során, de a fájl ott van a parancssorban, illetve a linker Miscellaneous paraméterei között, az Other objects listában is.
Viszont úgy találtam, hogy a __real_main igazából a mbed_sdk_boot.o fájlban van definiálva, de erre a fájlra is rendesen hivatkozunk linkelés közben...

mbed OS 5

Erre a problémára sehol sem találtam megoldást, így úgy döntöttem, hogy portolom a vezérlőprogramot mbed OS 2-ről mbed OS 5-re, ami a gyakorlatban annyit tesz, hogy az mbed és az mbed-rtos könyvtárak helyett az mbed-os könyvtárat választom az online környezetben, ami egyben tartalmazza a korábban külön könyvtárakban megtalálható funkciókat.

Az így nyert projektemet KDS-be importálva újra belefutottam egy-két előbb ismertetett ismerős hibába, amiket könnyen korrigáltam, de úgy tűnt, hogy komoly a baj.

Az mbed-os/targets mappában található Board Support Packageket (BSP-ket) mind kiszórtam a Freedomboardé kivételével, így máris kevesebb hiba maradt a kódban. Maradtak viszont olyan apróságok, hogy a mbed-os/features/nanostack/FEATURE_NANOSTACK/sal-stack-nanostack/source/configs mappában egyáltalán nem voltak .cfg fájlok, pedig a kód hivatkozott rájuk. Githubról leszedtem a nanostack forrását, amiben már ott voltak  a kérdéses fájlok, pedig elvileg az export előtt frissítettem az online környezetben is az mbed-os-t.

A fájlokat pótolva újabb hibákba ütköztem, de ezek egy része az adott funkció teljes kidobásával megoldható volt.

Az include hibák nem is voltak vészesek, de akadtak conflictoló típusok, implicit deklarációk, stb., tehát megint sűrűsödött a dzsungel...

Találtam egy tavaly márciusi fórumbejegyzést arról, hogy a KDS exporter még nem tökéletes, a fejlesztők tudnak róla, de még nem javították.

Áh, hagyjuk, nézzünk valami profibb környezetet:

Keil v5

A Keil-t már használtam korábban, így tudtam, hogy a kódszerkesztőt leszámítva nagyon felhasználóbarát, és professzionális felhasználásra is szánt termék. Szerencsére van belőle egy szabadon használható ingyenes változat, ami csak annyi korlátot állít elénk, hogy nem tudunk vele 32 kB-nál nagyobb binárist készíteni, ill. debugolni. Beágyazott rendszereknél a 32 kB szerencsére nagyon sokmindenre elég.

Az először exportált Keil projektem nem meglepő módon azonnal kukázható volt, amit viszont a lib-ek frissítése után exportáltam, tökéletesnek bizonyult. A Keil jelezte, hogy nincsenek telepítve a projektben szereplő Freescale targethez tartozó BSP csomagok, így készségesen elindította a Package Installert.

Package Installer

Itt egy listából a Freedom boardot kiválasztva megmutatta, hogy mely csomagok szükségesek, ill. melyek azok (pl. az ARM compiler), amikhez van frissítés.

A csomagokat telepítettem, bár valamiért a Package Installer nem tudott csatlakozni a keil.com-hoz, de a konzolra kiírt URL-eket böngészőbe másolva le tudtam tölteni a csomagokat, majd a Package Installer Import funkciójával tudtam telepíteni az így letöltött csomagokat.

Fordítás...

A Keil-t újraindítva, a projektemet újra megnyitva nem láttam hibát, így nyomtam egy "Rebuild all"-t, és valami hihetetlen csoda folytán egy-egy kósza warning mellett minden hibátlanul lefordult! Elsőre! Elképesztő!

Persze egy működő környezetből egy hibátlan projektet exportálva ez az elvárt működés, de ez akkor is lenyűgözött.

...és linkelés

Lelkesedésemet ekkor az törte meg, hogy a Keilban található ARM linker arról értesített, hogy a binárisom 37 kB lenne, ami nyilvánvalóan az ingyenes verzió 32 kB-os korlátja fölött van. Mivel a Keil-t GDP termelésre szánja az ARM, borsos ára van. Beszédes, hogy a hivatalos oldalon nincs is feltüntetve, csak ajánlatot lehet kérni. Valahol $5000 körüli árról olvastam, így elég valószínű, hogy a közeljövőben nem fogom megvenni.

Amit tenni lehet, hogy másik linkert, pl a GNU ARM toolchainben találhatót használom, ami állítólag a Keil-al nem kompatibilis binárist állít elő, de ha sikerülne, akkor is ott van még a debugger szintén 32 kB-os limitje.

Tehát amit tenni lehet: zsugorítani a kódot.
Először az mbed OS 2-es kódomat próbáltam meg kisebbre venni, majd megnéztem az mbed OS 5-re portolt változatot.

Menekülés 32 kB alá

A cél tehát egy legfeljebb 32768 byteos linkelt bináris.

Mivel elsősorban a parancsértelmezőt debugolnám, kukáztam az egyéb C++ osztályaimat, amivel máris 33020 bytera csökkent a bináris mérete. Kukáztam a komplett heartbeat threadet, ekkor azonban 36032 bytera nőtt a kódméret. A threadet inkább megtartva kukáztam csak  a LED-et reprezentáló DigitalOut objektumot, így 32856 bytera csökkent a méret.

A handleCommand() függvény kukázásával további 36 byteot nyertem, és akkor rájöttem, hogy van egy-két printf is a kódban, azok eltüntetésével akár célba is érhetek. Először 32792 bytera, majd 32776 bytera csökkent a bináris mérete, tehát már csak 8 byte választott el a sikertől!
Volt még egy printf-em, benne a "received chars:" stringgel, ami több, mint 8 karakter. Ezt szűkítve, illetve kompletten törölve azonban csalódnom kellett, a bináris mérete érthetetlen módon nem csökkent egy bytenyit sem, sőt, növekedett 37848 bytera!

Arra gyanakszom, hogy szándékosan szívat a linker, hogy ne lehessen 32 kb körüli méretű kódot készíteni vele. A maradék 8 byteot sehogy sem sikerült lefaragni, sőt megmagyarázhatatlanul több kilobyteot nőtt időnként a bináris.

Az mbed OS 5-re portolt vezérlőszoftvert is könnyedén sikerült importálni a Keil-ba, sőt, lefordítani is, azonban ott 64040 byteról indulna a hajsza, amit így meg sem próbáltam.

Konklúzió

A jó hír viszont, hogy mbed OS 5-tel megszűnt a platformnak az a hibája, ami miatt az UART megszakításkezelője összeakadt az mbed OS 2 szálkezelésével! Így akár desktop fejlesztőkörnyezet és debugger nélkül is sikerülhet a parancsértelmezőt működésre bírni.

A folytatáshoz tehát visszatérek az online fejlesztőkörnyezetbe. Jó tanulság, hogy érdemes nagyon alaposan megválasztani a fejlesztőeszközeinket, beleértve a hardvert és a szoftvereket is, mert nagyon sok energiát emészthet fel az ezekkel hadakozás a produktív fejlesztéssel szemben.

Viszont, ha már van ez a kártyám, és az mbed OS 5-ös verziója tényleg sokkal ígéretesebb, mint a 2-es, adok még neki egy esélyt a folytatáshoz.

A bejegyzés trackback címe:

https://robotkocsi.blog.hu/api/trackback/id/tr2113085558

Kommentek:

A hozzászólások a vonatkozó jogszabályok  értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai  üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a  Felhasználási feltételekben és az adatvédelmi tájékoztatóban.

Nincsenek hozzászólások.
süti beállítások módosítása