Fórum témák

» Több friss téma
Fórum » AVR - Miértek hogyanok
 
Témaindító: pakibec, idő: Márc 11, 2006
Témakörök:
WinAVR / GCC alapszabályok:
1. Ha ISR-ben használsz globális változót, az legyen "volatile"
2. Soha ne érjen véget a main() függvény
3. UART/USART hibák 99,9% a rossz órajel miatt van
4. Kerüld el a -O0 optimalizációs beállítást minden áron
5. Ha nem jó a _delay időzítése, akkor túllépted a 65ms-et, vagy rossz az optimalizációs beállítás
6. Ha a PORTC-n nem működik valami, kapcsold ki a JTAG-et
Bővebben: AVR-libc FAQ
Lapozás: OK   834 / 840
(#) harcipocok hozzászólása Jún 5, 2023 /
 
Sziasztok!

Van egy érdekes hibám. Arduino Mega 2560-at használok, és van kb. 30 változóm, aminek a beállított értékeit EEPROM-ban tárolok. Ez egy céleszköz, amit az ügyfél telepén üzemelek be, itt állítom be a változók értékeit a környezethez igazítva. Miután mindent beállítottam akkor történik EEPROM írás csak a kódban. Ezután a vezérlőt újraindítva a beállítói menü ahol az írás történik már nem kerül meghívásra, így elméletileg többször nem fog lefutni az írásos funkció, csak induláskor beolvassa az EEPROM-ban tárolt értékeket egy-egy változóba, és azokat a változókat használja futáskor.

Ezek a telepített eszközök hónapok óta tökéletesen működnek, viszont a telepített kb. 100 eszközből 3-4 gépnél előfordult az, hogy a napi bekapcsolását követően az eszköz nem jól működött, és mint kiderült az egyik változó értéke valami hatalmas nagy szám lett. (alapesetben ezek az értékek 0-100-ig vannak, és a beolvasott érték ~23.000 környéki volt) Többszöri újraindítás után is mindig ezt az értéket kapta vissza, tehát magában a memóriában már rossz érték szerepelt. Kérdés hogy ez hogy került oda úgy, hogy az EEPROM írásos függvény elvileg már nem is kellett hogy lefusson, illetve ha lefutott is volna, akkor is írás előtt lecsekkolja, hogy a menteni kívánt érték 100 alatti-e, és 0-nál nagyobb-e.
Az EEPROM.put függvényt használom, és sima int értéket teszek bele, egymástól 5 címmel eltolva. Tehát ezek nem fedik egymást.

EEPROM library-t használok

Amit még fontos tudnotok: eddig balga módon a Brown-Out-Detection-t kikapcsoltam a fuse biteknél. Megvan az oka hogy miért, de nagyon gyanús hogy ez okozhat problémát. Stabil tápot kap a mikrovezérlő, és indításkor 2 másodpercig nem csinál semmit az eszköz, csak várja hogy tuti stabil legyen a táp, és csak a 2sec után kezd EEPROM-ot olvasni. Viszont utána a normál futás közben sosem hívódik meg az írás, mégis valamiért rossz adat került az EEPROM-ba. Ez lehet esetleg amiatt, hogy Brown-Out-Detection hiánya miatt alacsony feszültségnél a proci hibázik, és valamiért meghívja az EEPROM írást és oda hülye értéket ír be? Mert ez nekem annyira lehetetlennek tűnik...

A kapcsolásban látható, hogy 1 db 100 nF kondi van zavarszűrésre, és 1-1 db 1000µF/10V LOW ESR kondi van a mikrovezérlő előtt és után. Elképzelhető hogy a stabil 5V betáp megszűnése esetén a két kondi szépen beejti a feszültséget mondjuk a kritikus 4V alá, és a Brown-Out-Detection hiánya miatt ekkor a proci elkezd hibázni és meghívja az EEPROM.Put függvényt amivel betesz egy random számot egy random címre? Vagy mi okozhat ilyen random memória írás hibát?

Ha újra konfigurálom, újra lementem a változót a memóriába akkor természetesen megjavul, tehát maga a memóriaterület nem ment tönkre és nem is történik sűrű írás a memóriaterületre. Az eset ritkán fordul elő és nem minden gépen, de simán lehet hogy csak idő kérdése....

UI: a képen a bal oldali kondik fordítva vannak, tehát a 100nF van közvetlenül a táp után
A hozzászólás módosítva: Jún 5, 2023

kapcsolas.jpg
    
(#) Kovidivi válasza harcipocok hozzászólására (») Jún 5, 2023 / 1
 
Szia.
Nekem is van hasonló probémám, de nálam írás közbeni tápelvétel az ok (áramszünet vagy bármi más miatt). Amit tudsz tenni: 3 különböző helyre mented le ugyanazt, és beolvasáskor megvizsgálod, hogy mindhárom érték azonos-e. Ha nem, akkor a kettő helyessel felülírod a hibásat. Ezzel kiküszöbölted a hibás működést.
Arra tudok gondolni, hogy akár ha olvasáskor szűnik meg a táp, akkor is lehet, hogy az EEPROM-ba hibás adat kerül. Pl. olvasás félbemarad, az EEPROM egy bizonyos állapotban van, és újraindítás után úgy kezeled az EEPROM-ot, mintha alapállapotban lenne, miközben ő mondjuk a címet várja. Erre te elküldesz neki ismét egy olvasás parancsot, amit ő adatnak értelmez, majd utána egy adatot, amit meg utasításnak. Valami ilyesmire gondolok. Tehát kellene egy EEPROM resetet is indításkor csinálni.
Én így oldanám meg, ezzel a maradék 3-4% hibalehetőség is eltűnne.
Üdv.
A hozzászólás módosítva: Jún 5, 2023
(#) harcipocok válasza Kovidivi hozzászólására (») Jún 5, 2023 /
 
Idézet:
„"EEPROM reset"”
- Ezt hogyan tudom megcsinálni?

Hibajavítást most már én is alkalmazok, bár én csak 2 helyre mentek adatot.
Ha a fő memóriacímen tárolt adat 0-100-ig van (jellemzően amikor rossz érték került bele akkor szint mindig ilyen nagyon magas szám volt benne) akkor a backup memóriacímről beírom az értéket a fő memória címre. Egyébként ha a fő memóriacímből kiolvasott érték tartományon belüli, akkor a Backupot mindig beírja újra. Elméletileg az EEPROM.put() függvény csak akkor írja ténylegesen be ha változott az érték a tárolthoz képest.

Egyébként az, hogy az Arudio Mega-nak 4kbyte-os az EEPROM-ja, azt azt jelenti hogy a max cím amit beírhatok az EEPROM.put(4000, változó)?? Tudom, hülye kérdés, de tényleg nem vágom

Idézet:
„"akár ha olvasáskor szűnik meg a táp, akkor is lehet, hogy az EEPROM-ba hibás adat kerül. "”
- Ezt egyébként a Brown-Out-Detectionnel megelőzhető?
A hozzászólás módosítva: Jún 5, 2023
(#) Kovidivi válasza harcipocok hozzászólására (») Jún 5, 2023 /
 
Nézz utána, hogyan működik pontosan az EEPROM írása, olvasása, pl., hogy mennyi idő telhet el az adatok között. Lehet, hogy nincs is időkorlát, elküldöd az olvasás parancsot, majd fél óra múlva a címet, és működik... Nem akarok butaságot írni, már nagyon régen nem foglalkoztam vele. Lehet elégséges, ha indításkor kiküldesz 4db 0-t. Gondolom inicializálás nincs, így reset sem.

Ha csak két helyen tárolod az infót, akkor sosem tudod, hogy melyik a jó (ha véletlenül 100 alatt maradna a hiba is). Háromnál már egyszerűen eldönthető. Ha nagyon magas értéket olvasol, akkor ott több hiba is van. 255-nél nagyobb értéket csak 2 byteon tudsz tárolni. Miért olvasol be egynél több bytot, ha csak egy byteon tárolsz? A második byte fixen nulla kellene hogy legyen, miközben az EEPROM gyárilag 0xFF-fel van feltöltve! Ilyenkor lehetséges, hogy nem is az adatod lesz hibás, hanem az utána levő címre kerül valami beírásra, vagy az előtte levőre. Ne integert-t használj, hanem byte-ot olvass be. Esetleg van egy függvényed, ami a RAM-ot túlcímzi, és miután az adat az EEPROM-ból a RAM-ba került, a hibás függvény pont arra a részre ír be, ahol a változókat tárolod. Ilyenkor ha összehasonlítanás az EEPROM és a RAM tartalmát, más értékeket kapnál.

4kbyte az 4096byte, a címek 0-tól indulnak, a legnagyobb cím 4095 lehet! Integert 2byteon tudsz tárolni, így kettessével kellene lépkedned.

A Brown-Out detektorban én nem bíznék, főleg, hogy ha több byteot írsz. Ha elmegy a táp, akkor elment, nem tudsz mit csinálni. Az EEPROM írás lassú folyamat.

"Egyébként ha a fő memóriacímből kiolvasott érték tartományon belüli, akkor a Backupot mindig beírja újra" - itt viszont van egy írás, ami félre is sikerülhet, és olyankor hogy melyik adat károsodik, azt nem tudni. Lehet az összes.
(#) harcipocok válasza Kovidivi hozzászólására (») Jún 5, 2023 /
 
Közben átnéztem a programot, és találtam egy hibát:

A program elején definiálom az alábbi tömböt:

  1. int konfig[50];


Tehát ez egy 51 elemből álló tömb. Majd a program futása közben a user le tudja csekkolni, úgymond lapozgatni tudja a beállított értékeket.
  1. ertek = konfig[aktertek];

Az aktertek mindig az aktuális érték, ha ezt lapozza akkor ez növelődik egyesével.

Észrevettem, hogy a megjelenítésnél van egy érték, ami kifut a tömb tartományból, ugyanis az 50 db konfigurálási értéken kívül van egy ellenörző érték, és ez ha meghívódik, akkor az akterteknek 500-as értéket ad:

  1. ertek = konfig[500];


Ugyebár a tömb nincs definiálva 500-ig csak 50-ig. A fordításkor a program nem veszi észre mert változóval hívom be az 500-as elemet, így szépen gond nélkül lefordul a program.

A poén az, hogy nem is fagy le miatta, szépen fut tovább ha egy pillanatra meghívom az 500-at, de ez okozhat ilyen túlcsordulást, hogy a háttérben szépen memóriaterületeket írogat hülyeségekkel?

Gondolnám hogy ebbe bele kellene fagyni, de fut tovább a program. Persze a következő ciklusban az aktertek az 0 lesz mert akkor már az elején lecsekkolom hogy 50 feletti-e az aktertek, ha igen akkor legyen 0. De egyszer engedi 50-ről 500-ra állítani
A hozzászólás módosítva: Jún 5, 2023
(#) pipi válasza harcipocok hozzászólására (») Jún 5, 2023 / 1
 
Mitől lenne 51 az az 50?
50 hely az , a cimzés meg [0]...[49]
(#) harcipocok válasza pipi hozzászólására (») Jún 5, 2023 /
 
Teljesen igazad van, rosszul írtam.
(#) zolee1209 válasza harcipocok hozzászólására (») Jún 5, 2023 /
 
Használd a BOR-t. Az AVR nem szereti, ha lassan megy el a tápja, sérülhet az EEPROM tartalma. Ehhez nem szükséges a függvényt tartalmaznia a programnak, a vezérlőregiszterek vesznek fel fals értéket.
(#) Kovidivi válasza harcipocok hozzászólására (») Jún 5, 2023 /
 
Miért fagyna be? Ez nem windows. Csinálja, amire megkéred, még ha értelmetlen, akkor is. Szépen kiolvassa az 500-as helyen levő memória értékét, és utána fel is használja. Honnan tudná az AVR, hogy ezt esetleg nem direkt csináltad? Ha eljutsz a pointer logikáig, rájössz, hogy AVR mindent IS csinálhatsz, lefagyni nem fog. Ha "lefagy", akkor is inkább user error miatt belement egy olyan ciklusba, amiből nem tud kijönni, de ilyenkor sincs lefagyva, csak nem azt csinálja, amit szeretnél. Jók ezek az AVR-ek.
(#) pipi válasza Kovidivi hozzászólására (») Jún 5, 2023 /
 
Kedvenc - valahol hallott - szólásom: a számítógép utasításaid, és nem a a kívánságaid szerint működik
(#) lazsi válasza pipi hozzászólására (») Jún 6, 2023 /
 
Ezért értik meg jobban a férfiak, mint a nők...
(#) harcipocok válasza Kovidivi hozzászólására (») Jún 6, 2023 /
 
Rendben, ezt megértettem...

Egy dolgot kihagytam a leírásból, így már érthető lesz miért gondoltam hogy "kifagy":

  1. for (int i = 0; i <= 50; i++) {
  2.     EEPROM.get((i * 10) + 1, konfig[i]);    
  3.   }


Ilyen módon oldom meg az eltolást. Tehát az 50 konfig érték egymástól 10-re van eltolva.

A konfig[1] az 1-es címen tárolódok, a konfig[2] a 11-es címen, és így tovább. A konfig[50] pedig az 501-es címen. Viszont ugye írtam hogy véletlenül bekerül az 500-as érték is, és a konfig[500] az az 5001-es memória címre mutat, ami meg ugye Mega esetén már nem létezik.

Ez okozhat anomáliát? Elvileg írni nem akarna erre a területre csak olvasni, de egy hibás címzés miatt az olvasásból lehet valamilyen módon eeprom korrupció?
A hozzászólás módosítva: Jún 6, 2023
(#) lazsi válasza harcipocok hozzászólására (») Jún 6, 2023 /
 
A konf[1] a 11-es címen tárolódik...
Az 1-es címen a konf[0] lesz (a "for (int i = 0;" miatt).
Szerintem így összesen 51 db értéked van (az "i <= 50;" miatt): 0 - 50.
Viszont az "int konfig[50];" talán valóban csak 50 db. helyet definiál...
Ezt az 50 vs. 51 kérdést célszerű lehet rendezni...

Másrészt, azt is meg kellene nézni, hogy miért alakulhat ki az 500-as érték? Ne a lekérdezésnél, hanem már a keletkezésénél zárd ki a lehetőségét...
(#) harcipocok válasza lazsi hozzászólására (») Jún 6, 2023 /
 
  1. int konfig[50];


Ezt a sort már megemeltem a biztonság kedvéért 55-re Gondot nem hiszem hogy okozna az, hogy több elemet definiáltam mint amennyit használok.

Az 500-as érték az az én hülyeségem miatt van, nem véletlenül került bele. Ahogy fentebb is olvasható sajnos oda nem számot írtam hanem változót. És a változó sajnos néha lehet 500. EZT tegnap már javítottam, ez a változó már nem vehet fel 500-as értéket, és így elvileg két hibát javítottam:

- Nem futok ki az előre definiált tömb méretből (50-et definiáltam csak, de az 500-as elemével is meghívtam és dolgozni akartam vele)
- Nem akar még véletlenül sem az 5001-es EEPROM címen olvasni/írni.

Mindegyik kritikus hiba, és NAGYON remélem hogy ez okozta azt a problémát, hogy néha-néha elmászott egy-egy EEPROMban tárolt érték. Logikus lenne. Kérdés még továbbra is az, hogy egy hibás címzés (tartományon kívül) miatt az olvasásból, vagy egy tömb túlcsordulásból lehet valamilyen módon eeprom korrupció, és emiatt sérül 1-1 eeprom címen tárolt adat?
A hozzászólás módosítva: Jún 6, 2023
(#) vargham válasza harcipocok hozzászólására (») Jún 6, 2023 /
 
Ilyet nem használunk. Nagyon könnyű elrontani. Tele lesz számokkal a kód. Egy helyen átírod, többi meg marad ugyanannyi...
  1. int konfig[50];

Egy forráskódban sehol sem szerepelhet szám, helyette nevesített konstansokat használni.
Aztán az is érdekes, hogy miért két bájtos adattípust (int) használsz, ha az adatod elfér egy bájton is. Használj pontosan definiált méretű adattípust, például uint8_t.
Rögtön feleslegessé is válik a tizes cím eltolás. Mondjuk int esetében is csak kettővel kellett volna eltolni... Amúgy pedig a sizeof függvénnyel lehet lekérni a hosszát. Olvashatóbb és változtatás állóbb is a kód.
  1. #define ELEMEK_SZAMA 50
  2. uint8_t konfig[ELEMEK_SZAMA];

És akkor a ciklus:
  1. for (int i = 0; i < ELEMEK_SZAMA; i++) {
  2.     EEPROM.get(i * sizeof(konfig[0]), konfig[i]);
  3. }

Így aztán nyugodtan változtathatod akár az elemek számát, akár a típusát, a kódod mindig jól fog működni.

Vagy ott lenne a C++ array, ami mindezt szükségtelenné tenné...
(#) harcipocok válasza vargham hozzászólására (») Jún 6, 2023 /
 
Köszönöm a sok segítséget, biztos vagyok benne hogy vannak hiányosságaim a kódolás terén. És nyilván ezeket az észrevételeket lehet hogy implementálni fogom a kódba.

Viszont a fő kérdésem továbbra is az hogy egy hibás címzés (tartományon kívül) miatt az olvasásból, vagy egy tömb túlcsordulásból lehet valamilyen módon eeprom korrupció, és emiatt sérül 1-1 eeprom címen tárolt adat?

Tehát hogy megnyugodhatok-e vajon a fent említett hibák javításával?

UI: egy kérdés, itt a "konfig[0]"-val kell hivatkozni a teljes tömbre? Vagy mindegy hogy melyik elemet adom meg, mert csak arra kell hogy tudjam hány bájtot foglal egy adat?
  1. EEPROM.get(i * sizeof(konfig[0]), konfig[i]);
A hozzászólás módosítva: Jún 6, 2023
(#) zolee1209 válasza harcipocok hozzászólására (») Jún 6, 2023 /
 
Nem állítom, hogy SW oldalról nincs értelme megtámogatni a hibakezelést, de 2000µF puffer esetén nem ez lesz a hosszútávú megoldás. Bővebben: Link
A hozzászólás módosítva: Jún 6, 2023
(#) vargham válasza harcipocok hozzászólására (») Jún 6, 2023 /
 
sizeof(konfig[0]) megmondja, hogy hány bájt a tömb első eleme. Mivel a tömb összes eleme egyforma méretű, így ezzel megkapod a méretét.
(#) vargham válasza harcipocok hozzászólására (») Jún 6, 2023 /
 
Amúgy a ciklust sem kell megírni, mert az AVR GCC libben már megírták nekünk mások.
Ezek a függvények azok:
  1. void eeprom_write_block (const void *__src, void *__dst, size_t __n);
  2. void eeprom_read_block (void *__dst, const void *__src, size_t __n);
  3. void eeprom_update_block (const void *__src, void *__dst, size_t __n);

Forrás
Így használhatod:
  1. eeprom_read_block ((void *)konfig, (const void *)EEPROM_CIM, ELEMEK_SZAMA); //Ahol konfig a tömböd, EEPROM_CIM az neked most nulla, ELEMEK_SZAMA pedig a tömb mérete.
(#) harcipocok válasza zolee1209 hozzászólására (») Jún 7, 2023 /
 
Idézet:
„de 2000µF puffer esetén”


Ez miért probléma? Túl sok, túl kevés? vagy mi a gond vele?
Elektronikához (is) hülye vagyok
(#) dc001 válasza harcipocok hozzászólására (») Jún 7, 2023 /
 
"Ez egy céleszköz, amit az ügyfél telepén üzemelek be, itt állítom be a változók értékeit a környezethez igazítva. Miután mindent beállítottam akkor történik EEPROM írás csak a kódban. Ezután a vezérlőt újraindítva a beállítói menü ahol az írás történik már nem kerül meghívásra, így elméletileg többször nem fog lefutni az írásos funkció, csak induláskor beolvassa az EEPROM-ban tárolt értékeket egy-egy változóba, és azokat a változókat használja futáskor."

Nekem is volt gondom az EEPROM-ban tárolt adatokkal. Főleg akkor, ha hosszú áramszünet miatt a szünetmentes akkumulátora merült le és így szép lassan fogyott el a "delej".

Ha csak egyszer (vagy ritkán) állítod az értékeket, akkor szerintem sokkal jobb megoldás, ha flash-be tárolod. Kiolvasod a page-et, a változók helyén módosítod, majd vissza írod. Akár az is lehet, hogy dedikált page-en csak ezek a változóid vannak.
(#) TavIR-AVR válasza dc001 hozzászólására (») Aug 5, 2023 / 1
 
BOD bekapcsolni (tápfesztől függően, az egy egységgel alább). Nincs "EEPROM garbage".
EEPROM 0. címe TILOS írni - > lsd adatlap: tápfeszvesztéskor véletlen beírás lehet.
Watchdog kezelendő.
(#) alita hozzászólása Aug 9, 2023 /
 
Szervusztok !

A napokban feltöltöttem az Atmel Studió 7-t.Úgy gondolom,hogy valamit nem jó csináltam,mert
a végén nem jelent meg a parancsikon,de a helyi lemez fájloknál sem jelenik meg a szokásos
Atmel.A programok között fenn van az 5.03 Gb. Persze megnyitani sem lehetett,ezért törölni akartam,de nem lehetséges,sem a vezérlő pulttal,sem a Totalcomander-ral.Törlés alkalmával
újra a szokásos telepítési eljárás jelenik meg,de csak egy darabig.
Hogy tudnék megszabadulni ettől a förmedvénytől.

Üdv:Minden fórumtársnak
(#) alita válasza alita hozzászólására (») Aug 9, 2023 /
 
Addig-addig győzködtem,míg nem sikerült a problémám megoldása.
(#) Sipy hozzászólása Aug 15, 2023 /
 
Sziasztok! Tönkrement az elektromos rollerem egy step-Down ic hibája miatt úgyhogy új elektronikát csinálok hozzá. Az egyik gondolatom az hogy ha elém kanyarodik valaki akkor egy távolságmérő szenzor segítségével ezt észlelné az avr és magától vészfékezne. Ehhez nekem olyan szenzor kellene ami tud legalább vagy 20 méterre látni. A hc-sr04 sajnos csak 5 méteres. Nem muszáj ultrahangos, lézeres is jó lenne de se a kereső nem ad ki megfelelő érzékelőt se az AliExpress. Tudtok ajánlani valamit?
(#) kalmi.kalmi válasza Sipy hozzászólására (») Aug 15, 2023 /
 
Sok sikert kívánok a fejlesztéshez.
(#) kendre256 válasza Sipy hozzászólására (») Aug 15, 2023 /
 
Hozzá sem kezdenék...
A Suzuki kamerás, radaros érzékelője is időnként ütközésre figyelmeztet indokolatlanul, és elkezd fékezni, pedig azt elég sokan fejleszthették, elég régóta.
Ha ilyet sikerülne is kifejlesztened, utána el kellene felejteni a járdán gyalogosok közötti cikázást, mert 10 méterenként fejreállnál...
Az emberi agy sokkal jobb ennél, három dimenziós, nemlineáris egyenleteket old meg valós időben. Már ha figyel persze...
(#) pipi válasza Sipy hozzászólására (») Aug 15, 2023 /
 
Madarakra is gondoltál?
(#) kalmi.kalmi válasza pipi hozzászólására (») Aug 16, 2023 /
 
Ez jó ! Madár, macska, utcai kuka, számtalan oszlop, kikerülendő tárgy, és igen az emberek.
(#) Sipy válasza kalmi.kalmi hozzászólására (») Aug 16, 2023 /
 
Azokat se kéne elütni
Következő: »»   834 / 840
Bejelentkezés

Belépés

Hirdetés
XDT.hu
Az oldalon sütiket használunk a helyes működéshez. Bővebb információt az adatvédelmi szabályzatban olvashatsz. Megértettem