Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[AVR][WinAVR][C] zapis struktury do EEPROM

markoll2 24 Sty 2010 09:51 4905 24
  • #1 24 Sty 2010 09:51
    markoll2
    Poziom 10  

    Witam, mam problem z zapisem ciągu znaków do pamięci eeprom (prawdopodobnie mam namieszane coś z wskaźnikami, lecz nie umiem sobie poradzić.
    Mam taką strukturę:

    Code:

    struct _CONFIG {
         uint32_t parametr1;
         uint32_t parametr2;         
         uint32_t *opis;   
    };


    jak to zapisać do eeprom ? Na co to skonwertować ?

    0 24
  • #2 24 Sty 2010 10:00
    _Robak_
    Poziom 33  

    Struktury jako takiej nie zapiszesz. Musisz rozbic to na poszczegolne bajty, zapamietac i potem sobie to wszystko odtowrzyc. Czyli musisz zapamietac 12 bajtow.

    0
  • #3 24 Sty 2010 10:21
    markoll2
    Poziom 10  

    czyli ale jak zapisuję

    Code:

    NutNvMemSave(1024, &_CONFIG, sizeof(_CONFIG));


    to mi zapisze i mogę odczytać wszystko poza pozycją opis :(
    w pozycji opis są same losowe znaczki

    0
  • #4 24 Sty 2010 10:35
    _Robak_
    Poziom 33  

    Przeciez opis jest wskaznikiem. Nie wiem jak dziala ta funkcja, ale moge sie domyslac ze w tym momencie zapisuje ci tylko adres pod ktorym jest pole opis, a nie wartosc samego pola.

    0
  • #5 24 Sty 2010 10:47
    markoll2
    Poziom 10  

    NutNvMemSave działa jak taponiżej tylo że mam możliwość zdefiniowania rodzaju podłączone pamięci (zewnętrzna, wewnętrzna)

    Code:
    int OnChipNvMemSave(unsigned int addr, CONST void *buff, size_t len)
    
    00097 {
    00098     uint8_t *cp;
    00099     size_t i;
    00100
    00101     for (cp = (uint8_t *) buff, i = 0; i < len; cp++, i++) {
    00102 #if defined(__IMAGECRAFT__)
    00103         if (EEPROMread((int) (addr + i)) != *cp) {
    00104             EEPROMwrite((int) (addr + i), *cp);
    00105         }
    00106 #elif defined(__GNUC__)
    00107         if (eeprom_read_byte((uint8_t *) (addr + i)) != *cp) {
    00108             eeprom_write_byte((uint8_t *) (addr + i), *cp);
    00109         }
    00110 #endif
    00111     }
    00112     return 0;
    00113 }

    0
  • #6 24 Sty 2010 11:31
    _Robak_
    Poziom 33  

    Zapisujesz wskaznik a nie wartosc spod wskaznika. Poczytaj troche o wskaznikach, to powinno sie wyjasnic.

    0
  • #7 24 Sty 2010 12:07
    markoll2
    Poziom 10  

    Noo właśnie od 2 dni stale czytam ale nie bardzo mi działa.
    To może inaczej
    jak zapisać jakiś stały ciąg umieszczony w tablicy np. char Nazwa[9]; ?

    0
  • #8 24 Sty 2010 14:08
    tmf
    Moderator Mikrokontrolery Projektowanie

    Jezeli ciag jest staly to zadeklaruj go z atrybutem EMEM, analogicznie jak dla FLASH PROGMEM. A jesli chcesz go kopiowac to pobierz jego adres (&Nazwa) i wykorzystaj odpowiednia funkcje kopiowania blokow pamieci.

    0
  • #9 24 Sty 2010 14:29
    markoll2
    Poziom 10  

    to wiem, lecz ciąg mam otrzymywać z formularza i będzie lądował w tablicy (np. char[10].)
    do eeprom zapisuje zmienne uint_8, a ciąg otrzymuję jako char ?

    0
  • #10 24 Sty 2010 14:47
    mirekk36
    Poziom 42  

    Czy nie znasz lepszej funkcji do zapisu dowolnego bloku pamięci EEPROM w tym także struktury?

    Code:
    typedef struct  { 
    
         uint32_t parametr1;
         uint32_t parametr2;         
         uint32_t *opis;   
    } _CONFIG;

    _CONFIG ee_my_config EEMEM;    // definiujemy strukturę w pamięci EEPROM
    _CONFIG ram_my_config EEMEM;  // definiujemy strukturę w pamięci RAM

    teraz zapis do EEPROM:

    Code:
    eeprom_write_block(&ram_my_config, &ee_my_config, sizeof(ram_my_config));


    albo odczyt:

    Code:
    eeprom_read_block(&ee_my_config, &ram_my_config, sizeof(ram_my_config));


    szybko, łatwo, przejrzyście i przyjemnie

    (oczywiście pomijam to, że skoro trzymasz wskaźnik do opisu to zapisujesz tylko 32bitowy adres - i na prawdę nie wiem po co aż 32bitowy)

    0
  • #11 24 Sty 2010 15:10
    markoll2
    Poziom 10  

    faktycznie można blokami - spróbuje, lecz niestety coś się pogubiłem w zmiennych :(
    ja powinna wyglądać funkcja która jako parametr dostanie tekst i zapisze go w eeprom
    np:
    void SaveText(......... Text) - jaką zmienną (uint8_t*)
    {
    ...... (jak dokonać konwersji jeśli trzeba char uint8_t - jeśli trzeba)
    }
    Ma ktoś może taką przykładową procedurę zapisu ciągu znaków ?
    mechanizm zapisu można pominąć bardziej mi zależy schemacie jak dokonać konwersji zmiennych, no ale jeśli ktoś ma taką procedurę lub może napisać bedę wdzięczny.

    0
  • #12 24 Sty 2010 15:16
    mirekk36
    Poziom 42  

    markoll2 --> ty się dlatego w tym wszystkim gubisz bo chcesz na upartego zapisywać do eepromu jakieś zmiennej wielkości łańcuchy pod bezwzględne adresy w pamięci EEPROM. To szybko doprowadzi cię do zguby albo na skraj szaleństwa ;)

    Zamiast tego przygotuj sobie strukturę jak powyżej i zamiast umieszczać w niej wskaźnik do opisu tekstowego, umieść tam jedną, dwie czy kilka tablic na twoje teksty. A potem będziesz do nich zapisywał ale już nie korzystając z bezwględnych adresów w pamięci eeprom tylko poprzez wskaźniki do struktury

    0
  • #13 24 Sty 2010 15:28
    markoll2
    Poziom 10  

    do szaleństwa to mnie już doprowadziło :P.

    Potrzebuje zapisać w pamięci eeprom od adresu 1024 strukturę w której bedą zdefiniowane adres IP, potrzebuję też pole na przechowanie adresu serwera SNTP w postaci nazwy a nie IP. i właśnie z tym mam problem bo IP mi się ładnie zapisuje i odczytuje ale za cholerę nie moge sobie poradzić z zapisem nazwy.

    Nazwę najlepiej będzie przechowywać w tablicy o stałej długości np30 elementów.Teraz jeśli chcę tam przechowywać tam text to jaką zmienną dać ? uint8_t nazwa[30] ? czy jako char ?

    Faktycznie pogubiłem się zaczynam w C, lecz chcę się uczyć na żywym przykładzie sam system na którym buduje to Ethernut z Nut/Os jest dość fajnie i prosto zrobiony. A tu widzisz taka prosta sprawa i nie bardzo wiem jak to ugryźć.

    0
  • #14 24 Sty 2010 15:37
    _Robak_
    Poziom 33  

    Problem wynika z tego ze, jak widac, ethernut ma wbudowane funkcje z ktorych korzystasz, nie bardzo wiedzac co do konca one robia ;) Char to signed int 8 czyli int8_t, natomiast uint8_t jest unsigned. Nazwy nie sa ze znakiem, wiec daj uint8_t :)

    0
  • #15 24 Sty 2010 16:01
    Freddie Chopin
    Specjalista - Mikrokontrolery

    _Robak_ napisał:
    Nazwy nie sa ze znakiem, wiec daj uint8_t :)

    Mylisz się - typ char jest (technicznie rzecz ujmując) czym innym niż unsigned char albo signed char. Każda funkcja standardowa operująca na napisach / znakach przyjmuje char / char *, więc podanie jej uint8_t albo int8_t tak czy siak wywoła warninga. Ze swojej strony radziłbym trzymać się tego standardu - napis = char i koniec.

    4\/3!!

    0
  • #16 24 Sty 2010 16:10
    _Robak_
    Poziom 33  

    Hmm otwieram stdlib.h i mamy takie cos

    Code:

    /** \ingroup avr_stdint
        8-bit signed type. */

    typedef signed char int8_t;

    /** \ingroup avr_stdint
        8-bit unsigned type. */

    typedef unsigned char uint8_t;

    /** \ingroup avr_stdint
        16-bit signed type. */

    typedef signed int int16_t;

    /** \ingroup avr_stdint
        16-bit unsigned type. */

    typedef unsigned int uint16_t;

    /** \ingroup avr_stdint
        32-bit signed type. */

    typedef signed long int int32_t;

    /** \ingroup avr_stdint
        32-bit unsigned type. */

    Czyli chyba jednak jest to samo ;) Chyba ze jest cos czego nie wiem :)

    0
  • #17 24 Sty 2010 16:15
    Balu
    Poziom 38  

    Freddie Chopin napisał:
    _Robak_ napisał:
    Nazwy nie sa ze znakiem, wiec daj uint8_t :)

    Mylisz się - typ char jest (technicznie rzecz ujmując) czym innym niż unsigned char albo signed char.

    Gdzie masz tam napisane, że to sam char?:>

    0
  • #18 24 Sty 2010 16:51
    _Robak_
    Poziom 33  

    Ahhh w ogole zle przeczytalem post Freddiego ;)

    0
  • #19 24 Sty 2010 18:34
    Freddie Chopin
    Specjalista - Mikrokontrolery

    Balu napisał:
    Gdzie masz tam napisane, że to sam char?:>


    Tutaj:

    _Robak_ napisał:
    Char to signed int 8 czyli int8_t, natomiast uint8_t jest unsigned. Nazwy nie sa ze znakiem, wiec daj uint8_t :)


    4\/3!!

    0
  • #20 26 Sty 2010 20:28
    rpal
    Poziom 27  

    ja bym kol. markoll poradził aby, jeśli nie chce operować wskaźnikami do struktury użył sobie unii wg np. takiej deklaracji

    Code:

    union {   
       struct {
           unsigned long int parametr1;
            unsigned long int parametr2;         
            unsigned long int *opis;   
       } _CONFIG ;
       unsigned char tbl[12];
    }Test;

    wówczas operując elementem unii jakim jest tablica, poprzez jej kolejny indeks, będziesz miał dostęp do zawartości kolejnych bajtów danych skladajacych się na strukturę. Bez wnikania jakiego rodzaju jest to element. Ważne aby wiedzieć ile bajtów pamięci on zajmuje. Pamięci, nawet gram więcej nie zużyjesz a wygoda dość poważna. Możesz więc sobie każdą zmienną "przerobić" na liczbę 8bitową bez zawracania sobie głowy czymś takim jak konwersja danych bo zrobi to za ciebie kompilator. Ważne tylko aby poprzez zapisywanie do tablicy danych, potem poprawnie nadać wartości , elementom struktury.

    0
  • #21 26 Sty 2010 21:51
    Freddie Chopin
    Specjalista - Mikrokontrolery

    Eeee... A po co, skoro i tak zapis do EEPROMu realizowany jest blokowo? A nawet jeśli by nie był, to wystarczy zrobić sobie funkcję, która ten zapis będzie realizowała właśnie w taki sposób?

    Tak czy siak nie rozwiązuje to problemu autora, ponieważ problem ten jest dosyć skomplikowany [; Ze swojej strony proponowałbym tablicę na takie napisy użytkownika w EEPROMie, niestety tablica taka musiałaby mieć ograniczoną długość (trzeba założyć, że ciągi nie będą dłuższe niż x znaków), bo rozwiązanie ze zmienną długością i bez marnowania miejsca zahacza mocno o dynamiczną alokację pamięci, która do tego jest nieulotna i zaczyna się robić niezły hardcore. Anyway - po zapisaniu sobie napisu do pierwszego wolnego elementu tablicy wystarczy operować nie "wskaźnikiem" a indexem tego elementu i właśnie w takiej postaci (z indexem) zapisać strukturę do EEPROMu. Oczywiście wtedy "odczyt" takiej struktury będzie działał inaczej niż odczyt tej ze wskaźnikiem.

    4\/3!!

    0
  • #22 26 Sty 2010 22:41
    krzemowy
    Poziom 19  

    Hm, nie wiem czy to coś pomoże, ale w jednym takim programie miałem struktury zapisane w pamięci programu. Zmieniłem na bardzo szybko co trzeba, całość kompiluje się i jest generowany plik wsadowy do EEPROMu - nie wiem czy to jest poprawne, nie mam jak teraz tego sprawdzić.

    Plik C:

    Code:
    #include <avr/eeprom.h>
    
    #include "defs.h"
    #include "par1.h"


    const wspolrz EEMEM strony[3] =
    {0, 0,  13, 0,  28, 0,   0, 1,  13, 1,  28, 1,  0, 2,  13, 2,  28, 2,  28, 3,
     0, 0,  16, 0,  28, 0,   0, 1,  14, 1,  28, 1,  0, 2,  22, 2,  29, 3,   0, 0,
     0, 0,  25, 0,   0, 1,   0, 2,  30, 3,  26, 1,  0, 0,   0, 0,   0, 0,   0, 0,};

    const unsigned char EEMEM wybor[3][10] =
    {13,     3,    4,    5,    2,   10,    6,    7,    1,    0,
     13,     8,    9,   12,   11,   14,   16,   19,    0, 0xFF,
     13,    15,   17,   18,    0,   16, 0xFF, 0xFF, 0xFF, 0xFF,};

    const EEMEM struct parametry par[20] =
    {"Sec:",       Secl,          1,  3,      1,   0,     "s", 0,
    "ATM:",        BaroADC,       1,  3,      1,   0,   "kPa", 0,
    "MAP: ",       MapADC,        1,  3,      1,   0,   "kPa", 0,
    "IAT: ",       MatADC,        1,  3,      1, -40, "\337C", 0,
    "CLT:",        CltADC,        1,  3,      1, -40, "\337C", 0,
    "TPS: ",       TpsADC,        1,  3,  0.393,   0,     "%", 0,
    "BAT:",        BatADC,        1,  4, 1.0874,   0,     "V", 1,
    "EGO:",        EgoADC,        1,  4,  1.961,   0,     "V", 2,
    "EgoC:",       EgoCorrection, 1,  3,      1,   0,     "%", 0,




    "AirC:",       AirCorrection, 1,  3,      1,   0,     "%", 0,
    "PW:",         Pw1,           1,  4,      1,   0,    "ms", 1,
    "GammaE:",     GammaEnrich,   1,  3,      1,   0,     "%", 0,
    "VEcurr:",     VeCurr1,       1,  3,      1,   0,     "%", 0,
    "RPM:",        RpmL,          2,  4,      1,   0,   "rpm", 0,
    "Alfa:",       Alfa,          1,  3,      1,   0,  "\337", 0,
    "ImpLen:",     ImpLenL,       2,  4,      4,   0, "\xE4s", 0,
    "LSync: ",     LostSync,      1,  3,      1,   0,      "", 0,
    "Time1:",      Czas1A,        4, 12,      1,   0,      "", 0,
    "Time2:",      Czas2A,        4, 12,      1,   0,      "", 0,
    "StepperPos:", StepperPos,    1,  3,      1,   0,      "", 0};


    Plik H:
    Code:
    #include <avr/eeprom.h>
    

    typedef struct xy
    {
       unsigned char x;
       unsigned char y;
    } wspolrz[10];

    struct parametry
    {
       char nazwa[12];
       unsigned char adres;
       unsigned char rozmiar;
       unsigned char rozmiar_pola;
       float mnoznik;
       char offset;
       char jednostka[3];
       unsigned char przecinek;
    };

    const struct parametry par[20];
    const wspolrz strony[3];
    const unsigned char wybor[3][10];

    0
  • #23 26 Sty 2010 22:58
    rpal
    Poziom 27  

    Autor nie pisze o jaki mu eeprom chodzi, wszyscy tu zakładają że wewnętrzny a może miał na mysli jakiś z serii SPI albo I2C? I może co najważniejsze czemu ten zapis ma służyć i czy ma być aktualizowany a jesli tak to jak często ?

    0
  • #24 31 Sty 2010 18:00
    markoll2
    Poziom 10  

    OK, problem rozwiązany. Zrobiłem strukturę o stałym rozmiarze i bez problemu poszło :)
    A chodziło o EEprom wewnętrzny.

    0
  • #25 27 Sie 2010 20:47
    ginar
    Poziom 21  

    Odwołując się do tego co napisał mirekk36 próbowałem ominąć funkcję typu

    Code:
    eeprom_write_block(...) 

    def. przykładowo (globalnie):
    Code:
    EEMEM struct _sEEPROM_default sEEPROM_default = {0x23, {1,2,3,4,5,6}};
    
    EEMEM struct _sEEPROM_default *pEEPROM_default = &sEEPROM_default;

    z symulacji wychodzi, że jest ta struktura umieszczona jak powinna, ale już próba odczytu:
    Code:
    unsigned char aaa = pEEPROM_default->ucActiveNumberRing;

    daje zły wynik (0). Zastanawiam się dlaczego wskaźnik zadeklarowany z tym samym atrybutem jakby nie odczytywał pamięci eeprom. Czy jedynym (najlepszym) wyjściem to skopiować strukturę do Ram'u używając eeprom_write/read_block i dopiero tam działać ?
    ___________
    edit
    ano tak, zapewne trzeba ten wskaźnik odczytać funkcją uint8_t eeprom_read_byte
    czyli nic z tego.

    0