Hogyan szívassuk magunkat Arduino alatt

Ha a chip nem reagál a programozóra...
Avatar
csabeszq
Bitfaragó
Hozzászólások: 678
Csatlakozott: 2012. szeptember 5. szerda, 6:00

Hogyan szívassuk magunkat Arduino alatt

Hozzászólás Szerző: csabeszq »

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.

:)
Avatar
Robert
Elektronbűvölő
Hozzászólások: 10191
Csatlakozott: 2005. december 9. péntek, 7:00

Re: Hogyan szívassuk magunkat Arduino alatt

Hozzászólás Szerző: Robert »

SPI megoldás mi lett?
MISO láb és GND közé 10kohm?


I2C:
Hiányzó volatile és szinkronizáció (cli)
Ez hol hiányzott?
Megszakításkezelés végén?
Avatar
csabeszq
Bitfaragó
Hozzászólások: 678
Csatlakozott: 2012. szeptember 5. szerda, 6:00

Re: Hogyan szívassuk magunkat Arduino alatt

Hozzászólás Szerző: csabeszq »

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:

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;
  }
}
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.
Válasz küldése