A karom, a karom! A karom akarom!

 ( balagesz | 2018. január 24., szerda - 21:02 )

Annyiszor leírtam már, hogy jobb ha nem is linkelem: C-t kellene tanulnom. Ehhez viszont jól jönne valami projekt, mert csak a „tanulás kedvéért” az ilyen nem szokott menni. Azért akadt már a múltban példa, (meg jó pár nem publikus is, ) de a cézés előnye nem a 8 bites, egyszerű mikrovezérlőknél jön majd elő, hanem akkor, ha valami „modernebbet” akarok programozni. A „modernebb” alatt továbbra sem valamilyen OS alá készülő alkalmazást értek, hanem bare-metal programozást, igazi hardver-közeli bitpiszkálásos mókát, csak komolyabb, leginkább a 8-nál nagyobb bitszámú mikrovezérlőn. Mondjuk 32 elég is lesz! Manapság ilyenből egy kis MIPS mellett a leginkább elterjedt architektúrák az ARM-tól jönnek. De kész mikrovezérlők / alkalmazásprocesszorok azok nem, az ARM maga nem gyárt terméket, csak IP-ket licencel másoknak.

Alkalmazásprocesszorokkal egyelőre nem foglalkoznék, azokhoz úgyis valamilyen óperenciás rendszer illik, maradnék most a mikrovezérlő vonalon. Vagy ezer éve beszereztem egy ARM7TDMI magos mikrovezérlővel felépített „fejlesztő” nyákot, amihez egy USB soros portot „produkáló” mintaprogramot el is kezdtem átalakítani a megfelelő feladatra. De ez a projekt is „elsüllyedt”, olyannyira, hogy az ARM7TDMI azóta tulajdonképpen ki is ment a divatból. :) Most a Cortex-M különböző fajtái futnak inkább, de ez se számít (így, 2018 elején) valami újdonságnak. Mint a linkelt Wikipedia oldal is írja, rengeteg gyártótól lehet venni Cortex-M magos mikrovezérlőt, és ami az igazán szép, hogy az „egyszerűbb” verziók simán olcsóbbak lehetnek a 8 bites társaiknál, így aztán kérdés, hogy van-e manapság létjogosultsága azoknak a 32 bites csipek mellett? (Válasz, az nincs. Gondolom itt is az van, hogy ha a tervezőmérnök „megszokott” egy típuscsaládot, akkor nyomós ok kell ahhoz, hogy váltson.)

Ez az első ARM-os teszt annyira régen volt, hogy az, amit utána próbáltam, már az is régi történet, úgy 2011 körüli. De pont arról lesz szó, mivel ez nálam egy ilyen „évente visszatérő jelenség”. A gyártó a Nuvoton, ami lehet hogy nem mond sokat, 2011-ben nekem se volt ismerős. Rákeresve kiderült, hogy ez egy Winbond-ból kivált cég, a mikrovezérlős / azzal összefüggő termékeket ezentúl az új csapat készíti. Akkor a legegyszerűbb, Cortex-M0 magos tokok voltak elérhetőek, ma vannak már „komolyabb” változatok is, de a portfólió jelentős részét még mindig az M0 teszi ki, ahogy látom... Több ok is volt, ami miatt akkor képbe kerültek a mikrovezérlőik. Egyrészt 50 MHz-es órajellel is mehetnek (pár dologra csak elég...), aztán 5V-os (!) táp is jó / megfelel nekik. (Ez utóbbi nagyon nem jellemző! Maga a core talán 2.5V-ról jár, de be van építve hozzá egy feszültségstabilizátor, kívülről nem kell neki más tápot előállítani. Az I/O lábak meg természetesen a tápfeszültséghez igazodnak.) A hozzá tartozó fejlesztő eszközök ára meglehetősen barátságos (volt), de maguk a csipek is pofátlanul olcsónak tűntek. :) (Ha megnézem, ilyen 1000 Ft. alatti nettó árakat látok most, még a legnagyobb memóriával rendelkező tokoknál is.) Ez valahol tuti vissza fog ütni, ezt már akkor is gondoltam, de hamarosan az is kiderült, hogy hol. A dokumentációk sok színes-szagos dolgot elmesélnek, minden szép és jó. Na, de a szupport... Arról nehéz lesz írni, mert az tulajdonképpen nincs. :-D (Nyilván ez azért így nem teljesen igaz, csak töredéke a fellelhető információ bármelyik másik gyártóhoz képest.) De kanyarodjunk vissza egy kicsit a 2011-es állapotokhoz. Akkor beszereztem egy fejlesztőcsomagot, ami tartalmazott egy alap fejlesztői panelt rajta egy „nagyobb” NuMicro (így hívják a programozandó µC szériát) mikrovezérlővel, meg tartozott hozzá egy USB-s programozó / debugger dongle:

A kivezetésekhez tartozó tüskesorok nem képezték a készlet részét, azokat már én forrasztottam be! :) Ettől függetlenül ez eddig még tetszetős is. A csomaghoz tartozik még egy (írott!) CD, rajta némi dokumentáció illetve a programozáshoz / csip feltöltéséhez szükséges stuffok. Na, és itt kezdődnek a bonyodalmak... Fejlesztő programnak mellékelték két nagy gyártó, az IAR illetve a KEIL aktuális Cortex-M-es IDE-jének a demó verzióját. :) Fantasztikus! A Nuvoton oldala említi még a Coocox CoIDE-t, ami egy Eclipse-ből kifaragott IDE, ez a GCC ARM-os fordítóját használja. (Ez a CooCox elvileg egy kínai egyetemi projekt, az Eclipse-t addig faragták, hogy csak Windows®-on fut, ráadásul rengeteg mindent az internetről töltöget le használat közben, az meg – hogy is mondjam – felvet némi kérdést. :) ) Ez így már 3 integrált fejlesztői környezet, nekem meg még mindig hiányérzetem van. Ugyanis ezek közül mindegyik Win-only stuff, nekem meg inkább Linuxra kellene valami. A GCC-vel biztos hogy nincs baj, IDE meg van itt is bőven, de van egy „bökkenő”: a megírt / lefordított programot valahogy a mikrovezérlő FLASH memóriájába kellene írni. A dongle-hez tartozó direkt programozó stuff is kizárólag Win-en fut, a fantasztikus „Nu-Link” kifejezésre meg nem hoz valami értelmes találatdömpinget egyik kereső sem. Rengeteg kereséssel odáig jutottam, hogy a Nu-Link protokollja zárt, csak a gyári stuff tudja használni. Még itt, az elején lelövöm a poént: nem, most sem találtam semmilyen lehetőséget arra, hogy Linux alól a Nu-Link-et használni tudjam. Pedig valószínűleg nem lenne annyira nagy kaland, dmesg részlet:

