STM8S -re írok egy egyszerű polling -os i2c handlert.
Több helyen szükség van arra, hogy kiolvassak egy-egy státusz regisztert, így lehet tovább lépni. A beolvasott értékkel nem érdekel, nem kell vele műveleteket végeznem, de ki kell olvasnom, különben nem lehet tovább lépni.
Az egyik forrásban pl. így oldotta meg a szerző "(void) I2C_SR3;" - no ezt a mostani SDCC simán ki optimalizálja, hiszen semmire nincs használva.
Egyelőre úgy "kerültem meg" hogy foglaltam egy fájl globál változót és abba "olvasom bele" a regiszter értékét. (Később, lehet még jó valamire, mondjuk hiba kezelésre, de most semmi szükségem rá, csak foglalja az értékes memóriát.)
Tudtok valami más megoldást?
OFF: A terv az, hogy majd interrupt -ba kerül az egész, valószínűleg assembly -ben. De itt inkább az elv lenne a lényeg.
Hozzászólások
vagy írsz inline assembly-t az utasítás helyére vagy ha van az SDCC-ben olyan #pragma amivel ki lehet kapcsolni az optimalizálást (nem ismerem ezt a compilert pontosan) akkor használod azt.
Az inline assembly -vel az lehet a gond, hogy milyen utasítást is, hogy ne zavarjon bele a regiszter használatba.
Sajnos én sem ismerem elégg az SDCC -t. Még azt sem tudnám megmondani, milyen optimalizáció eredménye is ez, vagy mit is kellene kikapcsolni.
* Én egy indián vagyok. Minden indián hazudik.
Az I2C_SR3-at volatile-kent kell deklaralni. Ha nem ugy van deklaralva akkor biztos kioptimalizalja fordito. Nem ismerem az STM8-as cimtartomanyait de pl AVR-bol kiindulva imigyen kellene, ha ott is igy hivnak ezt a 8 bites regisztert:
#define I2C_SR3 ( *(volatile uint8_t *)(0x23))
De egzaktul ugyanez a sema ARM+STM32 eseteben is, csak ott inkabb 32-bites I/O van (bar van ott is 16 meg 8 bites is, sok esetben a doksi nem is explicit irja hogy kell 8 bites access, de... na mindegy, az mar mas problemakor, de a volatile oda is kell).
Na ez a helyes válasz.
Alapvetően ebből a blogból indultam el: https://lujji.github.io/blog/bare-metal-programming-stm8/
Itt az i2c kezelésnél az utasítás így néz ki: "(void) I2C_SR3;"
Először én is ezt használtam, majd miután nem működött elkezdtem molyolni a listában és kiszúrtam hogy be sem fordul.
Alapvetően egy másik fickó stm8s.h fájlját használtam, nem a lujji félét, ahol volatile -nak vannak definiálva a regiszterek.
Na nézhetem át mindent amit eddig csináltam :(
TANULSÁG: Van még mit tanulnom.
* Én egy indián vagyok. Minden indián hazudik.
Nagyobb volt az ijedség mint a baj :)
Csak az interrupt címek nevét kellet módosítani (az én forrásomban).
Működik a volatile és (void).
Más kérdés, hogy így a compiler két utasítást is bevágott, egyszer tölti a az Y 16 bites "címző" regisztert, majd beolvassa a akksiba az ott talált értéket. Lehet ez gyorsabb mint implicite olvasni a regisztert ... megnéztem nem, ugyanúgy 4 ciklus.
(Borzasztó zavaró, hogy az STM és az SDCC jelölései kicsit eltérnek)
Köszönöm a tippet!
OFF: Több évtizede használok C nyelvet, de a "type qualifiers", ami const vagy volatile nem igen kellett. Legalább is nem emlékszem rá. (Sokkal gyakrabban jön elő, a "storage class specifier", lehet kevertem is a fogalmakat) Jó kis lavinát indított el ez nálam.
* Én egy indián vagyok. Minden indián hazudik.
Ez itten valoszinuleg optimalizacio-fuggo. Az avr-gcc is csinal olyat hogy egy *(volatile uint8_t *)(0x20) olvasast azt siman asm("in r24, 0x00;");-nak fordit mondjuk -O3-as optimalizacioval. De optimalizacio nelkul pedig ugyanigy asm("ldi r28, 0x20; ldi r29, 0x00; ld r24, Y");-nek. Ezeeobbi 1 oracilus, ezutobbi pedig 3 vagy 4 :) De hogy miert az rejtely...
Fontos megjegyezni, hogy az STM8x processzorok "extended" utasításkészlettel rendelkeznek, mig az AVR "reduced".
OFF: Az STM8x számomra a Z80 idézi sőt. (Én épp ezért szeretem.) Így nagyon elegáns kis assembly handlert írtam, az UART -ra. Sajnos korlátok vannak a változók átvételében az assembly és a C között.
Persze ez sem mindig elégséges. Pl. a "tiny-usb" ami egy ATtiny85 -ön (de lehet kisebb is) valósítja meg az USB HID kommunikációt, az úgy tűnik nem tud működni az STM8x pont az utasítás készlete miatt. Semmi sem tökéletes.
* Én egy indián vagyok. Minden indián hazudik.
Fontos megjegyezni, hogy az STM8x processzorok "extended" utasításkészlettel rendelkeznek, mig az AVR "reduced".
Igen, nem ismerem ezt az MCU-t, de valoban ilyen CISC-light jellegunek tunik az utasitaskeszlet ;)
Sajnos korlátok vannak a változók átvételében az assembly és a C között.
Mgen... a gcc inline assembly-je elegge agyfaszosnak nez ki elsore, de valojaban pont ez az elonye hogy a valtozo-atadasok meg az ilyesmik egysegesen legyenek kezelve. Lehet hogy az SDCC ezt nem csinalja annyira jol es/vagy hatekonyan...
Pl. a "tiny-usb" ami egy ATtiny85 -ön (de lehet kisebb is) valósítja meg az USB HID kommunikációt, az úgy tűnik nem tud működni az STM8x pont az utasítás készlete miatt
Ez inkabb azert van/lehet mert a CISC-light jellegu instruction pipeline miatt sokkal nehezebben becsulheto hogy egy-egy utasitas hany oraciklusig fut le (noplane foleg ha memory wait cycle-k is kerulnek bele, amik az AVR-nel gyakorlatilag nem leteznek, ott nincsenek I/O wait cycle-k). Es ez a tiny-usb stack az nagyon-nagyon arra van kihegyezve hogy iszonyatosan pontosan tudjuk hogy melyik utasitas mennyi ido alatt fut le :)
Csak most akadtam bele véletlenül:
https://github.com/unfrozen
Nagyon letisztult, megbízható kódnak tűnik számomra. A másik, hogy a kódban nagyon jól látszik, hogy kell az SDCC -ben inline assembly -t írni. Mindenkinek javaslom, aki STM8 -al akar dolgozni.
* Én egy indián vagyok. Minden indián hazudik.
Hat, nekem inkabb ez pure assembly-nek tunik elsore... szoval pl az ABI-t is ismerned kell ahhoz hogy hatekonyan es/vagy jol felhasznald.
Megfogtál :( Mi az az "ABI"?
Rengeteg inline assembly. Tetszik milyen szabadon vált és hatékonyan használja. Én is írtam assembly modulokat, pl. az UART handlerem végül teljesen assembly lett, még a ciklikus buffer is (egy egy eljárás 2X sorban elférnek).
* Én egy indián vagyok. Minden indián hazudik.
Tobbekkozott peldaul az hogy egy fuggvenyhivaskor hogyan passzolja at az argumentumokat a hivo a hivott felnek. Regiszterben? Stack-en? Ha regiszter(ek)ben akkor mit csinal amikor tul sok a parametere egy adott fuggvenynek? Es mi a helyzet a return value-val? Lasd meg: https://en.wikipedia.org/wiki/Application_binary_interface, ezen belul is az EABI szekcio erdekes most.
Kösz! Így már értem, bár a részletekbe most még nem ásnám magam bele.
Én úgy tudom az SDCC mindent stackbe pakol és az X regiszterben (16 bit) várja a visszatérési értéket.
(Lehet valami pragma -val ez módosítható.)
Nem túl szerencsés abból a szempontból, hogy a legkisebb STM8S verziókban mindössze 1K bájt RAM van, így a stack csúnyán elszállhat (az interrupt eleve mindent ment). De mint régi motoros, amúgy is ha két változónál több van inkább pointer és struktúra.
OFF: Sajnálom hogy pont a memória ilyen szűkös, régen Z80 -al csináltunk egy nagyon primitív multi task ot, de itt egy taszkhoz min. 16bájt kellene, ráadásul nehezen kontrollálható a stack használat.
* Én egy indián vagyok. Minden indián hazudik.
Ami meg mukodhet az egy ures while tehat while(status); vagy while(!status);, hogy ha lehet tudni, hogy biztosan lesz neki nulla vagy nem nulla erteke. Nyilvan kod memoriat ez is hasznal.
Igen, noha ez is kapcsolodik a feladatkorhoz de a kolleganak itten nem erre van szuksege. Inkabb csak egy interrupt flag acknowledgement-re, amit mikrokontrollertol fuggoen persze de eleg sok esetben egy sima input (regiszter ertek beolvasasa) is ki tud valtani.
Meg ez a while ( ... ) konstrukcio is tud csunyasagokat csinalni hogyha a status kifejteseben nem volatile-kent van deklaralva az adott I/O regiszter ;)