OpenOCD: 0.11 => 0.12: flash image write error

Sziasztok!

OpenOCD 0.11 => 0.12 upgrade soran tapasztaltuk hogy a sima mezei "ST-Link-en keresztul frissitsunk STM32F3xx-es MCU-kon flash image"-t folyamat egy 

Error: error writing to flash at address 0x08000000 at offset 0x00000000

jellegu, egyebkent minden elozmeny nelkuli hibauzenettel leall. Sima `flash write_image erase ...` jellegu parancs, ugyanaz amit evek (~evtizedek?) ota hasznalok es eddig mindenhogy ment, ST-Linken, FTDI MPSSE-n, arkon-bokron, ahogy kell. Halistennek nem teglasitja a cuccot, visszaterve 0.10/0.11-es openocd-re ugyanugy jol megy minden.

Tapasztalt valaki hasonlokat? Eleg uj ez az `openocd` (ha jol latom ~januarban jott ki), siman lehet hogy megjavitottak ami mukodik :/

A teljes szekvencia egyebkent ez: 

openocd -f interface/stlink-v2-1.cfg \
        -c "transport select hla_swd" \
        -f target/stm32f3x.cfg \
        -c "adapter_khz 100" \
        -c "reset_config srst_only srst_nogate" \
        -c init \
        -c "reset halt" \
        -c "flash write_image unlock erase main.hex 0 ihex" \
        -c reset \
        -c exit

Azaz lehet hogy mar itt valami "nem az igazi", csak eddig veletlenul mukodott 0.10/0.11 alatt :/

A.

Hozzászólások

Kicsit reszelgettem még ezt - pl hogy kulon parancs törli ill. irja a flash-t, ketto kozott opcionalisan sleep, de ez sem segit...  :/ 

Szerkesztve: 2023. 07. 01., szo – 15:43

off

Ezeknek az eszközöknek van gyakorlati hasznuk? Sohasem használtam még hardware debuggert. Első dolgom, hogy legyen valami soros portra logolásom. Kis PIC-re erre CLC modulból egy bites soros transmittert csináltam, a többi megy software-esen. Utána meg logolok, ha valami nem működik, aztán a homlokomra csapok, hogy hogyan lehettem ekkora ökör. :)

Értelemszerűen nem tudom a kérdésedre a választ, ha tudnám, írnám. Persze tippjeim vannak, mivel PIC32-re írtam már bootloadert.

Van valahol a bootloader. Az Intel hex file-ban meg az, hogy milyen címre mit kell írni. Ha a bootloader reserved címére akar írni, akkor könnyen lehet, hogy ez hibaüzenetben végződik, nem lesz öngyilkos a bootloader, s így nem téglásodik.

Ami nehéz ezekben a dolgokban, az az, hogy reset vektorból a valós hardware-en csak egy van, míg itt nyilván a bootloader indul, de akkor mi van azzal a kóddal, amit letölt? A megoldás, hogy a linker file-t kell átírni megfelelő módon. Illetve reset után fut egy olyan kódrész, ami inicializálja a globális és static változókat, minimálisan a hardware-t - órajel, eseteleg watchdog, memória elérés, effélék. Szokott lenni néha egy early initre kiugrási lehetőség, amelyet assembly-ben kell megírni, ha van erre igényed. Ezeket a fordító és a linker dokumentációjában találod meg, ezekre nincs szabványos megoldás. Processzorfüggő. Arról nem is beszélve, hogy vajon a flash-elt kódnak hol van az entry point-ja? Mert a reset vektor nyilván nem lehet.

Csak ezek után jön a main(), amiről a felületes szemlélő gondolhatná, hogy ott kezdődik a programja, de addig egy rakás dolog lefutott már. Viszont, ha van bootloader, ez a „láthatatlan” rész ütközhet a bootloaderrel.

Van egy másik izgalmas kérdés, az pedig az IT vektorok. Fut a bootloader, van pl. USB kezelése, benne IT, DMA, akármi, logolsz soros porton, tehát van EUSART IT, átadod a vezérlést arra a programra, amit letöltöttél, aztán... ó, jaj, még a bootloader IT-je kerül végrehajtásra az új programban? Tehát detach USB, IT tiltások vezérlés átadása, nagyon fontos, hogy itt inicializálódik a verem, a stack pointer új értéket kap, ezzel minden elvész a veremből, visszatérési címek is, majd IT-k engedélyezése, USB attach, meg ami még kell, aztán hadd szóljon, előbb-utóbb jön a flash-elt kód main()-je. :)

