реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> Работа с EEPROM в WinAVR
PhX
сообщение Jan 5 2009, 07:25
Сообщение #1


Местный
***

Группа: Свой
Сообщений: 473
Регистрация: 10-09-06
Из: Тольятти. Самарская обл.
Пользователь №: 20 249



Добрый день!

Встала проблема – сохранять и затем читать несколько переменных (10-15) в/из EEPROM. Посмотрел примеры здесь, но не понравилось, как-то громоздко получается, байты считать приходится... Если кто сталкивался, подскажите нет ли решений поэлегантней?

Пусть набор переменных будет такой:
Код
uint8_t a1;
double a2;
uint16_t a3;


Заранее спасибо.

p.s. Компилятор Winavr, камень atmega128


--------------------
Если все, то не я...
Go to the top of the page
 
+Quote Post
korobov_michael
сообщение Jan 5 2009, 07:59
Сообщение #2


Частый гость
**

Группа: Свой
Сообщений: 118
Регистрация: 11-03-07
Из: Украина, Харьков
Пользователь №: 26 059



По идее должен быть квалификатор, указывающий способ компиляции соответствующей переменной. К сожалению, не знаю как это у WinAVR, у IAR это квалификатор __eeprom:
Код
__eeprom int i, j;
__eeprom int k @0x14;


Вторая строка показывает как расположить переменную в заданном месте.
Уверен, что у WinAVR есть подобная штука
Успехов

Сообщение отредактировал korobov_michael - Jan 5 2009, 08:01
Go to the top of the page
 
+Quote Post
ReAl
сообщение Jan 5 2009, 08:20
Сообщение #3


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(PhX @ Jan 5 2009, 09:25) *
Встала проблема – сохранять и затем читать несколько переменных (10-15) в/из EEPROM.
...
p.s. Компилятор Winavr, камень atmega128


Ну в самом простом виде как-то так (несколько переменных независимо от места хранения, удобно группировать по смыслу):

Код
#include <stdint.h>

#include <avr/eeprom.h>

typedef struct {
    uint8_t a;
    uint16_t b;
    float f;
} config;

config cfg;

config ee_cfg EEMEM =
{
    12, 1078, 3.5
};

uint16_t ee_u EEMEM = 65000;

float ff;
uint16_t u;

uint16_t foo(void)
{
    ff = 7.5;
    eeprom_read_block( &cfg, &ee_cfg, sizeof(cfg) );        // можно всю структуру
    eeprom_write_block( &ff, &ee_cfg.f, sizeof(float) );    // можно одно поле
    uu = eeprom_read_word( &ee_cfg.b );    
    return eeprom_read_word( &ee_u);            // само собой, можно и одночные переменные
}


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Jan 5 2009, 09:02
Сообщение #4


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(ReAl @ Jan 5 2009, 12:20) *
Ну в самом простом виде как-то так (несколько переменных независимо от места хранения, удобно группировать по смыслу):

Несколько уточнений.
1. На кой икс держать множество инлайновых вызовов eeprom_read_*** ?
2. eeprom_write_block() туповат - придется переписать, чтобы не трогал ячейки, в которых нет изменений.
3. После хорошего совета здесь делаю так:
Код
//все, что в еепроме, тотально объединено в структуру
typedef struct
{
****
} paramset_t;
// __MAIN__ определен там, где у нас main()
#ifdef __MAIN__
EEMEM paramset_t paramset = {большой блок инициализации};
#else
extern paramset_t paramset;
#endif
Go to the top of the page
 
+Quote Post
ReAl
сообщение Jan 5 2009, 14:58
Сообщение #5


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(_Pasha @ Jan 5 2009, 11:02) *
1. На кой икс держать множество инлайновых вызовов eeprom_read_*** ?
Я всего лишь показал, как можно обращаться и к структуре целиком и к отдельному её полю и к независимой переменной. И в комментариях отметил, что можно так, а можно сяк.

