Van egy projekt, amin dolgozom: a terepasztal jelzővezérlése. I2C-n érkeznek a jelek a vonat/váltók helyzetéről, a cucc meg automatikusan állítja a jelzőket. Többé-kevésbé ment is, de volt két hiba:
- néha kezdetben, amikor rádugom a kakaót, akkor nem állítódnak a jelzők, rosszul indul el a rendszer
- vagy néha elfelejti átállítani a jelzőket akkor, amikor elmegy a vonat az ellenőrzőpontnál
Apró hibáknak tűnnek, de a javításuk 10 óra volt mindenestül együtt. A probléma ugye az, hogy néha megy, néha nem megy. Ezek a legrohadtabb fajtából vannak. Több hónap kellett, hogy végre leüljek és rááldozzam azt a 10 órát, mert helyette idáig inkább szórakoztam, netezgettem és hagytam az egészet a fenébe.
Hiba 1: amikor időnként nem indul el a rendszer
- a rendszerre kötött TLC5940-es IC-k számát úgy határozom meg, hogy kiküldök SPI-n egy csomó 0xFF byte-ot, kiküldök utána egy 0xA5 bájtot és utána addig tolom az 0xFF bájtokat, amíg a 0xA5 vissza nem jön. Ez a chip shift regiszternek felel meg. Ha egy TLC van, akkor 24 küldés után jön vissza, amit beraktam. Ha 10 TLC van, akkor 240 után. Mi volt a probléma? Az, hogy egy TLC sem volt rákötve. Ilyenkor elvileg küldöm az adatokat, de mivel nincs IC rákötve, semmi sem jön vissza. Ezt programból detektálni lehet. Amit eltoltam, hogy a MISO láb lebegett, nem raktam rá pull-up-ot. Ebből kifolyólag Időnként megérkezett a 0xA5, anélkül is, chip lett volna mögötte, mikor éppen úgy támadt kedve lebegni. Itt pedig szétszállt az egész.
Hiba 2: amikor kimarad a jelző frissítése
- az I2C adat interruptban jön, a jelző a fő szálban fut. Hiányzó volatile és szinkronizáció (cli). Jó szórakozás AVR alatt szinkronizációs problémák vadászata. Pláne, hogy azt sem tudtam, hogy elküldi-e a másik IC, ezért analizátorral kellett kimérni. Utána láttam, hogy el is küldi, meg is kapom, csak valamiért elveszik. Ekkor szinkronizálás + volatile és lám megjavult.
Hogyan szívassuk magunkat Arduino alatt
Re: Hogyan szívassuk magunkat Arduino alatt
SPI megoldás mi lett?
MISO láb és GND közé 10kohm?
I2C:
Megszakításkezelés végén?
MISO láb és GND közé 10kohm?
I2C:
Ez hol hiányzott?Hiányzó volatile és szinkronizáció (cli)
Megszakításkezelés végén?
Re: Hogyan szívassuk magunkat Arduino alatt
A felhúzó az SPI-nél kellett a MISO-ra.
A jelzővezérlő TLC-t és NeoPixelt egyszerre tud kezelni, jelenleg TLC-t nem használtam, helyette egy WS2812B LED szalaggal emuláltam a jelzőket. A logika ugyan az, csak szoftverből nem a TLC LED vezérlőre, hanem a LED szalagra drótoztam a jelzőket. Az egészet úgy kell elképzelni, hogy minden égőnek feladata lehet, a feladatokat és az égőket szoftverből kötöm össze (EEPROM). Az "állomás lámpa" egy feladat (amikor bejön a vonat felkapcsol, egyébként lekapcsol), de a "7. jelző piros lámpája" szintén feladat, amit valamelyik LED-del a TLC-n, vagy a NeoPixelen össze lehet drótozni. Nincs kitüntetett szerepe az égőknek, ugyanaz a kimenet lehet kereszteződési lámpa, vasúti jelző, vagy utcai lámpa is (lassan kapcsol fel).
A kódot sematikusan felvázolnám:
A fenti ábrán látszik, hogy egyrészt a "feladatok" változót egyszerre használja interrupt és a fő szál, tehát definició szerint volatile.
Emellett szinkronizációs probléma is van, mert a "feladatok &= ~(TLC_FRISSITES | TLC_AKARMI)" sor képes arra, hogy kinullázza a beérkező NEOPIXEL_FRISSITES-t.
- beolvassa a "feladatok" változót valamelyik regiszterbe
- ISR eközben felülírja a "feladatok"-at, hozzáadva a NEOPIXEL_FRISSITES bitet
- a kód a regiszterben kitörli a TLC biteket
- majd visszaírja, felülvágva az ISR által beállított NEOPIXEL_FRISSITES-t
A volatile elengedhetetlen és emellett még interrupt-ot is kellett esetenként tiltanom, hogy ne keveredjenek össze.
A jelzővezérlő TLC-t és NeoPixelt egyszerre tud kezelni, jelenleg TLC-t nem használtam, helyette egy WS2812B LED szalaggal emuláltam a jelzőket. A logika ugyan az, csak szoftverből nem a TLC LED vezérlőre, hanem a LED szalagra drótoztam a jelzőket. Az egészet úgy kell elképzelni, hogy minden égőnek feladata lehet, a feladatokat és az égőket szoftverből kötöm össze (EEPROM). Az "állomás lámpa" egy feladat (amikor bejön a vonat felkapcsol, egyébként lekapcsol), de a "7. jelző piros lámpája" szintén feladat, amit valamelyik LED-del a TLC-n, vagy a NeoPixelen össze lehet drótozni. Nincs kitüntetett szerepe az égőknek, ugyanaz a kimenet lehet kereszteződési lámpa, vasúti jelző, vagy utcai lámpa is (lassan kapcsol fel).
A kódot sematikusan felvázolnám:
Kód: Egész kijelölése
uint8_t feladatok = 0;
ISR(I2C)
{
if( vonatallapot erkezett )
{
feladatok |= NEOPIXEL_FRISSITES | TLC_FRISSITES;
}
}
void loop()
{
if( nincs_tlc )
feladatok &= ~(TLC_FRISSITES | TLC_AKARMI); // ha nincs TLC, akkor a TLC feladatokat nem hajtom végre
if( feladatok & NEOPIXEL_FRISSITES )
{
frissitsd_a_led_szalagot();
feladatok &= ~NEOPIXEL_FRISSITES;
}
}
Emellett szinkronizációs probléma is van, mert a "feladatok &= ~(TLC_FRISSITES | TLC_AKARMI)" sor képes arra, hogy kinullázza a beérkező NEOPIXEL_FRISSITES-t.
- beolvassa a "feladatok" változót valamelyik regiszterbe
- ISR eközben felülírja a "feladatok"-at, hozzáadva a NEOPIXEL_FRISSITES bitet
- a kód a regiszterben kitörli a TLC biteket
- majd visszaírja, felülvágva az ISR által beállított NEOPIXEL_FRISSITES-t
A volatile elengedhetetlen és emellett még interrupt-ot is kellett esetenként tiltanom, hogy ne keveredjenek össze.