usb 1-2.4: new full-speed USB device number 7 using ehci-pci
usb 1-2.4: New USB device found, idVendor=0416, idProduct=511c
usb 1-2.4: New USB device strings: Mfr=1, Product=2, SerialNumber=0
usb 1-2.4: Product: USB ICE 
usb 1-2.4: Manufacturer: USB 2.0ICE 
input: USB 2.0ICE  USB ICE  as /devices/pci0000:00/0000:00:12.2/usb1/1-2/1-2.4/1-2.4:1.0/input/input5
hid-generic 0003:0416:511C.0003: input,hidraw2: USB HID v1.10 Device [USB 2.0ICE  USB ICE ] on usb-0000:00:12.2-2.4/input0

Ez egy sima HID-device, amihez egyéb driver nem is kell, lehetne kezelni simán. Maga a dongle egyébként pont egy olyan µC-re épül, amit éppen programozni szeretnék vele.

Viszont ha már előjött a belső FLASH programozása, itt is van azért egy kis kavarás. Az, hogy egy mikrovezérlő „nemfelejtő” memóriájába hogyan kerül bele a belevaló firmware, arra több lehetőség is van, most így hirtelen 3 variáció ugrik be:

  1. A még nem beszerelt csipet egy erre a célra készült programozó készülékbe rakják, majd azzal felprogramozzák. Általában valami gyors algoritmussal, a µC sok lábát használva egyszerre, párhuzamosan. Ezt inkább nagy-szériás gyártásban alkalmazzák, a programozó eszköz csak programozni tud, drága, hobbi-szinten ez nem játszik.
  2. Kis szériában / háztáji körülmények között az un. ISP / In-System Programming az, ami szóba jöhet, ebben az esetben az adott µC már be van szerelve a helyére az áramkörbe, onnan kap tápfeszültséget, órajelet, miegymást. A fw beírását itt is valami speciális eszköz végzi (mint pl. a fenti Nu-Link), de ez a módszer a µC néhány (kevés!) lábát használja csak a firmware „beégetése” alatt. Itt a programozó hardver már lehet (relatíve) olcsó, cserébe a kész áramkörben kell a µC „élesztését” elvégezni, ami lehet plusz macera. Programfejlesztési szakaszban viszont egy áldás, hogy nem kell egy fw cseréhez kiszedni a helyéről az IC-t.
  3. A legolcsóbb megoldás az, amikor a µC eleve tartalmaz egy olyan programot, amivel a tényleges firmware a FLASH-ébe tölthető. Ekkor a mikrovezérlő a saját programmemóriáját írja a saját magán futó szoftverrel. Az, hogy a tényleges firmware milyen úton jut el a mikrovezérlőbe, ez implementációfüggő. Régen sima soros portot használtak erre, manapság inkább az USB a „menő”, de a lényeg nem változott: a mikrovezérlőn futó kód végzi a FLASH írását. Ezt a kódot hívják „bootloader”-nek, így ez a fajta FLASH-írás a bootloader-es programozás. Itt „csak” az a kérdés, hogy maga a bootloader hogy kerül bele a mikrovezérlőbe? Vagy az első, vagy a második módszerrel kell „beprogramozni”, de a régi ARM7TDMI-s mikrovezérlő, amivel először találkoztam közelebbről, az gyárilag tartalmazott egy bootloader-t. Egy megfelelő „lábbekötéssel” ezt maga belemásolta a saját FLASH-ébe, amivel utána soros vagy USB kapcsolaton keresztül fel lehetett tölteni a végleges firmware-t.

Ennek a „rákeresek a Nu-Link-re / NuMicro-ra, hátha van valami változás” jellegű feladatnak szinte minden évben nekifutottam azóta, nagyjából eredménytelenül. Aztán tavaly (?) valamikor rátaláltam a Nuvoton ISP Tool-jára a github-on, mint programozó szoftver. Ugyan továbbra is Windows®-only, de ebből talán ki lehet indulni... Ki lehet? Hát, nem igazán. :-D A fenti három FLASH programozási módszer közül mindre van megoldás itt is, de amit a nagyvilág ISP-nek hív, azt a Nuvoton ICP-nek (In-Circuit Programming). Amit itt ISP-nek hívnak, az tulajdonképpen a bootloader-es firmware feltöltés, egy ilyenhez tartozó ARM-os kód illetve az azt kezelő Windows®-os program forráskódja található meg a linkelt github repóban (egy adag további érdekesség mellett), nekem meg továbbra sem az kell.