Цитата(_Pasha @ Jan 5 2009, 11:02) *
2. eeprom_write_block() туповат - придется переписать, чтобы не трогал ячейки, в которых нет изменений.
"а ещё они гнутся и сваливаются", т.е. "а ещё eeprom_write_block() останаваливает работу всего, кроме обработчиков прерываний, на время записи".
Я же говорю - пример в самом простом виде, ведь можно и так:
Код
void
eeprom_manager::write( const void *buf, uint16_t addr, uint16_t len)
{
    ee_guard pg; // тута мьютекс спрятан

    const uint8_t *ptr = reinterpret_cast< const uint8_t* >(buf);

    do {
        uint8_t to_write = *ptr++;
        EEAR = addr++;
        EECR |= 1 << EERE;
        if( EEDR == to_write)
            continue;

        write_done.Clear();
        EEDR = to_write;
        {
            TCritSect cs;
            EECR |= 1 << EEMWE;
            EECR |= 1 << EEWE;
            EECR |= 1 << EERIE;
        }
        write_done.Wait();
    } while( --len);
}


OS_INTERRUPT void
EE_READY_vect()
{
    OS::TISRW isrw;
    EECR &= ~(1 << EERIE);
    eeprom_manager::write_done.SignalISR();
}


Цитата(_Pasha @ Jan 5 2009, 11:02) *
3. После хорошего совета здесь делаю так:
Код
//все, что в еепроме, тотально объединено в структуру
typedef struct
{
****
} paramset_t;
// __MAIN__ определен там, где у нас main()
#ifdef __MAIN__
EEMEM paramset_t paramset = {большой блок инициализации};
#else
extern paramset_t paramset;
#endif
Я нарисовал выше и структуру, и "большой" (на все три поля структуры) блок инициализации. Единственное отличие - в примере всё как бы в одном файле показал.


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
singlskv
сообщение Jan 5 2009, 21:18
Сообщение #6


дятел
*****

Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065



Цитата(ReAl @ Jan 5 2009, 17:58) *
"а ещё они гнутся и сваливаются", т.е. "а ещё eeprom_write_block() останаваливает работу всего, кроме обработчиков прерываний, на время записи".
Я же говорю - пример в самом простом виде, ведь можно и так:
Ага, очень похоже на то как у меня smile.gif , только у меня без OS и автоматный подход
для 2 копий X 2 блоков и с CRC каждого блока
типа:
Код
//=============================================================================
// Автомат записи в EEPROM
//=============================================================================
void EepromRun()
{

  if (EECR & (1<<EEWE)) return;                // идет запись ? тогда отваливаем

  if (CurrState==EE_FREE)                      // если еще не пишем
  {
    if (EE_StatUpdate==EEPROM_STAT_UPDATE)
    {                                          // обновляем статистику

      CurrBase=0;                      // первая копия
      BYTE *ps=(BYTE *)&modbase.Resets;
      BYTE *pd=(BYTE *)&EEStat;        // сохраняем во временном буфере
      BYTE len=(sizeof(EEStat)-2)/2;   // CRC не копируем
      do {                             // т.к. статистика вся WORD и DWORD
        *pd++=*ps++; *pd++=*ps++;      // копируем по 2 байта для скорости
      } while (--len);

      CurrState=EE_START_STAT_WRITE;
      return;
    }

    if (EE_ParamUpdate==EEPROM_PARAM_UPDATE)
    {                                          // обновляем параметры фильтрации
      CurrBase=0;                      // первая копия

      CurrState=EE_START_PARAM_WRITE;
      return;
    }

    EE_StatUpdate=0;                             // сбрасываем некорректные значения
    EE_ParamUpdate=0;
    return;
  }

  if (CurrState==EE_START_STAT_WRITE)            // начинаем обновлять статистику
  {
    CRC16.W=0xFFFF;                    // начальное значение CRC
    EEAddr=(WORD)&EE[CurrBase].Stat;   // адрес в EEPROM
    EESize=sizeof(EEStat);             // кол. байт на запись с учетом CRC
    MemAddr=(BYTE *)&EEStat;           // адрес в памяти откуда пишем

    BYTE tmp=*MemAddr++;
    CRC16.W=_crc16_update(CRC16.W, tmp);

    EEAR=EEAddr;
    EECR |= (1<<EERE);
    if (EEDR!=tmp)
    {
      EEAR=EEAddr;
      EEDR=tmp;
      EECR |= (1<<EEMWE);
      EECR |= (1<<EEWE);
    }

    EEAddr++;
    EESize--;

    CurrState=EE_STAT_WRITE;
    return;
  }

  if (CurrState==EE_STAT_WRITE)                  // продолжаем обновлять статистику
  {
    BYTE tmp=0;

    if (EESize==0)
    {
      CurrBase++;
      if (CurrBase==1)
      {
        CurrState=EE_START_STAT_WRITE; // переходим ко 2 копии
      }
      else
      {
        EE_StatUpdate=0;               // закончили писать статистику
        CurrState=EE_FREE;
      }
      return;
    }

    if (EESize>2)
    {
      tmp=*MemAddr++;
      CRC16.W=_crc16_update(CRC16.W, tmp);
    }
    else
    {
      if (EESize==2) tmp=CRC16.B[0];
      if (EESize==1) tmp=CRC16.B[1];
    }

    EEAR=EEAddr;
    EECR |= (1<<EERE);
    if (EEDR!=tmp)
    {
      EEAR=EEAddr;
      EEDR=tmp;
      EECR |= (1<<EEMWE);
      EECR |= (1<<EEWE);
    }

    EEAddr++;
    EESize--;

    return;
  }


  if (CurrState==EE_START_PARAM_WRITE)           // начинаем обновлять параметры
  {
    CRC16.W=0xFFFF;                    // начальное значение CRC
    EEAddr=(WORD)&EE[CurrBase].Param;  // адрес в EEPROM
    EESize=sizeof(TEEPROMParamBase);   // кол. байта на запись с учетом CRC
    MemAddr=(BYTE *)&modbase.CONFIG;   // адрес в памяти откуда пишем

    BYTE tmp=*MemAddr++;
    CRC16.W=_crc16_update(CRC16.W, tmp);

    EEAR=EEAddr;
    EECR |= (1<<EERE);
    if (EEDR!=tmp)
    {
      EEAR=EEAddr;
      EEDR=tmp;
      EECR |= (1<<EEMWE);
      EECR |= (1<<EEWE);
    }

    EEAddr++;
    EESize--;

    CurrState=EE_PARAM_WRITE;
    return;
  }

  if (CurrState==EE_PARAM_WRITE)                 // продолжаем обновлять параметры
  {
    BYTE tmp=0;

    if (EESize==0)
    {
      CurrBase++;
      if (CurrBase==1)
      {
        CurrState=EE_START_PARAM_WRITE; // переходим ко 2 копии
      }
      else
      {
        EE_ParamUpdate=0;               // закончили писать параметры
        CurrState=EE_FREE;
      }
      return;
    }

    if (EESize>2)
    {
      tmp=*MemAddr++;
      CRC16.W=_crc16_update(CRC16.W, tmp);
    }
    else
    {
      if (EESize==2) tmp=CRC16.B[0];
      if (EESize==1) tmp=CRC16.B[1];
    }

    EEAR=EEAddr;
    EECR |= (1<<EERE);
    if (EEDR!=tmp)
    {
      EEAR=EEAddr;
      EEDR=tmp;
      EECR |= (1<<EEMWE);
      EECR |= (1<<EEWE);
    }

    EEAddr++;
    EESize--;

    return;
  }

  if (CurrState!=EE_FREE) CurrState=EE_FREE;     // если неопределенное состояние, сбрасываем

}

