Atmel ATmega328 (a další z rodiny) a atomické čtení

Wasper

  • ***
  • 120
    • Zobrazit profil
    • E-mail
Zdravím, rád bych se zeptal - je na Arduinu nějaká lepší možnost než zákaz interruptů, jak atomicky přečíst int16_t popř int32_t?
Konkrétní příklad
Kód: [Vybrat]
volatile int msec;

/* interrupt rutina */
msec++; if (msec > 999) msec = 0;

/* main loop */
while (1) {
    ledka(OFF);
    while (msec < 900) ;      // <---- nekonzistence
    ledka(ON);
    while (msec >= 900) ;
    Serial.printf("je cas %i\n", msec);
}
Tenhle fragment zobrazuje casy 0 0 0 768 0 0 0 768 0 768 0.
Důvod je nasnadě, prvně se načítá low byte, pak high, a když se doprostřed trefí interrupt, který (už načtený) lo změní z 255 na 0, ale ještě nenačtený high naincrementuje z 2 na 3, tak v podmínce se porovnává 1023 < 900 a projde to dál.
OK, ale co s tím? jedna možnost je samozřejmě to obalit nějakým
Kód: [Vybrat]
int my_msec;
cli();
my_msec = msec;
sei();
To samozřejmě fungovat bude, jen se mi to moc nelíbí, reálně chci používat interrupty v množství nemalém (na druhou stranu ty 2 takty navíc asi moc nebolí), ale přecejen, není nějaké čistší řešení? Konkrétně u timeru by se to ošklivě dalo řešit tak, že si ten low byte přečtu znova a porovnám, u složitějších věcí nějakým bytem navíc, kde se nastaví dirty apod.
Ale kam směřuju otázkou - neexistuje něco snadnějšího? Koukal jsem na instrukční set a nic použitelného jako load dvou registrů neobjevil, ale je možné, že jsem slepej/blbej/oboje ;-)

P.S. To výše je jenom nejjednodušší příklad na osvětlení. Že do toho while je dobré dát __asm__ __volatile__ ("sleep") vím, a že to problém omezí, ale úplně nevyřeší (když přiletí interrupt od seriáku a hned pak od timeru, tak se taky může trefit nedobře) vím taky. A že volatile v interruptu se má načíst do lokální proměnné a pak zase po inkrementaci zapsat zpět taky...


RDa

  • *****
  • 2 672
    • Zobrazit profil
    • E-mail
Re:Atmel ATmega328 (a další z rodiny) a atomické čtení
« Odpověď #1 kdy: 24. 11. 2022, 18:04:58 »
V konkretnim pripade bych to resil tak, ze se porovnani provede v ramci preruseni a nastavi event flag led_turn_off pripadne led_turn_on, a mainloop ti ty eventy provede a flagy smaze. Samozrejme tim ti vznikne urcity jitter - na spinani ledky to neva, ale jsou veci kde by to vadilo. To pak musis i tu akci vlozit do interrupt handleru.. ale chapu ze to ne vzdy jde (treba ledka na i2c expanderu), pripadne vypisy.

Ja na XMEGA resil podobnou obskurnost, kde byl soubeh preruseni a potreba atomickeho cteni 5B (dva 16bit kaskadovane pocitadla a jeste bajt ze sw pocitadla), s tim ze se externi hodiny do pocitadla nesmi zastavit. Nakonec to dopadlo tak, ze sampluji 2x a hlidam monotonnost, pokud je tam vada, tak znova. Tj v bodu preteceni (na kterekoliv urovni kaskady) vznika jitter (nelze nikdy ziskat otisk ktery by byl na hrane).

Re:Atmel ATmega328 (a další z rodiny) a atomické čtení
« Odpověď #2 kdy: 24. 11. 2022, 22:55:10 »
Jen u té vaší metody cli() sei() musíte mít jistotu, že v danou chvíli je přerušení povolené a pak ho na konci tedy správně opět povolíte
U komplexnějšího programu se může stát, že to atomické čtení použijete ve chvíli, kdy je přerušení zakázané odjinud a vy ho tím atomickým čtením nesprávně povolíte.
Proto má avr-libc knihovnu util/atomic.h a parametr ATOMIC_RESTORESTATE, který provede blok atomicky a na konci obnoví přerušení do stavu v jakém bylo na vstupu do bloku.