Gondolom, te ezt tudod, inkább az erre tévedő olvasóknak szólt. :)

tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Ezeknek az eszközöknek van gyakorlati hasznuk?

Hogyne, ezzel megy fel a firmware es/vagy a sajat bootloader :) Enelkul nehez. Persze nem mondom hogy lehetetlen akkor hogyha az adott MCU-nak van sajat bootloadere egy ROM-ban - de akkor egyreszt ahhoz kell alkalmazkodni; masreszt meg mas a hardver felepitese mint az eles alkalmazaskor (ld: boot mode select bits); harmadreszt meg az SWD meg ehhez hasonlo dolgok ipari sztenderdek amik minden magnal ugyanugy viselkednek, fuggetlenul attol hogy ki a gyarto; negyedreszt meg a soft core rendszerek is teljesen hasonloan mukodnek (mert ott nincs kedvunk altalaban meg plusz egy bootloadert irni, egy boot ROM bus matrix komponens mar onmagaban pont eleg szivas).

De valo igaz, hogy pl en is relative ritkan hasznalom ezeket a cuccmanyokat konkret debug jellegu debuggolashoz. Bar persze lehetnek erdekes megkozelitesek. Pl csinaltam mar olyat hogy ugyanigy, SWD felhasznalasaval, OpenOCD-n keresztul ertem el a periferia-cimtartomanyt ugy hogy a fejlesztogepen (mezei linuxos laptopon) levo progi szinte 1:1-ben megegyezett a mikrokontrolleres celprogrammal, csak az MMIO request-ek voltak atforditva OpenOCD parancsokra valos idoben. Vagy Cortex-M0 szimulatorban az LDR/STR assembly utasitasok a periferia-cimtartomany (0x40000000+ ...) elerese eseteben egy, nekik megfelelo mdw/mww parancsra "futnak ki"  amit kikuld a localhost:4444-es porton figyelo OpenOCD-nek mezei socket-en. Szoval jo ez azert sokmindenre :)

Arra is jó az openocd, hogy firmware-t tölts fel vagy épp szedj le egy eszközről. Mondjuk JTAG-en keresztül. Vannak esetek amikor más megoldás nem jöhet szóba, csak a JTAG. Ebben is kiváló társ lehet az openocd. Van egy hobby projektem, ahol a CPU belső rom-jából kell a loadert kinyerni, itt elvileg csak a JTAG és szoftverben az openocd vagy talán az urjtag jöhet szóba. Azért ez a sok feltételes mód, mert az egész nem ennyire egyszerű, ugyanis az eszközön a JTAG tiltva van, úgyhogy most azon fogok dolgozni, hogy szoftveresen engedélyezzem.. Van erre megoldás, de hogy működik e, az egy nagyon jó kérdés...

Ezeknek az eszközöknek van gyakorlati hasznuk? Sohasem használtam még hardware debuggert.

Csak az en velemenyem, de szerintem sajnalatos, ha ennyi ev tapasztalattal ez a kerdes komoly es utana kovetkezo allitas is.

Jo dolog a soros portra irogatas, de kozel sem alkalmas mindenre. Szerintem pl. sokszor elofordul, hogy egy interruptban meg az is sok, hogy (mondjuk 115200-zal) kiirsz par karaktert - ennel a sebessegnel az majdnem 1 milliszekundum.

Masreszt, egy hard faultot (mondjuk null pointer dereference ami konnyen elo tud jonni, de barmilyen nem letezo cimre valo iras vagy onnan olvasas is triggereli) szerintem nem fogsz meg printekkel.

/sza2

Digital? Every idiot can count to one - Bob Widlar

IT-ből nem printelek, olyankor FIFO-ba írok, amit alapszintről logolok ki, de törekszem jól érthető, átlátható kódot írni, így a kód puszta szemmelverésével is meg szoktam találni a bugot. Az egyik legsúlyosabb bugom, amit nagyon szégyellek, valami ilyesmi volt:

uint8_t *crc;

if (condition) *crc++;

A helyes megoldás ez lett természetesen:

if (condition) ++*crc;

Vagy lehetett volna ez is:

if (condition) (*crc)++;

Nyilván azért követtem el, mert gyakran használt alak, amikor a pointer által mutatott címre írunk, vagy onnan olvasunk, majd a pointert postincrementáljuk. Most viszont nem a pointert kellett leléptetnem az eredeti címről, hanem a dereferált értéket kellett növelnem.

tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE