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
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
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...