Tehát nagyjából az a szituáció, hogy ameddig a µC-ben levő FLASH-t nem tudom írni, addig a többi részen (fordító, mintaprojekt...) kár is gondolkodni. Emiatt itt a „visszafele haladás” esete fog fennállni. Na de mi is szokott lenni az a kevés vezeték, amivel ezeket programozni szokták? Az ARM-os magok között általában ez is szabvány, a port neve JTAG, ez 4 (esetleg 5) vezetékből áll. Viszont a Cortex-M0 esetén nem szokás (nincs is?) a JTAG-port, ehelyett a 2 (plusz 1) vezetékes SWD-t, a Serial Wire Debug portot használják. Itt is ez a helyzet, bár ezt meg ICE (In-Circuit Emulator?) interfésznek hívja a doksi, az SWD-t mint megnevezést hanyagolják... :) Úgyhogy a keresés „másik szála” az SWD-t tudó interfészek / programozók irányába zajlott, de pár zsákutcát leszámítva ott se jutottam sok eredményre. Legalábbis régebben... Később lehetett olyan „híreket” találni, hogy az SWD kezelése esetleg bekerül az OpenOCD-be, ami valamikor az elmúlt 7 évben aztán meg is történt. :) Az OpenOCD alapból NEM egy FLASH programozó eszköz, hanem – mint a neve is mutatja – egy „On-Chip Debugger”, a µC-en futó programot lehet vele „debuggolni”. Ettől függetlenül sok mikrovezérlő FLASH-ét is lehet vele írni, mivel azért ez erősen idevágó feladat.

Tavaly év vége fele jött az ötlet, hogy ismét rákeresek a szokásos dolgokra, de közben ránézek az OpenOCD SWD szupportra, hátha abból is ki lehet valamit okoskodni. Az SWD, mint port az ARM-tól jön, tulajdonképpen szabvány. Nézek valami olyan eszközt, ami SWD-s és támogatja az OpenOCD, aztán abból talán ki lehet indulni. Hátha a FLASH-írás is szabványosított, így esetleg elég lesz pár azonosítót átírni, aztán már működhet is! Hát, ez nem egészen így van, de erről később.

Első lépésként kell valami hardver (a Nu-Link helyett, attól egyelőre könnyes búcsút veszek), amit a pc-re lehet kötni, a másik fele SWD portban végződik, illetve én is meg tudom építeni, meg támogatja az OpenOCD. A keresési találatok zöme olyan kapcsolásokat hozott, ami JTAG és / vagy SWD portot valósít meg, mindezt az FTDI-féle FT2232 USB-soros átalakító csippel. Ezt a csipet a Linux kernel alapból támogatja, ez egy két csatornás USB-soros átalakító. Azért kedvelt ez az IC ilyen feladatokra, mert van benne egy ide tökéletesen illő funkció (ami az egy csatornás változatokban nincs meg), az MPSSE. Ez a Multi-Protocol Synchronous Serial Engine rövidítése, mind a JTAG, mind az SWD szinkron-soros port, ezzel meg pont ilyen adatátvitelt lehet „szabadon” programozni. (A részletes MPSSE programozási dokumentáció elérhető, ha valaki akar, nyugodtan belemélyedhet.) Ráadásul az OpenOCD rengeteg, ezzel a csippel épített adaptert támogat, tehát ez a rész is rendben van. Az FT2232-nek még meg is örültem, mivel régebben (az is egy ősi projekt, 2012-es) csináltam egy JTAG interfészt vele, az lesz most a főszereplő:

A képen levő áramkör egy galvanikusan leválasztott (!) JTAG port, ez most szét lesz szedve! :| Sajnos az eredeti célra, amire készült, arra nem tudtam használni, de ide pont jó lesz! Mint látható, az FT2232 nem egy „felhasználóbarát” tokozásban van, ez egy 48 lábú LQFP tok, 0.5mm-es lábtávolsággal. A nyákot alá az egyik ismerősömmel készítettük, (Ezúton is köszönet érte!) vasalásos (!) technikával. Azt azért ki merem jelenteni, hogy ennek a technikának erősen ez az alsó korlátja... :-D A „lábasjószágok” (kondenzátorok, ellenállások, kvarc, ...) a nyák túlsó felén vannak, nincsenek elspórolva. Az áramkör a mintakapcsolás alapján készült:

Ez (a konfigurációt tároló 16 bites EEPROM-mal együtt) van a PCB-n, az FT2232 összes I/O lába (2×12 + még pár apróság) meg ki van vezetve arra a tüskesor-párra, amivel a prototípus-panelre csatlakozik. Amikor ez készült, valahogy sejtettem, hogy az FT2232-es „alapkapcsolás” jó lesz még nekem máskor is!

SWD-t tudó áramkört azt szerencsére találtam, talán túl sokat is. A legegyszerűbbeknél maga az FT2232 hajtja így vagy úgy a vonalakat, egy „apró” probléma van csak: az egyik SWD láb (SWDIO) kétirányú, az FT meg „szeret” külön lábon olvasni / hajtani. Ezt több fajta módon is látni „megoldva”, a leg-hack-szagúbb változat az volt, hogy a porthoz tartozó VCCio lábat a dear user ne kösse be, így az FT nem fog magasat hajtani, csak alacsonyat. :-D Volt olyan változat, aminél egy ellenálláson keresztül hajtotta az SWDIO-t az FT, ott a target „túl tudta hajtani” az aktuális szintet, ha éppen ő adott. Mondjuk úgy, hogy egyik sem nyerte el a tetszésem...