Экономией памяти не занимался потому что было не надо...
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Jan 5 2009, 22:09
Сообщение #7


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Самые неприятные варианты работы с EEPROM - это когда все должно быть "на лету" - и чтение, и запись. И тут опять же рулит структура - скопировал в ОЗУ, лишь бы его хватило, те настройки, что используются в работе, а писАлка пишет себе...
Go to the top of the page
 
+Quote Post
singlskv
сообщение Jan 5 2009, 22:26
Сообщение #8


дятел
*****

Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065



Цитата(_Pasha @ Jan 6 2009, 01:09) *
Самые неприятные варианты работы с EEPROM - это когда все должно быть "на лету" - и чтение, и запись. И тут опять же рулит структура - скопировал в ОЗУ, лишь бы его хватило, те настройки, что используются в работе, а писАлка пишет себе...
Примерно так оно и работает в моем варианте, основная прога просто говорит:
EE_StatUpdate = EEPROM_STAT_UPDATE; // пора обновить статистику
EE_ParamUpdate = EEPROM_PARAM_UPDATE; // нужно обновить параметры
и все, дальше все делает автомат записи... причем для 2 копий с CRC.

для чтения у меня тоже была примочка, но проще оказалось делать копию в памяти при старте,
а еще у меня был вариант атомата который, когда не занят записью, начинает тестировать
записи eeprom на предмет валидности CRC, и при несовпадении сигнализирует об этом основную прогу,
при этом если пришел запрос на запись во время тестирования то он имеет приоритет,
те результат тестирования обновляется только после тестирования всего блока.
Go to the top of the page
 
+Quote Post
ChaiSER
сообщение Feb 23 2012, 06:07
Сообщение #9





Группа: Новичок
Сообщений: 4
Регистрация: 14-02-11
Из: UA-RU
Пользователь №: 62 962



Для записи переменных в EEPROM рекомендуеться использовать функции eeprom_write_хххх, а для перезаписи/обновления eeprom_update_хххх. Есть такой код:

Код
#include <avr/eeprom.h>

//Переменные хранящиеся в EEPROM памяти MCU
uint8_t eeFooByte EEMEM;
uint16_t eeFooWord EEMEM;

int main ( void )
{
    //Переменные для хранения значений из EEPROM в SRAM
    uint8_t myByte;
    uint16_t myWord;

    //Считываем значения из EEPROM
    myByte = eeprom_read_byte(&eeFooByte);
    myWord = eeprom_read_word(&eeFooWord);

    //Записываем новых значения в EEPROM
    if ( myByte == 0х00 ) {
        myByte = 254;
        eeprom_write_byte(&eeFooByte, myByte);
    }
    else {
        myByte = 254;
        eeprom_update_byte(&eeFooByte, myByte);
    }

    if ( myWord == 0х000 ) {
        myWord = 65500;
        eeprom_write_word(&eeFooWord, myWord);
    }
    else {
        myWord = 65500;
        eeprom_update_word(&eeFooWord, myWord);
    }
}


Правильно ли я делаю проверку есть ли значения переменных myByte и myWord в EEPROM?
Go to the top of the page
 
+Quote Post
Marian
сообщение Feb 24 2012, 13:51
Сообщение #10


Частый гость
**

Группа: Участник
Сообщений: 148
Регистрация: 23-02-07
Пользователь №: 25 618



Перед записью нет необходимости делать проверку.
Когда решите записать в еепром, используйте eeprom_update_ххх.
Она сама проверит и если необходимо запишет в еепром.
Go to the top of the page
 
+Quote Post
ChaiSER
сообщение Feb 24 2012, 15:26
Сообщение #11





Группа: Новичок
Сообщений: 4
Регистрация: 14-02-11
Из: UA-RU
Пользователь №: 62 962



Цитата(Marian @ Feb 24 2012, 17:51) *
Она сама проверит и если необходимо запишет в еепром.

Не знал этого, спасибо!
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 20th July 2025 - 16:28
Рейтинг@Mail.ru


Страница сгенерированна за 0.01449 секунд с 7
ELECTRONIX ©2004-2016