Elektroda.pl
Elektroda.pl
X

Search our partners

Find the latest content on electronic components. Datasheets.com
Elektroda.pl
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

Przenoszenie danych pomiędzy Flash Ram eeprom

ginar 29 Aug 2010 14:27 3295 26
  • #1
    ginar
    Level 21  
    Mam dużą strukturę (różne typy danych) ustawień, które muszą być zapisane w eeprom , w pamięci flash trzymam kopię ustawień domyślnych na wypadek gdyby użytkownik zechciał powrócić do ustawień 'default'.
    Problem polega na tym, że chciałbym w razie potrzeby skopiować strukturę z fash'a do eepromu pomijając kopiowanie całości do Ram - dlatego, że zajmie mi to 20% całej pamięci danych. Są jakieś eleganckie sposoby kopiowania blokowego pomiędzy różnymi typami pamięci?
    Z góry dzięki za porady.
    [28-30.06.2022, targi] PowerUP EXPO 2022 - zasilanie w elektronice. Zarejestruj się za darmo
  • #2
    szczepar
    Level 20  
    Zależy jaki procesor i czy masz 2 Wskaźniki DPTR
    Jeśli masz to piszesz wstawkę w asemblerze
    gdzie jeden wskaźnik odwołuje się do pamieci Flash , Drugi do Eeprom
    I kopiujesz to albo pojedyńczo albo blokami gdzie blok ma wielkość określoną przez ciebie.
    Ale ja nie wróżka. :)

    Bez typu procka , i pamięci to żadnej konkretnej porady nie dostaniesz.
    Pozdrawiam.

    @Down
    Atmegą się nie zajmowałem więc ci nie pomogę jako tako.
    Nierozumiem tylko czemu musisz przegrać Całą pamięć do RAM aby poźniej ją skopiować. Jest to dla mnie niezrozumiałe. Myśląć w ten sposób przegranie 50GB Dysku na drugi 50GB dysk wymagało by 50GB RAM :)

    Prawdopodobnie C jezyk więc
    potrzebujesz
    bufor o określonej wielkosci
    wskaźnik zapełnienia bufora (1 licznik)
    2 wskaźniki gdzie aktualnie zapisujesz odczytujesz.
    I jedziesz kolejno
    Odczyt Pamieci 1 do bufora do momentu zapełnienia bufora.
    Gdy zapełniony zapisujesz do drugiej pamięci.
    2 Wskaźniki pilnują ci (ty pilnujesz musisz je opisac oprogramować) abyś przepisywał do i z bufora odpowiednie dane.
    Ot i tyle.
    Wybacz że nie podaje ci gotowego C. :)
    Ale tu chodziło o wędkę a nie o rybę :)
  • #3
    ginar
    Level 21  
    uk to atmega164p, stosowania asm wolałbym uniknąć:)
  • #5
    tmf
    Moderator of Microcontroller designs
  • #6
    ginar
    Level 21  
    @szczepar
    Quote:
    Nierozumiem tylko czemu musisz przegrać Całą pamięć do RAM aby poźniej ją skopiować

    no właśnie tak nie chciałem
    @atom1477
    chyba jednak to nie jest złe pod warunkiem, że będę kopiował lokalnie w funkcji z falsh'a - do tej pory miałem globalnie zdef. w ramie i stąd ta duża jej zajętość.

    @tmf
    masz na myśli kopiowanie w pętli bajt po bajcie -od wskaźnika ustawionego na pierwszy element struktury do wsk. ust. na końcowy element? hmm w ten sposób musiałbym wiedzieć pod które dokładnie miejsce w eepromie mam to skopiować
    (teoretycznie wiem: deklaruje np. EEMEM struct sEeprom więc pewnie od adresu 0x00 )- co prawda chciałem to zrobić blokowo ale jest to jakieś rozwiązanie
  • #7
    tmf
    Moderator of Microcontroller designs
    A po co? Masz dwie struktury, do nich możesz uzyskać wskaźnik, prawda? Długość struktury uzyskujesz przez sizeof, robisz typecast wskaźnika na char*, co da ci dostęp do poszczególnych bajtów (albo robisz unie) i sobie kopiujesz bajt po bajcie. Jak do tej pory kopiowałeś strukturę do RAM? Przecież dokładnie tak samo, tyle, że używałeś odczytu blokowego - czyli ilestam razy odczytu bajtu.

    Dodano po 1 [minuty]:

    Oczywiście tak samo pobierasz wskaźnik do struktury w EEPROM w celu zapisu.
  • #9
    tmf
    Moderator of Microcontroller designs
  • #10
    ginar
    Level 21  
    Code:

    EEMEM struct _sWorkParameters *pEEPROM = &DefaultWorkParameters_inEEPROM;
    struct _sWorkParameters *pFLASH = &DefaultWorkParameters_inFLASH;

    Code:
       
    
       uint8_t uiStatusSREG = SREG;
       cli();

       uint8_t uiSize = sizeof(struct _sWorkParameters);
       unsigned char *cptrFLASH=(unsigned char*) pFLASH;
       unsigned char *cptrEEPROM=(unsigned char*) pEEPROM;
       for(uint16_t i=0; i<uiSize; i++)
       {
          eeprom_busy_wait();
          eeprom_write_byte (cptrEEPROM, pgm_read_byte(cptrFLASH));
          cptrEEPROM++;
          cptrFLASH++;
       }

       SREG|=uiStatusSREG&0x80;
    }


    w jaki sposób odczytać wskaźnik (nie zawartość) pEEPROM, - tak jak powyżej źle jest ustawiany cptrEEPROM w efekcie dane są przestawione o jeden adres wstecz
  • Helpful post
    #11
    tmf
    Moderator of Microcontroller designs
    Niepotrzebnie tyle razy rzutujesz, możesz od razu char *cptrEEPROM=(char*)&DefaultWorg.... zarówno dla FLASH jak i EEPROM. Swoją drogą to nie widzę powodu dla którego dane powyższy kod miałby źle ustawiać cptrEEPROM.
  • #12
    ginar
    Level 21  
    Code:
        char *cptrFLASH=( char*)&DefaultWorkParameters_inFLASH;
    
        char *cptrEEPROM=( char*)&DefaultWorkParameters_inEEPROM;

       unsigned char *cptrFLASH=(unsigned char*) pFLASH;
       unsigned char *cptrEEPROM=(unsigned char*) pEEPROM;


    to czy unsigned char czy char nie ma znaczenia
    w tym pierszym przypadku działa ok a wdrugim jest to przesunięcie o jeden czyli
    mniej wiecej:
    eeprom adress: 0 1 2 3 4 5..
    dane przed wywołaniem funkcji: 4 5 6 7 8 9 ..
    dane po wywołaniu: 5 6 7 8 9..

    edit
    po usunięciu atrybutu EEMEM z wsk. pEEPROM wszystko działa ok.
    Swoją drogą wydają mi się te atrybuty w avr gcc strasznie zagmatwane i korzystając z okazji
    Code:
     struct _sWorkParameters * EEMEM pEEPROM 
    czy to jest wsk umieszczony w eeprom
    a
    Code:
    EEMEM  struct _sWorkParameters * pEEPROM
    jest to wskaźnik w ramie do pamięci eeprom?

    Dzięki za pomoc
  • #13
    tmf
    Moderator of Microcontroller designs
    Jasne, że w tym wypadku unsigned nie ma znaczenia, użyłem char bo mniej pisania :) Oba zapisy powinny być równoważne, więc dziwi mnie, że w drugim przypadku ci to nie działa. No ale jeśli działa to pierwsze to problem z głowy :)
  • #14
    ginar
    Level 21  
    Jeszcze jedna sprawa...
    W jaki sposób zmusić linkera (z poziomu eclipsa) aby przy definicji danych przeznaczonych do pamięci eeprom typu np:
    Code:
    EEMEM struct _sWorkParameters DefaultWorkParameters_inEEPROM[...]

    umieścił je poczynając od zadanego adresu? Domyślnie wpisuje od komórki 0x00
    co nie jest zalecane
  • #15
    gaskoin
    Level 38  
    Poczytaj o parametrze --change-section, w eclipsie tego nie ustawisz, musisz ręcznie pogrzebać w makefilu.

    Dlaczego niby nie jest zalecane ?
  • #16
    ginar
    Level 21  
    nie zalecane min. dlatego, że w czasie resetu może dojśc do jej napisania - http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_eeprom_corruption

    chyba da radę to zrobić w eclipsie, bez grzebania w jego makefilu.
    W makefilu eclipsa jest
    Code:
    Lift.eep: Lift.elf
    
        @echo 'Create eeprom image (ihex format)'
        [b]-avr-objcopy -j .eeprom --no-change-warnings --change-section-lma .eeprom=0 -O ihex Lift.elf  "Lift.eep"[/b]
        @echo 'Finished building: $@'
        @echo '

    wydaje mi się, że to będzie odpowiedzialne za to
    --change-section-lma .eeprom=0
    a jest to edytowalne w jednej z zakładek.
  • #18
    ginar
    Level 21  
    podglądnąłem plik .map i okazuje się, że jednak kombinację z change-section nie przynosi pożądanego rezultatu tj. dane wgrywane do eepromu zaczynają się od adresu 0x00.
    W makefilu domyślną wartość:
    Code:
    # Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
    
    COFFCONVERT = $(OBJCOPY) --debugging
    COFFCONVERT += --change-section-address .data-0x800000
    COFFCONVERT += --change-section-address .bss-0x800000
    COFFCONVERT += --change-section-address .noinit-0x800000
    [b]COFFCONVERT += --change-section-address .eeprom-0x810000[/b]

    zamieniłem na
    Code:
    # Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
    
    COFFCONVERT = $(OBJCOPY) --debugging
    COFFCONVERT += --change-section-address .data-0x800000
    COFFCONVERT += --change-section-address .bss-0x800000
    COFFCONVERT += --change-section-address .noinit-0x800000
    [b]COFFCONVERT += --change-section-address .eeprom-0x810001[/b]

    ale po kompilacji plik .map wygląda zawsze tak samo:
    Code:
    Name             Origin             Length             Attributes
    
    text             0x00000000         0x00020000         xr
    data             0x00800060         0x0000ffa0         rw !x
    eeprom           0x00810000         0x00010000         rw !x
  • #19
    mirekk36
    Level 42  
    No rzeczywiście kombinacje aż w pliku makefile są potrzebne ?

    Można np. zdefiniować jako pierwszą zmienną w EEPROM albo jakąś wieobajtową np uint32_t albo nawet małą pustą i nie potrzebną w programie strukturkę ??


    Code:
    typedef struct {
    
      uint32_t dum1;
      uint32_t dum2;
      uint32_t dum3;
    } TDUMY;

    TDUMY dumy EEPROM;     // pusta struktura jako pierwsza zdefiniowana w EEPROM
    MYPARAMS myparams EEPROM; // tu już twoje struktury


    i już masz pominięty początkowy jakiś tam obszar (tutaj konkretnie 12 pierwszych bajtów) - jaki cię interesuje jak się uprzesz go pomijać.

    Dodano po 5 [minuty]:

    A kopiowanie bajt po bajcie?

    jeśli masz jakąś strukturę typu TMYPARAMS to zdefiniuj sobie teraz ładnie unię:

    Code:

    typedef union {
       uint8_t byte_idx[ sizeof( TMYPARAMS) ];
       TMYPARAMS myparams;
    } TU;


    a później w kodzie przelatujesz po kolei wszystkie bajty indeksując po tablicy byte_idx[]
  • Helpful post
    #20
    tmf
    Moderator of Microcontroller designs
    Nie mozna tak zrobic, bo nie masz gwarancji gdzie linker umiesci zmienna - zwykle robi to w kolejnosci deklaracji, ale wcale nie musi. Zreszta to moze sie popsuc nawet i bez ingerencji linkera - wystarczy, ze ktorys naglowek stworzy zmienna w EEPROM.
    Sekcje pamieci EEPROM mozna przesunac przekazujac linkerowi polecenie --section-start (pamietaj o tym, ze start sekcji EEPROM to adres 0x810000.
  • #21
    mirekk36
    Level 42  
    ginar --> możesz zrobić jak chcesz (jeśli chodzi o pominięcie iluś tam początkowych bajtów), w tym przypadku także spokojnie, tak jak pisałem wyżej i to zadziała pod warunkiem, że na wszelki wypadek po kompilacji sprawdzisz sobie w pliku *.map w jakim porządku umieścił ci linker te struktury. I wcale nie trzeba się obawiać tego że ci "COŚ" tam namiesza bo jak się robi coś z głową to nic ci się nie stanie.

    Generalnie to co opisałem to wynik działania oczywiście ostatniej wersji AVRGCC z 2010r i jasna sprawa, że inne (poprzednie wersje (linkery)) mogą się nieco inaczej zachować - teoretycznie. Jednak z czystej praktyki i sprawdzania pliku *.map mogę powiedzieć, że w 99,9999% przypadków zobaczysz w pliku MAP i fizycznym EEPROM'ie poukładane te 2 struktury w takiej kolejności dokładnie jak je umieściłeś w kodzie - jesli znajdują się tylko ich definicje w pliku *.c. Jeżeli zaś użyjesz w jakimś pliku nagłówkowym *.h samych deklaracji tych struktur ze słówkiem extern na początku to wg moich obserwacji zdecyduje kolejność własnie umieszczenia w tym pliku nagłówkowym a nie w pliku *.c. Jak pisałem możesz sobie zrobic proste próbu kompilacji:

    Code:
    #include <avr/io.h>
    
    #include <avr/eeprom.h>

    #define EEMEM __attribute__((section(".eeprom")))

    typedef struct {
       uint32_t dummy1;
       uint32_t dummy2;
       uint32_t dummy3;
    } TDUMMY;

    typedef struct {
       char       nazwa[20];
       uint16_t    db_rec_nr;
       uint8_t    adres;
       uint8_t    tryb_pracy;
       int       tmp_off;
       int       tmp_dzien;
       int       tmp_noc;
       int       tmp_now;
       uint16_t    time_dzien;
       uint16_t    time_noc;
       uint8_t    ds_adr[8];
       uint8_t    ds_present;
    } TSEKCJA;

    typedef struct {
       TSEKCJA idx[4];
    } TMEM;

    // tutaj kolejność będzie odwzorowana w EEPROM (jeśli nie ma nagłówka z deklaracjami)
    TDUMMY eem_dummy EEMEM;
    TMEM eem_sekcja EEMEM;

    int main(void) {


       while(1);
    }


    w pliku *.map będzie to wyglądało tak:

    Quote:
    .eeprom 0x00810000 0xc0
    *(.eeprom*)
    .eeprom 0x00810000 0xc0 ./main.o
    0x0081000c eem_sekcja
    0x00810000 eem_dummy
    0x008100c0 __eeprom_end = .


    albo tak, jak niżej jeśli w źródłowym wyżej pliku zamienisz kolejność definicji:

    Quote:
    .eeprom 0x00810000 0xc0
    *(.eeprom*)
    .eeprom 0x00810000 0xc0 ./main.o
    0x00810000 eem_sekcja
    0x008100b4 eem_dummy
    0x008100c0 __eeprom_end = .


    widać jak na dłoni, że zmienia się kolejność w EEPROM zgodnie z tym co pisałem.

    Poza tym ja tam nigdy nie spotykam się ze zjawiskami nadprzyrodzonymi, że mi kompilator "SAM COŚ TAM ZROBI" , że SAM MI WSTAWI JAKIŚ NAGŁÓWEK, który z kolei "namiesza" w zmiennych EEPROM. Co to za pisanie programu, że używałbyś jakichś tam nagłówków, które nie wiesz co robią.


    Nie zmienia to faktu, że jest jeszcze inny sposób na to i pewniejszy niż opisany powyżej biorąc pod uwagę, że może skompilujesz to różnie datowanymi kompilatorami. Ale też sposób bez konieczności deklarowania początku sekcji .eeprom w pliku makefile. Polega on na tym, że to w swojej własnej strukturze z parametrami tworzysz jako pierwszy - taki pusty parametr np tablicę dummy[50] i już masz przesunięcie o 50 bajtów od początku pamięci EEPROM jeśli tylko tą jedną wielką strukturę trzymasz a w niej wszystkie zmienne. Zresztą ten sposób jest zdecydowanie NAJLEPSZY !!!


    A trzeci to oczywiście podanie jawnie początku sekcji .eeprom, chociaż nie trzeba tego robić w makefile jeśli działasz pod AVrStudio lub Eclipse ale należy tylko wejść w opcje linkera i dodać po prostu konkretnie taki parametr jak poniżej jeśli chcesz uzyskać np przesunięcie od początku o np 5 bajtów:

    Code:
    -Wl,--section-start=.eeprom=0x810005
    wtedy w pliku *.map zobaczysz:


    Quote:
    .eeprom 0x00810005 0xc0
    *(.eeprom*)
    .eeprom 0x00810005 0xc0 ./main.o
    0x00810005 eem_sekcja
    0x008100b9 eem_dummy
    0x008100c5 __eeprom_end = .
  • #22
    tmf
    Moderator of Microcontroller designs
    Tylko nie wiem po co kombinować, skoro rozwiązanie jest proste i skuteczne w 100%. Definiowanie struktur z niewykorzystanym bajtem nic nie rozwiązuje, bo jak pisałem taka struktura nie musi się znaleźć na początku EEPROM. Po prostu inne dane się tam znajdą, które już chronione nie będą. Co do dołączania - jakby kolega pisał poważne projekty, gdzie dołączanych jest sporo plików, nie tylko nagłówków, ale źródłowych, które umieszczają zmienne w EEPROM to by nie pisał takich bajek. Co do działania linkera to też polecam manuala. C to nie Bascom.
  • #23
    mirekk36
    Level 42  
    tmf wrote:
    Co do dołączania - jakby kolega pisał poważne projekty, gdzie dołączanych jest sporo plików, nie tylko nagłówków, ale źródłowych, które umieszczają zmienne w EEPROM to by nie pisał takich bajek. Co do działania linkera to też polecam manuala. C to nie Bascom.


    hehehe co? jak ci brak argumentów do dyskusji to zwykle sięgasz po opowieści o swoich wyimaginowanych "poważnych" projektach? :) Cierpisz dziecko na jakieś paranoidalne lęki, wystarczy przypomnieć niedawny temat z triakami lub wiele podobnych, gdzie wychodzi z ciebie przede wszystkim prostak, który nie potrafi kulturalnie dyskutować. Przez to wiele tematów na takim zacnym forum robi się śmietnikiem, gdzie widać tylko kłótnie z tobą lub czcze przechwałki i samozadowolenie narcyza.

    tmf wrote:
    Tylko nie wiem po co kombinować...
    Trochę za mało wiesz, żeby kombinować to fakt, lub podejmować samodzielne działania. Jeśli byś nieopatrznie przetłumaczył w jakimś manualu że powinieneś wyskoczyć przez okno, to zapewne już byś to zrobił bo po co kombinować? hehehe co za gostek ;)

    tmf wrote:
    ... bo jak pisałem taka struktura nie musi się znaleźć na początku EEPROM. Po prostu inne dane się tam znajdą, które już chronione nie będą.


    Jakie inne dane??? To w twoich "poważnych" projektach jakieś tam dane "rodzą" się samoistnie???? nie panujesz nad tym ??? więc to chyba ty jeszcze jedną nogą siedzisz w innym języku programowania? ;) O czym więc ty tu gadasz, skoro nie panujesz nad tym co robisz? Może czas wrócić do Bascoma skoro C cię przerasta?

    Jeśli będzie jedna tylko struktura - to pojawi się ona na początku obszaru EEPROM ! , doczytaj dokumentację i napisz kilka troszkę poważniejszych niż swoje "poważne" programy, zamiast wciskać swoje "kity" o samoistnym pojawianiu się danych w EEPROM w twoich "dużych" projektach. Bredzisz, po prostu bredzisz ;)
  • #24
    psine.pl

    Level 29  
    Moderated By inventco.eu:

    Panowie , Panowie, Koledzy...
    Proszę troszkę spokojniej.
    Jako osoby tak wysoko postawione powinniście dawać przykład.
    A tym czasem zachowujecie się jak dzieci. I kto jest mądrzejszy.
    No i sypią się raporty.
    Dogadajcie się na PW a nie na forum tworząc "wojnę" zresztą nie pierwszy raz.

  • #25
    ginar
    Level 21  
    Wydaje mi się, że im więcej sposobów na rozwiązanie problemu tym lepiej i wdawanie się w kłótnie o wyższości jednego nad drugim nie ma specjalnego sensu..

    Zdefiniowanie 'pustego' bajtu w celu przesunięcia obszaru oczywiście działa.

    Co do drugiego sposobu:
    Code:
    -Wl,--section-start=.eeprom=0x810000+offset
    z poziomu Eclipsa
    Opcje linkera są zablokowane:
    Przenoszenie danych pomiędzy Flash Ram eeprom
    a modyfikacja samego makefila (w projekcie eclipsa) nie ma sensu bo jest on automatycznie generowany... no chyba, że się mylę
  • Helpful post
    #26
    mirekk36
    Level 42  
    Masz rację, że nie ma sensu zmieniać ręcznie makefile (choć i takie są możliwości) .... jednak opcje linkera nie są zablokowane wstawiasz je o oczko niżej w drzewku niż to pokazałeś

    Dodano po 2 [minuty]:

    dokładniej mówiąc w tym miejscu:

    Przenoszenie danych pomiędzy Flash Ram eeprom
  • #27
    ginar
    Level 21  
    Podsumowując - oba sposoby działają poprawnie a najlepszym sposobem sprawdzenia to przeglądnięcie pliku .map na pozycji *(.eeprom*)
    Dzięki.