Jó lenne, ha a megépítendő kapcsolásban lenne plusz vonalhajtás, nem az FT intézné ezt, szerencsére ilyen kapcsolás is akad. Persze itt is elvesztem a részletekben, mert az OpenOCD „agyon konfigurálható” ilyen szinten is, de ez a projekt valahogy így alakult... :) Az FT2232 mellett található egy 93C46B/C EEPROM, ami az eszköz konfigurációját tárolja. (Egyrészt az USB-s adatok: VID/PID, név, ilyenek, másrészt a csip funkciók alapbeállításai: melyik port hogyan működjön, stb.) Ez egy 1 Kbites EEPROM, 64 szó × 16 bites szervezésben. (Érdekesség, de erősen állítólag: mivel az EEPROM 16 bites szervezésű, ezért egyszerre csak 16 bites darabokban frissíthető a tartalma. Pár éve sok FTDI-s csipet hamisítottak, a gyártó cég meg kiadott egy olyan drivert, ami „tönkretette” a klónokat. Ott állítólag az történt, hogy a driver 8 bites írásokkal végigírta az USB azonosítókat, amit a gyári verzió a hardverből kifolyólag nem tudott végrehajtani, de a klónok implementálták ezt is, emiatt ott meg „elromlottak” az adatok. A gyártó részéről egyrészt érthető a magatartás, másrészt meg elég gusztustalan húzás, mivel nagy részben azok a végfelhasználók szívták ezt meg, akiknek fogalmuk sem volt róla, hogy hamisított csip van az eszközükben.) Az, hogy „valamelyik ismert eszköz”-ként tudja majd a saját implementációm „mutatni magát” az OpenOCD felé, kellene az EEPROM tartalom, ami hozzá tartozik... Ez egyre cifrább lesz. :) A netet túrva viszont szembe jött velem ez az oldal, ez azt írja le, hogy hogyan kell a TI féle Stellaris-ICDI interfész EEPROM tartalmát helyreállítani. Az igaz, hogy mindezt továbbra is Win-en, de én mintha programoztam volna az FT2232 melletti EEPROM-ot Linux alól! Letölthető a „gyári” konfigurációs fájl, amit az FTDI saját programozójába lehet betölteni, de egy szkrínsoton ott van a kész tartalom is, legföljebb onnan le kell írni. :) A Stellaris-ICDI interfész JTAG/SWD-képes, ismeri az OpenOCD, van EEPROM tartalom, már csak egy kapcsolási rajz kellene hozzá. :)

De először az FT konfigurációs EEPROM-ot lesz érdemes valahogy felprogramozni, mert ez alapján fogja tudni az OpenOCD azonosítani majd az eszközt. Ha van a környéken Windows®, akkor erre a gyári FT_PROG megfelelő lehet, nekem most éppen nincs kéznél, így a feladatot Linux-on kell megoldani. De rémlik, mintha annak idején ez már sikerült volna… Találtam egy ftx-prog nevű utilt, ami pont azt ígéri magáról, hogy a gyári FT_PROG-ot ki tudja váltani Linuxon. Simán fordítható, de állandóan ellenőrző hibát mond az EEPROM tartalomra… Valami tuti nem kerek vele, mert 256 BYTE-okat olvas / ír, holott itt csak 128-at kellene neki. A programban a hosszt módosítva más lesz a számított checksum, de valahogy úgy se jó… :) Viszont! A megoldás keresése közben ráakadtam egy projektre. A készülő eszköz most nem érdekes, de a leírás pont az FT EEPROM programozásáról szól, csak az ftdi_eeprom nevű utility segítségével. Fura módon van ilyen nevű parancsom telepítve, ez a libFTDI része. A használata már nem annyira kézenfekvő, ebben a fenti projekt elég nagy segítség... Kell hozzá egy konfigurációs fájl, ami alapján elkészül az EEPROM tartalom. Ha ez megvan, ki kell deríteni, hogy milyen azonosítói vannak most az eszköznek, erre a legegyszerűbb a lsusb parancs a csatlakoztatás után:

$ lsusb
Bus 004 Device 006: ID 0403:6010 Future Technology Devices International, Ltd FT2232C/D/H 

Egy „üres” EEPROM-os eszköznél valami ilyesmi látszik, de törölni így lehet:

ftdi_eeprom --erase-eeprom --device i:0x0403:0x6010 configfile.conf

Az i:0x0403:0x6010 az eszköz Vid/Pid kódja, ez az lsusb kimenetéből kinézhető. Ha szükség lenne az EEPROM tartalmára, azt is ki lehet olvasni:

ftdi_eeprom --read-eeprom --device i:0x0403:0x6010 configfile.conf

A Vid/Pid értelemszerűen az eszköz jelenlegi azonosítója. A configfile.conf fájl – úgy tűnik – még a törléshez / kiolvasáshoz is kell! :) Az EEPROM „beégetése”:

ftdi_eeprom --flash-eeprom --device i:0x0403:0x6010 configfile.conf

A fenti parancsok futásához szükséges a configfile.conf, ez lett az enyém (a fent linkelt projekt alapján, csak a lényeg):

vendor_id=0x0403    # Vendor ID
product_id=0xbcda   # Product ID

max_power=500       # Max. power consumption: value * 2 mA. Use 0 if self_powered = true.

manufacturer="LMI"                   # Manufacturer
product="Luminary Micro ICDI Board"  # Product
serial="0B010001"                    # Serial

self_powered=false         # Turn this off for bus powered
remote_wakeup=false        # Turn this on for remote wakeup feature
use_serial=true            # Use the serial number string
suspend_pull_downs=false   # Pull Down lines under suspend
high_current=false         # High IO current

in_is_isochronous=false     # In Endpoint is Isochronous
out_is_isochronous=false    # Out Endpoint is Isochronous
suspend_pull_downs=false    # Enable suspend pull downs for lower power
change_usb_version=false    # Change USB Version
usb_version=0x0200          # Only used when change_usb_version is enabled

cha_vcp=false
cha_type=FIFO
chb_type=UART

eeprom_type=0x46

filename="eeprom.bin"   # Filename, leave empty to skip file writing

Az utolsó sorban levő filename= paraméter annak a fájlnak a nevét adja meg, ahova a kiolvasás / generálás után az EEPROM tartalom elmentődik. A fentiek betöltésének az eredménye egész közel áll az eredeti EEPROM tartalomhoz, pár BYTE-nyi eltérés van csak, de ezek most nekünk nem érdekesek. :-D (Amúgy az eredeti tartalomhoz tartozó kapcsolás is jó lehetne, az is tud JTAG mellett SWD-t is, de most már maradok az eredeti tervnél.)