_Jenda

  • *****
  • 1 601
    • Zobrazit profil
    • https://jenda.hrach.eu/
    • E-mail
Re:Atmel ATmega328 (a další z rodiny) a atomické čtení
« Odpověď #3 kdy: 25. 11. 2022, 00:35:33 »
Jen u té vaší metody cli() sei() musíte mít jistotu, že v danou chvíli je přerušení povolené a pak ho na konci tedy správně opět povolíte
U komplexnějšího programu se může stát, že to atomické čtení použijete ve chvíli, kdy je přerušení zakázané odjinud a vy ho tím atomickým čtením nesprávně povolíte.
Proto má avr-libc knihovnu util/atomic.h a parametr ATOMIC_RESTORESTATE, který provede blok atomicky a na konci obnoví přerušení do stavu v jakém bylo na vstupu do bloku.
V Arduinu je na tohle idiom uložit si SREG, udělat CLI, a pak SREG = uložený_SREG.

Příklad jak to dělá Arduino funkce millis (což je v podstatě tazatelův případ -- běží interrupt co každou 1ms inkrementuje čítač)
Kód: [Vybrat]
# zkopírováno ze souboru arduino-1.8.10/hardware/arduino/avr/cores/arduino/wiring.c
unsigned long millis()
{
  unsigned long m;
  uint8_t oldSREG = SREG;

  // disable interrupts while we read timer0_millis or we might get an
  // inconsistent value (e.g. in the middle of a write to timer0_millis)
  cli();
  m = timer0_millis;
  SREG = oldSREG;

  return m;
}

Wasper

  • ***
  • 120
    • Zobrazit profil
    • E-mail
Re:Atmel ATmega328 (a další z rodiny) a atomické čtení
« Odpověď #4 kdy: 25. 11. 2022, 09:51:43 »
Jen u té vaší metody cli() sei() musíte mít jistotu,
Což u vlastního programu mám (navíc cli sei jsou 2 takty, mov r,r cli mov r,r takty tři). Ale tam ten dotaz nesměřoval, to o co se snažím je se pokud možno zákazu interruptu vyhnout úplně.

Citace: Jenda
Příklad jak to dělá Arduino funkce millis (což je v podstatě tazatelův případ -- běží interrupt co každou 1ms inkrementuje čítač)
Jasný, u timeru je to celkem snadné (a stejně, konkrétně ten bych řešil radši nějak takhle, což za předpokladu, že se během 255 milisekund dostane alespoň na 10 cyklů času pro hlavní program bude fungovat)
Kód: [Vybrat]
unsigned int8_t tm_lo,tm_hi;

do {
    tm_lo = timerms_low;
    tm_hi = timerms_high;
} while (tm_lo != timerms_low);
což sice dá o jeden tik navíc, ale odpadne tam 5 cyklů ze 7mi se zakázaným interruptem.

Ale zatím mi pro obecné čtení () nejlepčí přijde konstrukce stylu
Kód: [Vybrat]
volatile int8_t data_valid;
volatile int nejaka_data;
// interrupt
nejaka_data++;
data_valid =0;

