Fórum témák
» Több friss téma |
Nem. Ha jól emlékszem FreeRTOS-nál egy alacsonyabb prioritású task sohasem fog procidőt kapni, amíg egy magasabb prioritású task futni akar. Ez logikus is, hisz a működés szempontjából fontos vezérlés ugyan ne várakozzon már arra, hogy egy másik task épp vmi vonalat rajzol a képernyőre. Ezért is RTOS, itt garantálhatod ha jól írod meg a programod, hogy a fontos task-ok azonnal CPU időhöz jutnak, amikor szükséges. A C# kód nagy teljesítményű számítógépeken fut, amelyeken valódi multitaszkos operációs rendszerek futnak. A programok futtatásakor itt teljesen más igényei vannak a felhasználóknak. Mivel itt a rendszer terheltségétől függ, mikor is lesz feldogozva egy esemény, itt simán elkéshet a jel feldolgozása, ezért is nem alkalmas bizonyos feladatokra egy ilyen rendszer.
Igen így logikus, csak pont az kellet volna, hogy prioritás függetlenül a "feliratkozás" sorrendjében kapjanak proci időt.
Amúgy cél az lenne, hogy több objektumot egy mutex-el lehessen lockolni de mikor több task próbál egy objektumhoz hozzáférni akkor blokkoljon mikor egy task hozzáfér a objektumhoz és "a" végrehajtást megkapja (a mutex még lockolva) egy másik szál ami mondjuk "b" objektumhoz akar hozzá férni akkor neki ne kelljen várnia a közös mutexre. Persze erre az egyszerű válasz a 2 db mutex csak sok objektum lesz és költségesnek tartom hogy minden objektumnak legyen saját mutexe. Alapvetően egy locked listre gondoltam, ha az objektum nincs benne akkor végrehajtható a property módosítás, ha benne van egy semaphore vár amit x művelet után release-el a módosító.
Igen, értem, de nagyon vigyázz ezekkel a lockokkal, mert nagyon könnyen körbe zárod magad és megáll a program.
Én igyekszem úgy megírni a programot, hogy egy adott perifériát legfeljebb egy task kezel. Pl. egy soros kimenetet, ha több tasknak is írnia kell, akkor van egy dedikált kis task, ami írhatja és egy queue-ból veszi ki a soron következő üzenetet, amikor elment az üzenet (DMA vége) a task megint felébred felszabadítja az üzetnethez tartozó memóriát és küldi a következő üzenetet, ha nincs olyan, akkor pedig alszik, amíg új üzenet nem kerül a sorba. Ilyenkor tetszés szerinti task pakolhat üzeneteket a sorba és nincs várakozás. Egy másik szituáció egy kritikus task és mondjuk egy felhasználói adatbevitelért felelős task közötti adatcsere. Ilyenkor szoktam egy "belső" másolatot készíteni az adatokról, amelyet a kritikus task használ. Ha az erőforrás szabad, akkor a kritikus task frissíti a saját belső adatait, illetve kiírja az új infókat a külsőbe, ha nem akkor simán lepattan róla és majd legközelebb frissíti, de nem vár a felszabadulására és tovább dolgozik a korábbi másolattal. Az alacsonyabb prioritású task viszont mindig lock-olja az adatokat és vár is erre, hisz itt nem baj ha picit megáll a kód.
Jelen helyzetben nem ez a cél. (legalábbis szerintem)
GUI-t írogatok magamnak egy pár meglévő implementáció alapján meg C# winforms-ból (szerintem rengetek jó ötlet van ott C++-hoz, csak tudni kell mit szabad és mit nem). (Control=grafikus objektum pl gomb) Ugye C#-ban alapból nincs locking csak InvokeRequired, de ott adott thread-ben zajlik a Form kezelése és ott többnyire ez a thread piszkálja az objektum propetyket. Ezzel szemben az MCU-n lesz egy render task és kicsit csúnyának tartom, hogy rajzolás alatt le van lockolva minden Control főleg úgy, hogy a render lowerst prioirty (persze ez lenne a legkényelmesebb, csak pazarló) a másolással a probléma, hogy a Control dinamikus string-et használ azt költséges másolni. Most két opció jutott eszembe 1. az előbb írt csnyát szűkítem és csak egy Control renderelése idejéig lockolock ha közben futó álapotba került task unlocknál átadja annak a vezérlést és hozzáférhet bármely Control-hoz 2. A legelső gondolatot megoldani, miszerint olyan sorrendben kapnak értesítést a Controlok amilyen sorrendbe be kerültek egy listába Itt arra gondoltam (itt még lesz benne nem szálbiztos rész, de hosszú lenne mindent kivesézni) hogy a Lockra a megnézzük, hogy a Control benne van e egy listában, ha nincs szabad az út, ha benne van várni fog egy semaphoret (legyen semFirst). Ha megkapja a semaphore-t akkor megnézni, hogy a Control locked e még, ha igen releaseel (semFirst) és vár másik semaphoret (legyen semSecond) ekkor egy alacsonyabb prioritású task is megkapja az erőforrást megnézi, hogy locked-e azt látja nem akkor végrehajta azt a módosítást amit kell majd az unlock szekvenciánál megnézi, hogy üres-e a lista, ha nem egy releaseeli semFirstöt és semSecondot is. Jó ez lehet kicsit komplex így az elképzelés (igaz C++, meg lista még sehol, de képzeld oda )
Első gondolatra nekem nem tűnik problémásnak dead-lock szempontjából, Szerinted? A másik van egyáltalán értelme ennyit tökölni vele, mert a grafika miatt nem 40 MHz a "célközönség"? (és nem az a cél, hogy a render alatt jobb legyen a lock, hanem ha adott Control edit közben szakad meg ne kelljen, majd egy más task is hozzáférne nem ugyanehhez akkor ne várjon a másikra)
Ne bonyolítsd túl, hogy controlonként lock-olsz. Kezeld a GUI-t egyetlen erőforrásként. Ha épp frissítés zajlik, akkor a GUI lockolja a saját mutex-ét, amíg nem végez a teljes frissítéssel, egyébként szabad a pálya. Beállíthatsz egy rövid alvási periódust a GUI saját taskja végére, ami a frissítési periódusért felel. Ha egy harmadik taskot is beállítasz, ami a képernyőre kiírásért felel, akkor még jobban felgyorsíthatod a működést (pl. a GUI task megrajzolja egy dinamikus minibufferbe a képernyőelemet, majd beteszi egy sorba [ha van hely, egyébként vár], majd nekilát a következő elem megrajzolásának). Ilyenkor a képernyő írása szinte folyamatos lehet, így még egy lassabb interfészű kijelző is meglepően gyors lehet (itt is ezt csináltam: https://youtu.be/ips9zyRMvF0)
Én nem használnék feleslegesen listát a frissítendő objektumokról. Sokkal olcsóbb ha minden controlnak van egy status szava, amiben előre definiált bit-ek vannak (pl. VISIBLE, ENABLED, UPDATED, stb.), ahol az updated alapján tudod, hogy újra kell rajzolnod egy elemet (illetve a gyerek objektumait ha vannak). Ha egy képernyő láncolt pointer listaként van felépítve (frame->first child(button)->next child), ahol egységes header-t használsz, ami azonosítja az objektum típusát, hogy tudjad cast-olni, akkor nagyon könnyen végigfuthatsz rajta, hogy mit frissíts és milyen sorrendben. Sőt, így a felhasználói bemeneteket is sokkal könnyebben tudod lekezelni (pl. érintőképernyő vagy ugrabugra gombokkal a kezelőelemek között).
Kicsit előre haladtál a végén, amúgy ezzel kezdtem, hogy lássak valamit a kijelzőn.
Alapvetően a minibuffer "nem" lesz hanem nagy buffer lesz, mivel nem cél a kis controller, így DRAM/SDRAM lesz a VRAM, adott esetben lesz SRAM cache, ami mégis csak gyorsabb. (mondjuk ping-pong ba SRAM felölt DMA->SDRAM közben mehet a második rész) A statusok még nincsenek megírva természetesen lesznek, a GUI task-ja vagy Queue-ban (C# implementációból jön) vár event üzeneteket, vagy elengedem a Windows message pump-ot és egy semaphore-al lesz jelezve, ha touch (/bármi input) történt vagy egy Control invalidált, majd végig pörgeti a listát kit kell rajzolni. A header részt "már" kitaláltam, itt mivel hardware van heterogén kollekció lesz a Control az ős osztály is minden renderhez kellő információt definitté tesz, az egyéb property-ket meg az adott leszármazottban megírom. Az egész előző elgondolás azért jött, mert ha egy Control lockolva van render alatt másik tizen x Control ne legyen már. A következő implementációt találtam ki, amíg a szál lockolja a Controlt addig átmegy a legalacsonabb prioritásba, innentől kezdve értelmet kap a Yield és a belockolt Controlok egymás között dobálják a hozzáférést (természetesen ha nem jön ben nagyobb prioritású task) A kód: Ja egyébként rátalátam, hogy amit akarok csinálni az a Monitor innen az elenezés
A fő kérdés ami miatt megosztottam, hogy nyerek-e én ezzel bármit is, vagy ha nyerek azt is ritkán, nem tudom mi a költségesebb az egy mutex-ből adodó várakozás vagy adott thread prioritásának piszkálása.
A mutex elég olcsó, a thread prioritás piszkálása szerintem már problematikusabb. A mutexnél ha az nem szabad és meg akarod várni, egyszerűen csak bealtatja a taskot a mutexre mutató pointerrel, hogy tudja a scheduler miért is várakozik. Amikor a mutex felszabadul, akkor felébreszti a taskot.
A prioritás probléma miatt, kitaláltam végre a jó megoldást, prioritáshoz rendelt semaphore-ok vannak, mivel én 7 db prioritást teszek definitté a lib-ben így belefér, így ugyanaz kb mint az előbb annyi különbséggel, hogy nincs prioritás állítva, ha adott prioritáson, több Control várakozik (és nincs más task ready-ben) akkor a Yield a következő azon a prioritáson várakozó Controlnak adja a vezérlést.
(persze ha már RTOS figyeltem rá, hogy a magasabb prioritás kapja először ) Most itt jöhet persze a kérdés, hogy van-e értelme spórolni, mert mennyi objektum lehet egyszerre a kijelzőn, attól függ, végül jó megoldás ide nincs, az egyik ekkor a másik akkor jobb (egyik - én módszer, másik - egyedi/közös mutex mindenkinek)
Sziasztok!
Egy kis segítségre lenne szükségem. Szeretnék a belső flash memóriába adatot elmenteni. Erre a program első futásakor kerülne sor, majd később ezt az adatot dolgozná fel a program a többi futás során. IDE: Keil, mikrokontroller: STM32F746NG. Mivel tömbösített adatokról van szó, ezért úgy gondolom, hogy a legjobb lenne, ha erre a célra egy külön memóriaterületet tudnék meghatározni. Sajnos a linker beállításaival nincs tapasztalatom, de utánaolvasás után azt találtam, hogy egy scatter fájlt kell létrehozni és abban definiálni külön memóriaterület. Olvasva a scatter dokumentációját nem igazán jöttem rá, hogy kellene használni. Van esetleg valakinek működő példája vagy leírása erre vonatkozóan? ui. A "Use Memory Layout from Target Dialog" beállítással az Options for Target ablakban elérhetővé válnak a memóriaterületek beállításai (IROM1 és IROM2). Ezt esetleg lehetne használni erre a célra? A válaszokat előre is köszönöm!
Vannak erre kész példák keres rá: stm32f7 eeprom emulation
Sziasztok. Elkezdtem használni próbaképpen Keil mellett a Visual Studio Code-ot. Telepítettem a gnu-debugger és a Keil Assistant bővítéseket, és működik is minden, de van egy gond. Debug futás közben a változók értékei nem látszanak, not available van kiírva. Csak akkor jelennek meg, ha megáll a futás töréspont miatt, vagy én manuálisan megállítom. A 'live view' funkciót minden valamirevaló debugger ismeri. Én rontok el valamit, vagy a gnu-debugger tényleg nem tudja ezt?
Ez neked Keil alatt ment? Én nem használom, de elég furcsa, ebben a világban még ezzel a tudással nem találkoztam. Én mindig akkor láttam változókat, ha állt a program.
Számora ez egy elég fontos szolgáltatás.
A Cortex debug rendszer ismeri. Támogatja az ST-Link GDB szerver és az OpenOCD is. A CubeIDE és a VisualGDB is támogatja, ahogyan a CubeMonitor is. Ráadásul kétirányú. Az MCU memóriája írható is futásidőben breakpoint és stop nélkül is. A CubeMonitorban komplett GUI rakható össze, írható és olvasható módon, anélkül, hogy kommunikációs protokollra lenne szükség. Meg kell adni az MCU-n futó programban használt változóneveket (kiszedi a címüket az elf-ből) és direktben írja/olvassa őket.
A VS Code nem igazán, controllerhez lett kitalálva a Real time watch-nak software-s világban nem feltétlen van értelme, mert ott ha megállítod a kódot a legtöbb esetben semmi gondot nem okoz.
Így szerintem amíg ehhez nem készül valami plug-in addig nem is fogja támogatni. VS-sem támogatja alapból ezt ez a VS GDB megoldása ott írtak hozzá külön funkciót, amivel kihasználható az OpenOCD funkciója. Amúgy VS GDB-nél ha local variable van akkor ott egyszer meg kell állítani a debug-ot, hogy meg legyen a címe a változónak. Én inkább annak szoktam hasznát venni, ha nincs elég UART meg amúgy is főleg csak debug-nál kell akkor az ITM-et szoktam használni üzenetküldésre amiből simán tudom követni milyen esemény történik.
Igen, megy. Nuvoton M0 és M4 CPU (gondolom mással is működik, csak én ezt használom), JLink és NuLink debuggerrel. Egyébként rosszat írtam, mert a cortex-debugger az ami működik VS Code alatt, a gnu-debugger nálam nem indult el, de lehet hogy csak nem voltam elég kitartó. Mindegy, marad a Keil
A hozzászólás módosítva: Nov 26, 2020
Igazán köszönöm, hogy ezt így leírtad, ez még jól jöhet. Én igazából az Eclipse-t használom, ezekszerint ott megy, GDB-vel vagy OpenOCD-vel, majd kipróbálom.
Üdvözlet!
Nagyon kezdőként kérdeznék gd32f130t6-os okkal kapcsolatban. A gondom az, hogy elkezdtem ezekkel foglalkozni, st-link-kel programozni csak 5900 byte-ig tudom, utána jött egy CoFlash, ezzel már tele is tudom írni. Elkezdtem rá fejlesztgetni, kicsontoztam pár példaprogramot, hogy nagyon alapról indulhassak. Eddig kisebb (2k) és nagyobb (24K) leszedett progikat töltöttem fel, sokat, sokszor. Most az egyik programnál azt csinálja, hogy feltölti és utána semmilyen módon nem kommunikál többet a programozóval (connection error, erase fail, mindenféle hibaüzenet, de olvasni sem tud semmit, már kapcsolódni sem). A boot0 GND-re húzva, minden tápláb bekötve, 100n-es kondik rögtön a chip mellett. Többször áramtalanítottam, újra feldugtam, reseteltem, semmi. Kis méretű progikkal működik, többször, jól, de ahogy ezt a hosszabbat ráteszem, kimúlik véglegesen. Van ötlet, hogy mit csinálok rosszul? Létezik ilyen program, ami úgy elrontja, hogy többet nem látja semmi? Az ST-LINK és a CoFlash-on túl milyen st-linkes programozó létezik még? (mindkettő meglehetősen szikár) Előre is köszönöm.
Na, mire elhatároztam, hogy segítséget kérek, meg is oldódott.
Connect under reset volt a megoldás és a reset lábat tényleg le kellett húzni, amíg csatlakozik. Eddig a hot plug/normal és software reset mellett programoztam.
Az oka pedig az, hogy a legutóbb feltöltött program nem kapcsolta be a debug (SWD) interfészt.
Köszönöm a választ.
Van-e esetleg valahol egy jó összefoglaló kezdőknek? (PIC, assembly előtanulmány, tapasztalat van)
Újabb kérdés:
Van egy kis egyszerű példaprogramom. Definiálok pár pint, egyik pull-upos input, a többi a LED-eket vezérli. A main csak annyi, hogy vár a lefutó input jelre és ekkor kigyújtja a ledet. Amíg nyomom a gombot, addig jó, de ha elengedem, akkor pár tized másodpercen belül elalszik. Ha csak simán, a végtelen cikluson kívül kapcsolom be, akkor folyamatosan világít.
Köszönöm válaszod: kipróbáltam, igen, újraindul.
Mit tudok és hol beállítani? Kezdő vagyok nagyon, a c-hez is...
Ennek nem sok köze van a C-hez. Ha a watchdog miatt indul újra, akkor a ciklusba kell egy watchdog reset utasítás. Viszont én nem programozok ilyen CPU-t, ezért nem tudom hogy pontosan hogy kell nálad leírni. Pic-nél ha jól emlékszem clrwdt, Nuvoton ARM-nál WDT_RESET_COUNTER() stb. Valami hasonlót kéne keresni a példaprogramokban.
Idézet: „Amíg nyomom a gombot, addig jó, de ha elengedem, akkor pár tized másodpercen belül elalszik.” Ez nem utal watchdogra. Főleg úgy nem, hogy a kérdező kódjában nem is szerepel watchdog indítás.
Szerintem ez CPU újraindulásra utal, a watchdog csak egy tipp volt. Mondjuk a kódban tényleg nincs semmi watchdog related code.
Újraindul, ez biztos. Csak nem tudom, miért.
Van egy csomó egyéb header meg c forrás is hozzá, de feltételeztem, hogy azok jók. Itt hol vannak pl. a config bitek beállításai? Előre be kell írni őket vagy a programból állíthatóak? Ez utóbbi esetben mi a default indítási környezet?
Van egy ilyen mondat a chip adatlapjában a watchdog résznél: "Hardware free watchdog timer bit, automatically start the FWDGT at power on."
Ez alapján ki kell kapcsolni a main legelején a watchdog-ot, ha nem akarod használni.
Én kerülném ezt az MCU-t, és azt használnám, amiről másolták a logikai felépítését: STM32 Sokkal jobbak a fejlesztőeszközök, sokkal több és jobb a dokumentáció, nagyobb az online közösség. Valamint sokkal többféle variáns is van belőle.
Az általam ismert mikrokontrollereken NEM lehetséges bekapcsolás után kikapcsolni a watchdogot. Pont az értelmét venné el, ha ki lehetne kapcsolni.
|
Bejelentkezés
Hirdetés |