Tehát van egy FT2232-es „alapkapcsolásom”, ami a Luminary Micro ICDI Board (Stellaris ICDI Board) névre hallgat, de kéne az FT utáni rész is, ami a JTAG/SWD illesztést elvégzi. Szerencsére a Stellaris development board-ok dokumentációja elérhető, bennük a kapcsolási rajzokkal. Rákeresve, az első találat talán ez volt, ez a „Stellaris® LM3S1968 Evaluation Board” felhasználói kézikönyve, de rengeteg (szó szerint!) ilyen fejlesztőeszköze van a TI-nek, ezeken integrált a JTAG/SWD interfész. Ami a linkelt darabot illeti, itt a vonalak hajtását, a JTAG/SWD „multiplexelést” (meg pár apróságot) egy CPLD-vel valósítottak meg. Viszont a dokumentációban ott van a felépített kapcsolás is, így látszik, hogy miből is áll a dolog. Ugyan ezt a típust nem használom, de adott egy jó ötletet: ilyet tudok én is csinálni egy általam is használt CPLD-vel! Nem lesz két I/O bankom külön VCCio-val, de enélkül is boldogulhatok... Az FT2232 VCCio része jelenleg +5V-ra van kötve, de a dokumentációja szerint a bemeneti feszültségszintek inkább a TTL-hez mint a CMOS-hoz vannak közel, azaz simán hajthatom őket „befele” +3.3V-os jelszinttel. A CPLD VCCio-ja +3.3V-tól +5V-ig mehet, viszont +3.3V esetén is +5V-toleráns... Összegezve tehát a CPLD-m VCCio-ja köthető +3.3V-ra illetve +5V-ra is, az FT2232 fele/felől nem lesz semmi gond a jelszintekkel, a JTAG/SWD interfész irányába meg a kívánt jelszintekkel fog hajtani. Ehhez képest minden megoldás bonyolult. :) A végeredmény ilyen lett:

Szinte „szédülök”, akkora szabad helyek maradtak a nyákon. :) (A másik dobozka egy JTAG kábel, a CPLD felprogramozása zajlik éppen.) Így utólag visszagondolva, megmaradhatott volna a galvanikus leválasztás is, de azt „sajnos” szétbontottam. A csip 1999-es gyártmány, lassan 20 éves lesz. Ez idő tájt kezdtem ismerkedni a CPLD-kkel, sanszos, hogy ez az első pár próbadarabok egyike lesz... A VCCio kapott egy +3.3V-os stabilizátort, de úgy lett bekötve, hogy a target felől jövő esetleges +5V fel tudja emelni, így meglesz a CMOS +5V-os jelszint-illesztés is (target-táp nélkül meg marad +3.3V, a CPLD nem jár VCCio nélkül). Alacsonyabb jelszintekkel egyelőre nem foglalkozok.

Lassan jöhetne egy teszt, OpenOCD próba, de maradjunk a JTAG-nál első körben:

És igen! Éledezik a cucc! :) Az OpenOCD a működéséhez szükséges adatokat konfigurációs fájl(ok)ból veszi, ilyet meg lehet neki adni többet is a -f paraméterrel. Az -f interface/ftdi/luminary-icdi.cfg paraméter mondja meg, hogy milyen típusú a használni kívánt interfész. (Ez a minimum, amit mindenképpen meg kell adni.) Az /usr/share/openocd/scripts/interface könyvtárban megtalálható jó néhány különböző interfész, az általam kiválasztott eszköz konfig fájljába belenézve viszont rendesen elcsodálkoztam. :-D Itt az interfész típusának egyszerűen ”ftdi” szerepel, azt, hogy mi hova van kötve, az szövegesen van leírva, mint ahogyan az is, hogy mi alapján azonosítja magát az eszközt. Remek... Simán definiálhatnék saját FT2232-vel készült interfészt, nem kellene ragaszkodni semmilyen jelenlegi verzióhoz! Így aztán fölösleges is volt EEPROM tartalmat vadászni... Bravó! Na, de ez már így marad.

A másik konfigurációs fájl már saját, itt két sor van benne:

adapter_khz 1000
transport select jtag

Ez az adatátvitel sebességét, illetve az interfész üzemmódját adja meg. Ami a képen látszik: talált a JTAG láncban egy eszközt, aminek a gyártóját mint „Xilinx” azonosította, és valóban: tesztből egy CPLD-t kötöttem rá az interfészre, szóval működni látszik a dolog!

Lassan minden (is!) meg lesz, de a tényleges feladattal még egyáltalán nem foglalkoztam. Ez a „projekt” vagy 7 éve ilyen nyögvenyelősen halad... :| Most már legalább illene rákötni ezt az egész cuccot a dev. board-ra. Persze ez sem lesz ilyen marha egyszerű... :) Az eredeti teszt-környezetet úgy képzelték el, hogy a Nu-Link USB-n a gépre van kötve, és a dongle maga biztosít tápot az ICE csatlakozón keresztül a dev. board-nak. Hogy kevésbé legyen „össze-vissza” kötözve a tápfeszültség, ezért a dev. board-on van egy dióda, ami „befelé” engedi a tápfeszültséget. A Nu-Link-ben meg szintén tervezve van egy dióda, ami „kifelé” küldené az USB +5V-ot az ICE csatlakozó felé, de ezen utóbbi helyére egy rövidzár van forrasztva:

Ezzel a felépítéssel csak annyi a gond, hogy az ICE csatlakozón így nincs meg a tápfeszültség „visszafele”, ami alapján a fent elkészült elektronika „illeszteni tudná magát” a megfelelő jelszintekhez. A terv: a diódát meg a rövidzárat leszedni, majd a dev. board-ra kerül a rövidzár, a Nu-Link meg megkapja a diódát:

A Nu-Link-en a dióda fordítva lett felszerelve a jelzett állapothoz képest, és ennek oka van: az ICE csatlakozón keresztül nem akartam, hogy megtápolja a fejlesztő nyákot, viszont a dongle-nek van (vagy tervben van?) egy olyan funkciója, hogy lehet vele a target-et programozni számítógépen futó programozó stuff nélkül is. Ehhez tartalmaz egy külső EEPROM-ot, amibe a letöltendő fw-t „elmenti”, majd gombnyomásra betölti a csatlakoztatott target-be. Ehhez viszont meg kell tudni táplálni az USB csatlakozás nélkül is. Aztán hogy ez így jó-e, meg használom-e valaha, az megint egy másik kérdés...