// hlavni program
int8_t mask = 1 << thread_id;
int data;
....
do {
    data_valid = mask;
    data = nejaka_data;
} while (data_valid & mask);
[/quote]
to že se to znovunačte i v případě, že mezitím dojde k běhu jiného threadu a ten bude něco číst asi vadit nebude. Jen holt jsem tak trochu doufal, že tam je něco jako LD HL,(mem) jako u Z80, které jsem si nevšiml, a která by pomohla docela hodně. :(


Wasper

  • ***
  • 120
    • Zobrazit profil
    • E-mail
Re:Atmel ATmega328 (a další z rodiny) a atomické čtení
« Odpověď #5 kdy: 25. 11. 2022, 10:00:55 »
hmm vypadla mi tam negace, a editnout to nejde :(

Wasper

  • ***
  • 120
    • Zobrazit profil
    • E-mail
Re:Atmel ATmega328 (a další z rodiny) a atomické čtení
« Odpověď #6 kdy: 26. 11. 2022, 06:22:13 »
Ja na XMEGA resil podobnou obskurnost, kde byl soubeh preruseni a potreba atomickeho cteni 5B (dva 16bit kaskadovane pocitadla a jeste bajt ze sw pocitadla), s tim ze se externi hodiny do pocitadla nesmi zastavit. Nakonec to dopadlo tak, ze sampluji 2x a hlidam monotonnost, pokud je tam vada, tak znova. Tj v bodu preteceni (na kterekoliv urovni kaskady) vznika jitter (nelze nikdy ziskat otisk ktery by byl na hrane).
Tak koukám, že těch vtipností je tam víc. Já tu honím každý takt, pak si chci dodělat výstup na displej, tak koukám, jak se inicializuje SPI (aneb nastavit MOSI a SCK na out) až jsem radší kouknul do přeloženého assembleru a jsem zděšen - to je fakt u Arduina normální, že mapování čísla PINu na port a bit (digitalPinTo*()) nejsou dělané přes nějakou magii v hlavičkách, kterou kompiler v nejběžnějším případě port# konstanta odoptimalizuje pryč, ale přes lookup tabulky v programové raměti? :-(
No jdu si dát radši panáka, a začínám mít čím dál větší úctu ke každému, kdo se tímhle musí živit....

xPoli

Re:Atmel ATmega328 (a další z rodiny) a atomické čtení
« Odpověď #7 kdy: 26. 11. 2022, 12:55:14 »
Kdo se tímhle živí zpravidla už 8bity dávno opustil. Za sebe nevím za posledních několik let, že bych narazil na něco, kde by se mi po nějaké atmeze stýskalo nebo kde by nebyl kdejaký cortex ve všech ohledech lepší.

RDa

  • *****
  • 2 672
    • Zobrazit profil
    • E-mail
Re:Atmel ATmega328 (a další z rodiny) a atomické čtení
« Odpověď #8 kdy: 26. 11. 2022, 15:46:55 »
... - to je fakt u Arduina normální, že mapování čísla PINu na port a bit (digitalPinTo*()) nejsou dělané přes nějakou magii v hlavičkách, kterou kompiler v nejběžnějším případě port# konstanta odoptimalizuje pryč, ale přes lookup tabulky v programové raměti? :-(
No jdu si dát radši panáka, a začínám mít čím dál větší úctu ke každému, kdo se tímhle musí živit....

Tak arduino jako HW ani jako libky ci IDE jsem nikdy nepouzil.. vzdy je to vlastni deska, vlastni kod a prime programovani.

Re:Atmel ATmega328 (a další z rodiny) a atomické čtení
« Odpověď #9 kdy: 26. 11. 2022, 19:19:26 »
Kdo se tímhle živí zpravidla už 8bity dávno opustil. Za sebe nevím za posledních několik let, že bych narazil na něco, kde by se mi po nějaké atmeze stýskalo nebo kde by nebyl kdejaký cortex ve všech ohledech lepší.

Není to trochu jiná kategorie čipů? Ostatně nějaké ATmega jsem naposledy potkal třeba v pračce. Celkem očekávatelně.

Re:Atmel ATmega328 (a další z rodiny) a atomické čtení
« Odpověď #10 kdy: 26. 11. 2022, 22:39:53 »
Kategorie čipů je to úplně stejná s tím rozdílem, že i entry-level arm (třeba nějaké stm32) dá i nejvyšším atmegám na zadek ve všem krom velikosti paměti, a bude stát desetinu. Poslední dobou je některé atmegy vůbec problém sehnat, end of life zprávy Microchip posílá pomalu každý měsíc.

_Jenda

  • *****
  • 1 601
    • Zobrazit profil
    • https://jenda.hrach.eu/
    • E-mail
Re:Atmel ATmega328 (a další z rodiny) a atomické čtení
« Odpověď #11 kdy: 27. 11. 2022, 15:33:34 »
Poslední dobou je některé atmegy vůbec problém sehnat, end of life zprávy Microchip posílá pomalu každý měsíc.
Zajímavé, mně přijde, že poslední rok a půl nebyla vůbec žádná STM32 (konkrétně jsem se snažil koupit F030CCT6, F103C8T6 a F405/415), teprve před měsícem se jich pár naskladnilo.

(na octopart můžete najít graf s inventory history, bohužel roční je jen pro přihlášené -- https://octopart.com/stm32f103c8t6-stmicroelectronics-41858015)

Oproti tomu AtMegy (klasika 328 v TQFP32 pouzdře) byly dostupné mnohem déle, pak nebyly asi měsíc a od té doby jsou pořád alespoň na LCSC (osazujeme u JLCPCB takže tam součástky bereme).

Každopádně já AtMegy používám protože to má na rozdíl od STM32 úplně blbuvzdorný software. Samozřejmě bych taky rád něco s vyšším výkonem. A většina STM32 má 0.5mm pitch, s čímž se mi blbě dělá, AtMegy mají 0.8mm.

Re:Atmel ATmega328 (a další z rodiny) a atomické čtení
« Odpověď #12 kdy: 27. 11. 2022, 15:52:07 »
Dostupnost čehokoliv s STM32 je teď hrozná. V mém případě STM32L031K6. A to samé platí i pro nástroje, STLink v3 mají akorát v SOS electronic za dvojnásobek normální ceny a ISOL desku jsem propásl úplně :(

Jenže.. ATmegy před pár lety hrozně zdražily a v poměru ceny k výkonu se vůbec nevyplatilo je používat, protože ARMy (hlavně různé M0+) byly příjemně levné.

Lead time na STM32 je často i dva roky. Snad se to zlepší než vyčerpám zásoby :)

Wasper

  • ***
  • 120
    • Zobrazit profil
    • E-mail
Re:Atmel ATmega328 (a další z rodiny) a atomické čtení
« Odpověď #13 kdy: 28. 11. 2022, 04:19:23 »
Tak arduino jako HW ani jako libky ci IDE jsem nikdy nepouzil.. vzdy je to vlastni deska, vlastni kod a prime programovani.
Tak to chápu. Mě zatím Arduina celkem vyhovují (začínám znovu po hodně letech bastlit a už na to tak dobře nevidím, abych desky pro SMD kreslil ručně a pak to pájel pistolkou se smyčkou ze zvonkáče jako dřív, takže hotová deska docela pomůže), nakoupenou jich mám pěknou zásobu neoriginálních od Číňana tak různě za 1-2 eura a na nějakej větší podraz jsem zatím nenarazil (nepočítaje veselé historky z natáčení jako včerejší noc příjemně strávenou studiem referenčního manuálu, Arduinových knihoven a pak i assembleru, co leze z překladače ve snaze přijít na to, proč je výstup na e-Ink přes SPI nekompatibilní s použitím USART0 na debug - nakonec důvodem bylo to, že Nano získává 3.3V z FTDI, a ten eInk když překresluje, tak žere docela velké špičky, takže to celé šlo do resetu...), až na to, že jsem tak trochu nečekal, že doba pokročila a neoptimální jsou už knihovny na osmibity, no ;-)
Ale OK, beru to, že nejsem až tak divnej a tu obsluhu si napíšu vlastní.

BTW jak to tak čtu, je tu vlastně něco sehnatelného mezi Atmelem a RPi Zero, kde se dá snadno začít si hrát? Ta malina je třeba príma třeba na časosběrnou kameru, ale na malou meteostaničku mi přijde jako kanón na vrabce (a tam ani těch 200mA spotřeby v klidu moc nepotěší). Do myčky nebo ke kotli bude Arduino asi v pohodě, ale už třeba s tím einkem je dost trouble, když se nevejde do paměti ani videoramka, které jsou potřeba navíc dvě (ne, že by to nešlo to dorenderovávat za běhu, ale je to pakárna).

Re:Atmel ATmega328 (a další z rodiny) a atomické čtení
« Odpověď #14 kdy: 28. 11. 2022, 07:37:38 »
Já mám řadu:
Attiny84 pro velmi malé projekty
Atmega328
ESP8266
ESP32
Ty Atmely používám jak kdy, buď s arduino frameworkem, když tam není nic kritického a nebo to chci mít rychle spíchnuté a nebo přímý kod na čisté železo.
ty ESP výhradně s Arduino frameworkem. Ostatně u větších projektů stejně téměř vždy potřebuji nějakou formu komunikace, tak se Wifi hodí.  Ty Esp  v provedení Wemos D1 Mini a nebo Wemos ESP32.