logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[a168][c]dlaczego procek może nie chcieć pisać do eepromu?

PO. 15 Cze 2010 16:46 1295 19
  • #1 8193318
    PO.
    Poziom 20  
    Pytanie z serii "krasnoludków" ale mnie przerosły.

    Nigdy nie miałem problemów z odczytywaniem i zapisywaniem eepromu. Używam procedur na żywca przepisanych z datasheeta i działało zawsze.
    Teraz zaczęło się dziwnie, odczyt ustawień w urządzeniu normalny, zapis niby leci ale nie były zapamiętywane.
    Obrałem program ze wszystkiego do testów, po restarcie jest jedno mignięcie diodką żebym wiedział, że ruszył i leci zapis jednego bajtu pod stały adres, po czym sobie zgrywam eeprom i podglądam w hexedicie - niespodzianka, nie ma zapisu...
    Już nawet nie wywołuję procedury tylko robię w głównym programie ten fizyczny zapis i też nic.
    Nie zezwalam na obsługę przerwań, mimo że i tak są niby wyłączane przeze mnie w procedurze przed każdym zapisem.
    Tak, procka zmieniałem na inny egzemplarz.
    Tak, używałem już tych samych procedur w innych projektach, z a168 też.

    Co za licho mnie dotknęło i jak je zwalczyć? Innymi słowy o jakich fanaberiach atmelka nie wiem, o które się potknąłem...?
  • #2 8193382
    lucas_mcs
    Poziom 22  
    A jak tam elektrycznie? Z tego co wiem EEPROM pobiera więcej prądu przy zapisie.
    Jeśli masz inny projekt z identycznym układem to sprawdz czym sie różnią na możliwie najniższym poziomie także (software/hardware). Ew. Przełóż układ do działającego projektu i zobacz czy się programuje.

    Może to słaby pomysł ale zdarzają się też wadliwe serie.
    Tyle co mi przyszło na myśl.
  • #3 8193390
    PO.
    Poziom 20  
    Elektrycznie 10uF+0,1uF+zasilanie usb jedzie z programatora.
    Wewnętrzny oscylator, ckdiv wyłączone.
    Ile mu dać, żeby elektrycznie wyrobił, jeśli to to?

    Procek wyjęty z działającego projektu, który normalnie zapisywał wszystko ale jeszcze w czymś sprawdzę...

    PS: problem w tym, że nie ma zwisu/resetu tylko się dane nie pojawiają. To normalne czy przy słabym zasilaniu byłby reset np?
  • #4 8193405
    Krauser
    Poziom 26  
    1. A co odczytasz jeśli po prostu stworzysz zmienną zainicjowaną w EEPROM i zaprogramujesz procesor?
    2. Próbowałeś funkcji z avrlibc?
  • #5 8193427
    PO.
    Poziom 20  
    Odczytuje się normalnie.
    Z programatora eeprom się zapisuje też normalnie.

    Softwarowo to nie możemy już o niczym mówić, bo w programie teraz jest już tylko ten jeden zapis i dalej nic nie robi.
  • #6 8193489
    Krauser
    Poziom 26  
    Na pewno kawałek kodu dał by lepszy obraz.
    Co z bitami EEPM1 i EEPM0 z rejestru EECR?
  • #7 8193495
    acid12
    Poziom 21  
    ustaw watchdoga, moze program wisi na zapisie,
    spribuj zmienic adres, na np wiekszy o 64B
    może ta sekcja pamieci uległa uszkodzeniu przez ciągłe próby zapisywania ... ale mówisz że z programatora normalnie idzie ...
  • #8 8193523
    sulfur
    Poziom 24  
    Nie mam doświadczenia w eepromie, ale z tego co wiem, jak się zapisuje więcej bajtów, to pomiędzy bajtami należy trochę poczekać, ponieważ zapis trwa. Ile ? Nie wiem, wyczytałem to w jednym temacie na tym forum, zupełnie przez przypadek. Może w tym jest problem?
  • #9 8193598
    PO.
    Poziom 20  
    Krauser napisał:
    Na pewno kawałek kodu dał by lepszy obraz.
    Co z bitami EEPM1 i EEPM0 z rejestru EECR?


    Kawałek kodu na zamówienie...
    
    int main(void){
    
     DDRB= 0b00000010;
     PORTB=0b10001000;
    
     DDRC= 0b00000000;
     PORTC=0b00000000;
    
     DDRD= 0b10100110;
     PORTD=0b11111100;
    
     led_d3_1;
     _delay_ms(100);
     led_d3_0;
     //mignąć ledką?
    
    //eeprom_write(0x0020,0x32);
     while(EECR&(1<<EEPE)); // Wait for completion of previous write
     cli(); //wyłącz przerwania
     // Set up addres and data registers
     EEAR=0x0020;
     EEDR=0x32;
     EECR|=(1<<EEMPE); // Write logical one to EEMWE
     EECR|=(1<<EEPE); // Write logical one to EEMWE
     sei(); //włącz przerwania 
    
    _delay_ms(100);
    led_d5_1;
    
    for(;;);
     sleep();
    


    i sama zewnętrzna procedura, wcześniej używana:
    void eeprom_write(uint16_t uiAddress, uint8_t ucData){
     while(EECR&(1<<EEPE)); // Wait for completion of previous write
     cli(); //wyłącz przerwania
     // Set up addres and data registers
     EEAR=uiAddress;
     EEDR=ucData;
     EECR|=(1<<EEMPE); // Write logical one to EEMWE
     EECR|=(1<<EEPE); // Write logical one to EEMWE
     sei(); //włącz przerwania 
    }


    EEPM1 i EEPM0 się zerują po resecie każdym ale i tak testowo wrzucałem zerowanie do zapisu i nie pomagało.

    Dodano po 1 [minuty]:

    acid12 napisał:
    ustaw watchdoga, moze program wisi na zapisie,
    spribuj zmienic adres, na np wiekszy o 64B
    może ta sekcja pamieci uległa uszkodzeniu przez ciągłe próby zapisywania ... ale mówisz że z programatora normalnie idzie ...


    No i nie zawisa, bo po zapisie włącza jeszcze jedną diodę.

    Zresztą, urządzenie, w całym dużym programie działa normalnie jakby zapisywało tyle że się to w eepromie nie pojawia...

    Jeszcze watchdoga włączę...

    Dodano po 1 [minuty]:

    sulfur napisał:
    Nie mam doświadczenia w eepromie, ale z tego co wiem, jak się zapisuje więcej bajtów, to pomiędzy bajtami należy trochę poczekać, ponieważ zapis trwa. Ile ? Nie wiem, wyczytałem to w jednym temacie na tym forum, zupełnie przez przypadek. Może w tym jest problem?


    Jest jeden bajt do testów i też nie działa. A czekanie na zakończenie poprzedniego zapisu jest i w datasheecie i znalazło się też u mnie.
  • #10 8193663
    acid12
    Poziom 21  
    spróbuj użyć funkcji z avr/eeprom.h

    eeprom_busy_wait()
    oraz
    eeprom_write_byte((uint8_t *__p, uint8_t __value)
    eeprom_read_byte (const uint8_t *__p)

    nie trzeba sie bawic w żadne rejestry etc
  • #11 8193752
    tmf
    VIP Zasłużony dla elektroda
    A ten kod w c to z jakimi opcjami optymalizacji kompilujesz? Bo jeśli nie -Os to może być problem z timingiem podczas zapisu do EECR. Pokaż wygenerowany kod assemblerowy dla tej sekcji. Zapomnij też o używaniu sei/cli - użyj ATOMIC_BLOCK. sei/cli może przez kompilator byc przeniesione tak, że wcale nie będzie obejmować sekcji którą zaznaczyłeś. Sprawdź też uiAddress - na pewno zawiera poprawny adres(0-511)?
  • #12 8193905
    PO.
    Poziom 20  
    -O0, bez optymalizacji jakby? Czy coś pomyliłem. Ale rada jest dobra, zaraz (dziś) sprawdzę na -Os...
  • #13 8215083
    PO.
    Poziom 20  
    apdejt:

    optymalizacja włączona na -Os pomogła i odbywa się wszystko bezboleśnie.
    Teraz pytanie dlaczego optymalizacja na -O0 ruszyła mi mój kod w taki sposób. Nie wiem tak naprawdę czy przestawiła cli() czy może wstawiła gdzieś coś, że nie dawało rady zmieścić się w limicie 4cykli przy ustawianiu flag zapisu.
    Przecież niby była wyłaczona? Czy coś pomyliłem?
  • #14 8215578
    tmf
    VIP Zasłużony dla elektroda
    Najprościej w pliku lst znajdź jak ten fragment został przetłumaczony na assembler. Zapewne nie zmieściłeś się w 4 cyklach. -O0 to brak optymalizacji, więc nie ma się czemu dziwić.
  • #15 8215760
    PO.
    Poziom 20  
    Poszukam. No dobra, ale kod macie, nie ma w nim co optymalizować a to zwykłe operacje bitowe - jak się nie zmieścić? Znaczy sprawdzę w wolnej chwili co on tam zrobił ale to szok ciężki dla mnie - tyle czytam że przy właczonych optymalizacjach są jazdy, a tu w drugą stronę...
  • #16 8215787
    tmf
    VIP Zasłużony dla elektroda
    Jak nie ma co optymalizować? Operacje logiczne powodują automatycznie promocję do integer. Stąd mimo, że EECR jest 8-bitowy, to pewnie suma jest wykonywana na 16-bitach. Potem kolejny odczyt EECR, znowu operacja logiczna. Gdybyś tylko zapisywał do EECR to może by przeszło.
    Co do optymalizacji - jazdy to są w programach, które są tak napisane, że najlepiej je od razu wrzucić do kosza :)
  • #17 8215806
    PO.
    Poziom 20  
    No to tego nie wiedziałem... Myślałem, że to co deklaruję pozostaje zadeklarowane a nie jeszcze zmiana z automatu - antyoptymalizacja ;) .

    Jest z tego nauka że w c i tak nie wiemy co się dzieje - nawet jak optymalizację wyłączymy i teoretycznie instrukcja po instrukcji leci. Nie chcę się przesiadać na asemblera ale nie chcę też takich niespodzianek :| .
  • #18 8215871
    tmf
    VIP Zasłużony dla elektroda
    PO. napisał:
    No to tego nie wiedziałem... Myślałem, że to co deklaruję pozostaje zadeklarowane a nie jeszcze zmiana z automatu - antyoptymalizacja ;) .

    Jest z tego nauka że w c i tak nie wiemy co się dzieje - nawet jak optymalizację wyłączymy i teoretycznie instrukcja po instrukcji leci. Nie chcę się przesiadać na asemblera ale nie chcę też takich niespodzianek :| .


    Jeśli nie chcesz takich "niespodzianek" to zabierz się w końcu za porządną książkę poświęconą podstawom C :) Naprawdę to nie jest "niespodzianka".

    Zobacz jak wygląda kod wygenerowany dla -O0 (zmieniłem stałe, bo akurat wrzuciłem to do programu, który piszę na ATMega128):
    
     EEAR=0x0020;
        9c40:	ee e3       	ldi	r30, 0x3E	; 62
        9c42:	f0 e0       	ldi	r31, 0x00	; 0
        9c44:	80 e2       	ldi	r24, 0x20	; 32
        9c46:	90 e0       	ldi	r25, 0x00	; 0
        9c48:	91 83       	std	Z+1, r25	; 0x01
        9c4a:	80 83       	st	Z, r24
     EEDR=0x32;
        9c4c:	ed e3       	ldi	r30, 0x3D	; 61
        9c4e:	f0 e0       	ldi	r31, 0x00	; 0
        9c50:	82 e3       	ldi	r24, 0x32	; 50
        9c52:	80 83       	st	Z, r24
     EECR|=(1<<EEMWE); // Write logical one to EEMWE
        9c54:	ac e3       	ldi	r26, 0x3C	; 60
        9c56:	b0 e0       	ldi	r27, 0x00	; 0
        9c58:	ec e3       	ldi	r30, 0x3C	; 60
        9c5a:	f0 e0       	ldi	r31, 0x00	; 0
        9c5c:	80 81       	ld	r24, Z
        9c5e:	84 60       	ori	r24, 0x04	; 4
        9c60:	8c 93       	st	X, r24
     EECR|=(1<<EEWE); // Write logical one to EEMWE 
        9c62:	ac e3       	ldi	r26, 0x3C	; 60
        9c64:	b0 e0       	ldi	r27, 0x00	; 0
        9c66:	ec e3       	ldi	r30, 0x3C	; 60
        9c68:	f0 e0       	ldi	r31, 0x00	; 0
        9c6a:	80 81       	ld	r24, Z
        9c6c:	82 60       	ori	r24, 0x02	; 2
        9c6e:	8c 93       	st	X, r24
    


    Ten sam kod dla -Os wygląda już przyzwoicie:
    
    EEAR=0x0020;
        54ae:	80 e2       	ldi	r24, 0x20	; 32
        54b0:	90 e0       	ldi	r25, 0x00	; 0
        54b2:	9f bb       	out	0x1f, r25	; 31
        54b4:	8e bb       	out	0x1e, r24	; 30
     EEDR=0x32;
        54b6:	82 e3       	ldi	r24, 0x32	; 50
        54b8:	8d bb       	out	0x1d, r24	; 29
     EECR|=(1<<EEMWE); // Write logical one to EEMWE
        54ba:	e2 9a       	sbi	0x1c, 2	; 28
     EECR|=(1<<EEWE); // Write logical one to EEMWE 
        54bc:	e1 9a       	sbi	0x1c, 1	; 28
    


    Jak widzisz dla -O0 były dobre powody, żeby to nie zadziałało. Jak widzisz kompilator (zgodnie ze specyfikacją C99) zrobił promocję do integer, po czym w celu dostępu do IO potraktował te adresy tak jakby były w SRAM (to jest ok). Dla wersji zoptymalizowanej usunięte zostały niepotrzebne instrukcje, w dodatku kompilator zauważył, że EECR leży w przestrzeni IO dostępnej dla SBI/CBI i zgodnie z oczekiwaniami zamienił to na 2 instrukcje, co dodatkowo umożliwiło wyrzucenie odczytu EECR i operacji logicznej (niepotrzebnej).
    A na przyszłość - zapomnij, że istnieją instrukcje sei/cli w AVR-libc (zresztą są poważne dyskusje, żeby ten support wyrzucić). Kompilator może swobodnie przemieszczać kod w ich obrębie, chyba, że dodasz dodatkowe bariery typu memory clobber. Stąd też używaj makra z nagłówka atomic.h (ATOMIC_BLOCK).
  • #19 8215974
    PO.
    Poziom 20  
    Jestem przerażony...

    OK, w tym miejscu akurat sei/cli można zamienić ale ja wachluję czasami przerwaniami w różnych miejscach programu i potrzebuję wiarygodnych instrukcji do tego - co mam zrobić, napisać sobie odpowiedniki fizycznie zmieniając bit w SREG? Poważnie pytam.

    Książka chyba niestety poczeka :( bo nie ma ani skąd ani czasu. Pozostanie wirtualne dokształcanie z doskoku. Po tym wątku już wiem że w życiu -Os nie wyłączę :) .
  • #20 8216050
    tmf
    VIP Zasłużony dla elektroda
    Właśnie do tego masz ATOMIC_BLOCK. Instrukcje w takim bloku będą chronione. Bardziej elegancko można to zrobić w C++, no ale to inna bajka.
REKLAMA