Most már csak egy egyszerű kábel kell a két „készülék” közé, aztán végre összekapcsolható a pakk:

Összedugva, megtáplálva... Vajon mit szól hozzá az OpenOCD? Első nekifutásból a transport select jtag sor módosult transport select swd-re, de erre az OpenOCD közölte, hogy ezt az interfészt csak JTAG-nak tudja használni. :) Viszont CentOS-ban minden régi, a telepített OOCD (talán...) a 0.8.0-ás. A honlapot megnézve, a jelenlegi legfrissebb a 0.10.0, ez 2017 januári, de mit is látok az újdonságok között:

Flash Layer:
  Unified Nuvoton NuMicro flash driver

Nahát! Erre várok 7 éve? :-D Fedora alatt ez a verzió van aktuálisan csomagban. A „szokásos” trükk be is jött; a forrás RPM-et letöltve és szétszedve meg is van a .spec fájl, aminek a segítségével „simán” készül belőle CentOS-os csomag. („Simán”: a fordításhoz szükség van az SDCC-re, de rossz néven, sdcc- előtaggal keresi a binárisokat, nekem meg „normál” néven vannak, ezt javítva illetve a függőségeket telepítve egyből minden rendben is lesz.) Az új csomagot felrakva folyik a teszt további része:

A JTAG interfész az eszközökben egy un. TAP-hoz („Test Access Port”) kapcsolódik. Ezeket „sorba lehet kötni”, így egy interfészhez több TAP is csatlakozhat. (Sőt: simán van olyan is, hogy egy IC-n belül (!) van több TAP, amik már ott is sorba vannak kötve!) Emiatt meg van oldva az egyes TAP-ok azonosíthatósága. (Ez látszott az első tesztnél, a csatlakoztatott IC-ből pár azonosítót ki is olvasott az OOCD.) Az SWD port – a JTAG-gal ellentétben – egy sima pont-pont kapcsolat, és itt úgy tűnik, hogy nincs megvalósítva az azonosítás. A NuMicro támogatás megjelenésének már csak ezért is örülnöm kell; volt mit megadni az OpenOCD-nek mint target. Enélkül egy Error: BUG: current_target out of bounds hibaüzenet az eredmény. Így viszont az első pár Info sor után a következők ismétlődnek folyamatosan:

Info : NuMicro.cpu: hardware has 4 breakpoints, 2 watchpoints
Error: NuMicro.cpu -- clearing lockup after double fault
Polling target NuMicro.cpu failed, trying to reexamine

Ha azt a 4 bp / 2 wp adatot a csipből olvasta ki, akkor valami már alakul! A double fault-os hibasor viszont még érdekesebb... Ez úgy tűnik, hogy a µC-ből jön! Mivel jelenleg „üres” a programmemória, esélyes, hogy valamilyen hibára fut a végrehajtás rögtön a legelején. Itt – gondolom – előszedi a hozzá tartozó kivételkezelő címét a CPU core, ahonnan elkezdené végrehajtani az ott található kódot, ami szintén hibára fut. A dupla-hiba ez a szituáció szokott lenni, ilyenkor egy jól nevelt CPU szépen megáll, aztán kész. :)

Ez azért így már eléggé biztató! Kell itt még egy-két paraméter majd, de a parancssor már kezd így is eléggé csúnya lenni. Erre viszont van megoldás az OpenOCD oldaláról: egyrészt egy konfigurációs fájlból simán „be lehet tölteni” egy másikat, másrészt ha az OOCD paraméter nélkül van elindítva, akkor az adott könyvtárban levő openocd.cfg fájlt megnyitja alapból. Ebbe be lehet rámolni a kívánt dolgokat:

source [find interface/ftdi/luminary-icdi.cfg]
transport select swd
set CHIPNAME NUC140VE3AN
source [find target/numicro.cfg]
adapter_khz 500
init
reset halt

Először a kábel-beállítás van „behúzva”, utána az SWD mód beállítva. Azután az eszköz típusszáma van megadva, hogy ez mire „jó”, az még kiderítésre vár, mindenesetre ezt írja ki a kimenetre névnek. Utána a target beállítása következik (ez „használja” az előző nevet). Az adapter sebességét itt visszaállítottam „lassabbra” a teszthez, ezt a numicro.cfg beállítja előtte. Ez egyébként mással is működik: ha ugyanaz van többször is beállítva, az utolsó lesz majd érvényes. Az utána levő init – mint a neve is mutatja – inicializál valamit, a reset halt sor „reszeteli” + megállítja a CPU-t. A végeredmény:

A CPU mag megállt, az OpenOCD meg itt áll és vár. No de mire? Hát arra, hogy valamit kezdjen a dear user a megállított maggal. Ez (legalább) kétféle módon lehetséges:

  1. Ha a konfigurációs fájl tartalmaz még plusz parancsokat, azok – természetesen – végrehajtódnak. Itt a fenti sorok után az openocd.cnf-be bekerült még egy targets sor, ez kiírta a target-eket, jelen pillanatban ezt az egyet. (SWD esetén nem is lesz több, ha jól sejtem.)
  2. Ha „nem lehet előre tudni”, hogy mi is fog majd történni, akkor a futó OpenOCD-hez hozzá tud kapcsolódni egy másik program, ami parancsokat adhat neki, amiket végrehajt. Ez lesz jó majd az esetleges „debug” alatt.

A teszthez most a második verzió az érdekes, az OpenOCD-hez való kapcsolódást pedig a telnet végzi:

$telnet localhost 4444

Ezzel az „Open On-Chip Debugger” parancssorába jutunk, a fenti targets parancsot kiadva itt is látszik a végeredmény:

Open On-Chip Debugger
> targets
    TargetName         Type       Endian TapName            State       
--  ------------------ ---------- ------ ------------------ ------------
 0* NUC140VE3AN.cpu    cortex_m   little NUC140VE3AN.cpu    halted
>

