|
|
  |
Работа с EEPROM в WinAVR |
|
|
|
Jan 5 2009, 07:25
|

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

|
Добрый день! Встала проблема – сохранять и затем читать несколько переменных (10-15) в/из EEPROM. Посмотрел примеры здесь, но не понравилось, как-то громоздко получается, байты считать приходится... Если кто сталкивался, подскажите нет ли решений поэлегантней? Пусть набор переменных будет такой: Код uint8_t a1; double a2; uint16_t a3; Заранее спасибо. p.s. Компилятор Winavr, камень atmega128
--------------------
Если все, то не я...
|
|
|
|
|
Jan 5 2009, 07:59
|
Частый гость
 
Группа: Свой
Сообщений: 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
|
|
|
|
|
Jan 5 2009, 08:20
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 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); // само собой, можно и одночные переменные }
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Jan 5 2009, 09:02
|
;
     
Группа: Участник
Сообщений: 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
|
|
|
|
|
Jan 5 2009, 14:58
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 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 Я нарисовал выше и структуру, и "большой" (на все три поля структуры) блок инициализации. Единственное отличие - в примере всё как бы в одном файле показал.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Jan 5 2009, 21:18
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(ReAl @ Jan 5 2009, 17:58)  "а ещё они гнутся и сваливаются", т.е. "а ещё eeprom_write_block() останаваливает работу всего, кроме обработчиков прерываний, на время записи". Я же говорю - пример в самом простом виде, ведь можно и так: Ага, очень похоже на то как у меня  , только у меня без 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; // если неопределенное состояние, сбрасываем
} Экономией памяти не занимался потому что было не надо...
|
|
|
|
|
Jan 5 2009, 22:26
|
дятел
    
Группа: Свой
Сообщений: 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, и при несовпадении сигнализирует об этом основную прогу, при этом если пришел запрос на запись во время тестирования то он имеет приоритет, те результат тестирования обновляется только после тестирования всего блока.
|
|
|
|
|
Feb 23 2012, 06:07
|
Группа: Новичок
Сообщений: 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?
|
|
|
|
|
Feb 24 2012, 15:26
|
Группа: Новичок
Сообщений: 4
Регистрация: 14-02-11
Из: UA-RU
Пользователь №: 62 962

|
Цитата(Marian @ Feb 24 2012, 17:51)  Она сама проверит и если необходимо запишет в еепром. Не знал этого, спасибо!
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|