A help paranccsal parancslistát lehet kérni, a help command-ra meg az adott parancs segítsége jön elő, bár gyanítom, hogy a rendes dokumentáció ennél többet nyújt. A parancsok között találni egy numicro nevűt is:

> help numicro
numicro
      numicro flash command group (command valid any time)
  numicro chip_erase
        chip erase through ISP.
  numicro read_isp address
        read flash through ISP.
  numicro write_isp address value
        write flash through ISP.
>

As'szem ezér' jöttünk! :) Egy kis teszt:

FLASH törlés (numicro chip_erase), majd „kézzel” a 0x100-as címre némi tesztérték beírása (numicro write_isp), visszaolvasás (numicro read_isp). Majd a „rendes” memóriatartalom visszaolvasása (mdw), úgy tűnik, hogy jó lesz ez! Az 0xE000ED00 címen a CPUID regiszter van, a visszaolvasott 0x410CC200 érték az ARM által implementált (!) Cortex-M0 magot jelöli. Az 0x50000000 címen levő 0x00014018 már a NuMicro saját azonosítója, a vicc az, hogy a dokumentációban (55. oldal) hibásan szerepel. Ha az egész doksi ennyire pontos, akkor valahogy nem sok jót jósolok... :\ Majd meglátjuk.

Az exit parancsra a telnet kapcsolat lezáródik, de az OpenOCD tovább futkározik a háttérben. Azt leállítani a shutdown paranccsal lehet. Ezek persze berakhatók a konfigurációs fájlba is, tehát lehet ezzel automatizálni a történéseket. Az alap flash parancsok működnek; komplett fájl beírása:

flash write_image erase fwfile.bin 0x100

Ez 0x100-tól kezdve „bepirítja” a FLASH-be a fwfile.bin fájlt, a cím a kívánt értékre behelyettesítendő! Az erase paraméter az írandó blokkot automatikusan törli. A fenti openocd.cfg fájl végéhez, a reset halt után a következőket berakva automatikussá tehető a folyamat:

targets
flash write_image erase fwfile.bin 0x100
shutdown

Az így megírt konfig fájl könyvtárában egy sima openocd parancsot kiadva megtörténik a fwfile.bin beírása a kívánt FLASH memóriacímtől, majd az OOCD befejezi a ténykedést. Sikerült a FLASH írása, jöhet a belevaló kód elkészítése! De ez egy másik történet lesz, mert ezt is túl hosszúra elnyújtottam. Mint magát az egész projektet...

Pár megjegyzés a végére azért idekívánkozik:

  1. Az OpenOCD kezd egyre inkább tetszeni, ez egy fantasztikus stuff! ;) A JTAG/SWD kábel esetén az FT2232 jó választásnak tűnik, de szinte bármilyen „szabvány” bekötés jó, be lehet konfigurálni! Nem kellett volna ragaszkodnom a Stellaris/Luminary ICDI-hez, mert „nagyjából” megfelelően bekonfigurált FT2232 esetén is viszonylag egyszerű az OpenOCD-t rávenni, hogy jól használja. Mondjuk hátrány nem ér vele, hogy annak hazudja magát, az is igaz...
  2. Maradva az interfésznél: az FT2232-ből többféle típus is létezik, én az FT2232D-t használtam. Ez egy Full-Speed sebességű eszköz, ehhez még reális házi körülmények között nyákot gyártani. Ezzel szemben az FT2232H már egy Hi-Speed-es IC, itt azért vannak nehézségek... A feladatra mindkét verzió jó lenne, de a H-s változat illesztését jól át kellene gondolni. A VCCio rész +3.3V-os, bár a kívánt lábak +5V-toleránsak a dokumentáció szerint. Ebből mindenképpen valami kész modult vennék, de mindkét típusnál igaz: jól meg kell nézni az árut, ami túl olcsó (100 db-os tételnél is 5$ / db. fölött van, ha ennél olcsóbb a kész modul, az minimum furcsa), az gyaníthatóan nem eredeti, hanem valamilyen klón. (Hogy aztán ez bármit is befolyásol-e, az jó kérdés.)
  3. Óriási köszönet a NuMicro támogatásért, mivel nagyon nem olyan egyszerű a történet, ahogyan az elején gondoltam. A forráskódba belenézve (openocd-0.10.0/src/flash/nor/numicro.c) „meglepődve” tapasztalható, hogy a FLASH kezeléséhez nincs szabványosított megoldás. A „pár azonosítót átírok” típusú téma felejtős... A megoldás itt az, hogy az OpenOCD az SWD interfészen keresztül letölt egy programot a µC RAM-jába, mellérakja a beégetendő adatokat, majd elindítja a letöltött programot, ami végrehajtja a tényleges FLASH-írást. Ez leginkább a bootloader-es programozáshoz hasonlít, csak itt a programozó algoritmus nem magában a FLASH-ban van, hanem a RAM-ba lesz előtte beletöltve. Ilyennel eddig még nem találkozhattam, leginkább azért, mert az eddig használt µC-ek mindegyike Harvard architektúrás. Itt a programot tartalmazó memória másik buszon van az adatokat tartalmazó RAM-tól, aminek a lényege ez esetben az, hogy nem tud a CPU a RAM-ból programot futtatni. Amúgy a többi eszköz forráskódjába belenézve ugyanez több helyen is látszik, tehát simán előfordulhat az a szituáció, hogy itt ez a megszokott programozási mód. Persze lehet, hogy az adott csipeket lehet programozni „közvetlenül” a debug interfészen keresztül is, csak nem ismert az algoritmus, az OOCD meg így kerüli meg ezt, de én inkább tippelnék az ez itt így megy változatra.
  4. A későbbiekben a Nu-Link akár még használható is lehet, csak ki kell benne cserélni a firmware-t. Mintha a CooCox is úgy használná, hogy saját fw-t kell bele tölteni az eredeti helyett? (Persze most erről nem találok semmit. 2011 meg elég régen volt.) Van rajta egy nyomógomb, ha azt nyomva kapcsolódik rá a gép USB portjára, akkor automatikusan bootloader üzemmódban indul el. (Ezt mintha nem említenék sehol sem a dokumentációk!) Ekkor a hozzá tartozó ISP letöltő szoftverrel programozható közvetlenül az USB porton keresztül. De van egy header a nyákján, ahol a NUC120 SWD portja elérhető, „megtámadható” onnan is. A kapcsolási rajza az megvan, egy NUC120RE3AN van benne egy W25Q16-os EEPROM-mal megtoldva. (16 megabit, gép nélküli programozáshoz ez tárolhatná a fw-t.) A µC az USB +5V-os tápjáról jár, az EEPROM ellenben 3.3V-os, ahhoz tartozik egy stabilizátor IC. De a jelszintek illesztéséről mintha nagyvonalúan megfelejtkeztek volna a készítők... :) Mindenesetre +5V-os az SWD rész, nem támogat +3.3V-os jelszinteket, emiatt az én változatom még jobb is!
  5. A fenti fejlesztői panelen található egy 20 pólusú Legacy JTAG/SWD csatlakozó, arra is csatlakozhattam volna, így elkerülhető lenne az elektronika átalakítása. Csakhogy – furcsa módon – ezen a csatlakozón nem a µC tápja van kivezetve, hanem egy 3.3V-os, külön stabilizátor IC-vel előállított feszültség, ami miatt a szintillesztés nem lenne megoldva. Ezt a külön tápot azóta se értem... :)
  6. A FLASH feltöltése megy, elvileg a konfigurációs „fuse” bitek is, de azt még fel kell fedezni! (A bootloader résznek van egy különálló 4K-s FLASH szegmense, annak az írását se nézegettem eddig.) Ahogy a dokumentációt elnézem, itt túl sok mindent nem kell állítgatni, a funkciók kapcsolgatása „runtime” történik majd. De azért van pár fontos bit (pl. honnan induljon a kód / milyen órajelről járjon az eszköz RESET után), de egy érdekes kérdés azért felmerült így hirtelen. Van egy LOCK nevű bit, ami az eszköz kiolvasását hivatott meggátolni. No de ez hogy működhet? Az, hogy „debug” parancsokkal az SWD-n keresztül nem lehet memóriát olvasni, az odáig oké. De ha tudok programot letölteni és indítani az SRAM-ban, akkor? Vagy ilyen esetben az SRAM-ban futó program se tudja a FLASH-t olvasni? Törölni ettől függetlenül még lehet? :) Csupa kérdések...

Viszont most itt befejezem, a tényleges mintaprojekt későbbre marad. Mondjuk kifogásom már nem lehet az, hogy „nincs mivel letölteni”... :-D (Legalábbis remélem.)

Linkek:

  1. A téma folytatása, toolchain illetve alap² (alap×alap, alap a négyzeten) tesztkódok
  2. A címhez némi magyarázat...
  3. FT2232 adatlapok, információk
  4. Stellaris/Luminary ICDI konfigurációs EEPROM tartalom az FT2232 mellé
  5. Stellaris Eval board, az integrált JTAG/SWD interfész volt a kiindulási alap
  6. LM3S9B90 Eval board, az OpenOCD luminary-icdi.cfg fájl hivatkozik rá, ebben CPLD nélküli a JTAG/SWD vonalmeghajtás, kompatibilis az előzővel
  7. FTDI EEPROM programozáshoz kiindulás, az ftdi_eeprom paraméterek használata mondjuk pont nem jó, de sebaj
  8. OpenNuvoton github oldal
  9. Nuvoton oldal Cortex-M0 mikrovezérlők
  10. Témába illő fórumszál „itthonról”

balagesz

---

2018.01.24.
2018.01.26. Idézőjelek, van pár... :)
2018.02.20. Folytatás link, + megjegyzés

Hozzászólás megjelenítési lehetőségek

A választott hozzászólás megjelenítési mód a „Beállítás” gombbal rögzíthető.

Nekem ez csak hobbim, szoval ha valamivel csak a szivas van (plane ennyi), sokkal hamarabb mar feladom. Ennyit nekem nem er az egesz.
Osszehasonlitaskepp vannak ebayen/alin $1.5-2 kozott ARM alapu boardok STM32F103C8T6 mikrokontrollerrel, viszonylag egyszeruen el tudsz jutni legalabb egy villogo LED-ig Arduino IDE-vel. Linuxon is. Ha az Arduino nem tetszik, akkor meg szinten $2 korul kapsz olyan egetot, ami tud STM8-at, STM32-t, mellesleg ugyanez a chip van benne (ezt meg nem probaltam).

FTDI-nak a "hamis/pinkompatibilis" chipek ota amugy is a nenikejet, azota nem rendelek olyan dolgot, amin nem CH340/341 (esetleg CP2102) van. Ha hamis, nem tudni meddig fog mukodni, ha eredeti, akkor meg egy olyan ceget tamogatnek vele, akiket nem akarok.

--
Any A.I. smart enough to pass a Turing test is smart enough to know to fail it. -Ian McDonald

Szerencsére nem szívásnak érzem a dolgot; annak talán csak akkor, ha határidős projekt lenne. Az az 1-2$-os STM32xxx érdekesnek tűnik, bár lehet hogy az is klón! ;) (Mintha említette volna valaki valamerre, hogy szorgos kínai munkások azt is másolják, de ez a működőképességükben nem látszik. Szóval nem fake áruról van szó, hanem klónozottról.)

Az FTDI meg szerintem egyszerűen "elkényelmesedett". Jó időben kezdték, csak azóta van bőven konkurencia. De adhatnák olcsóbban is a cuccaikat, az már igaz. (A CH/CP csipeknek van ilyen alternatív üzemmódjuk, ami itt most éppen jól jön? Eddig nem láttam erről infót.)

bookmarked

Mert ez jó. :)

-----
„Egy jó kapcsolatban a társunkat az ő dolgában kell támogatni, nem a miénkben.”
rand() a lelke mindennek! :)
Szerinted…

+1