|
|
  |
Энергонезависимая Память AVR |
|
|
|
Mar 3 2011, 10:06
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(Petka @ Mar 2 2011, 20:44)  avr-gcc вообще не распределяет eeprom память. Как понимать "avr-gcc использует"? Хорошо. Под avr-gcc я имел ввиду весь тулчейн, точно так же как и CV, ICC и IAR. Линкер помещает в отдельную секцию данные с атрибутом EEMEM, а потом утилита objcopy выкусывает её в отдельный файл - образ прошивки eeprom памяти. И в результате, по умолчанию, данные в eeprom располагаются начиная с нулевого адреса. Вся эта канитель конфигурится через Makefile и программист может изменить массу параметров, в том числе и стартовый адрес eeprom данных. Поправьте или дополните меня если считаете нужным.
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Mar 3 2011, 16:20
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(zombi @ Mar 1 2011, 17:01)  Если просто хранить номер записи то младший бит будет меняться с каждым увеличением. Во-первых вы немного ошибаетесь - можно подобрать количество записей так, что изменения в младшем бите будут очень редкими. Например, если записи всего две, то младший бит в sequence ячейках практически никогда меняться не будет, т.к. в 0-ю запись попадут все четные sequence, в 1-ю - все нечетные. Во-вторых - даже если младший бит будет меняться постоянно, ну и что? Мы же пишем всегда в новые n-байт, т.е. ячеек с sequence'ом будет столько же сколько и записей, наработка на отказ - все те же n * 100000, где n - размерность массива записей. Ниже пример реализации алгоритма, правда здесь в качестве хранилища используется флеш (проц SAM7): Код void js_LoadConfig(void) { U8 *p = (U8 *)(CONFIG_START_FLASH_ADDRESS); U8 last_seq = *p; U8 *pLastConfig = p; U8 buf[sizeof(jsContext.Cfg)]; PJS_CONFIG pCfg = (PJS_CONFIG)buf; int i;
for (i = 0; i < CONFIG_MIRROR_PAGE_COUNT; i++) { p += FLASH_PAGE_SIZE_BYTES; if (((U8)(last_seq + 1)) == *p) { last_seq = *p; pLastConfig = p; } else { p = pLastConfig; break; } } // at this point p - points to the address with the most fresh config record memcpy( buf, p, sizeof(buf)); jsContext.LastLocation = (U32)p; jsContext.Cfg.Sequence = *p;
// check CRC of the record if ( CRC16( buf, sizeof(buf) != 0 ) { printf("CRC error exp=%2x, cur=%2x, flash_addr=%x, seq=%d\n", hCRC, pCfg->CRC, (U32)p, *p); printf("The configuration has NOT been applied!\n" ); printf("or there is no previously saved configuration.\n"); // store defaults js_StoreConfig(); } else { // CRC is ok, applying new settings memcpy( &jsContext.Cfg, pCfg, sizeof(jsContext.Cfg)); printf("Configuration applied, seq_%x\n", *p); } }
void js_StoreConfig(void) { jsContext.Cfg.Sequence += 1; jsContext.LastLocation += FLASH_PAGE_SIZE_BYTES; if (jsContext.LastLocation > CONFIG_LAST_FLASH_CELL_ADDRESS) jsContext.LastLocation = CONFIG_START_FLASH_ADDRESS;
jsContext.Cfg.CRC = CRC16( (U8 *)&jsContext.Cfg, sizeof(jsContext.Cfg) - 2); iap_PageWrite( jsContext.LastLocation, (U32 *)&jsContext.Cfg, sizeof(jsContext.Cfg) );
printf("configuration stored, L(%x), Sq(%x), (%d)bytes\n", jsContext.LastLocation, jsContext.Cfg.Sequence, sizeof(jsContext.Cfg)); } CONFIG_MIRROR_PAGE_COUNT --> это число записей в массиве. Sequence постоянно увеличивается, и новый sequence пишется уже в новую запись. При загрузке конфигурации - пробегаемся по массиву, находим самую страшую запись и берем ее. 2 moderator: просьба тэг [ code ] на [ codebox ] не менять, пасиба.
|
|
|
|
|
Mar 3 2011, 16:43
|

Чайник, 1 литр
   
Группа: Свой
Сообщений: 655
Регистрация: 17-05-06
Из: Moscow
Пользователь №: 17 168

|
А всё-таки, EEPROM в AVR страничной организации, или же нет? В документации, правда, в разделе записи в EEPROM с программатора, указан страничный обмен: к примеру, страница - 8 байт, и минимально адресуемый элемент - 1 байт. Ежели оно минимально адресуемо байтом, то какой смысл считать в них биты, ибо стирание\запись всё равно для всех восьми? А если из МК при записи в EEPROM одного байта переписывается вся страница, про принципу read-modify-write, то всё и того хуже...
|
|
|
|
|
Mar 4 2011, 15:02
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(zombi @ Mar 3 2011, 18:58)  что такое это sequence, где оное хранится и какова его размерность? Sequence это первый байт структуры Cfg (она вся пишется во флеш, последние ее два байта - CRC16). Структура Cfg - пишется покругу во флеш, при каждой записи sequence увеличивается на 1. При старте девайса - последовательно вычитываются записи начиная с нулевой, там где обнаруживается разница Код sn[i+1] - sn[ i ] != 1 (т.е. следующий Sequence отличается от текущего не на единицу), и будет i - номер искомой самой свежей записи. Цитата(SysRq @ Mar 3 2011, 19:00)  Тогда нет смысла мудрить с отдельными битами, ибо для всего байта erase\write выполняется. Нет write-only команды. Я и не предлагал
|
|
|
|
|
Mar 5 2011, 11:34
|

Гуру
     
Группа: Свой
Сообщений: 2 076
Регистрация: 10-09-08
Пользователь №: 40 106

|
Цитата(aaarrr @ Mar 4 2011, 01:21)  Хранится в каждой записи. Размерность должна быть такой, чтобы максимальное значение sequence было больше числа возможных записей, тогда всегда можно достоверно определить наиболее свежую. Цитата(defunct @ Mar 4 2011, 18:02)  Sequence это первый байт структуры Cfg (она вся пишется во флеш, последние ее два байта - CRC16). Спасибо! Разобрался. Действительно очень красиво все получается.  Цитата(ukpyr @ Mar 4 2011, 01:06)  Цитата(zombi @ Mar 3 2011, 20:13)  Осталось только выяснить : приводит ли к исчепанию ресурса стирание(запись значения FFH) в ячейку которая и до того была FFH
Полезно перед записью каждого байта проверять на равенство записанному. Уменьшается износ и часто сильно ускоряется обновление параметров. В одном проекте не хватало заряда конденсатора для сохранения в EEPROM после пропадания питания (больше 0.5сек), добавил проверку - успевало записать за десятки миллисекунд. Т.е. получается что время на запись "тогоже самого" тратится по любому, а вот приводит ли это к износу еепром?
|
|
|
|
|
Mar 5 2011, 12:29
|

Чайник, 1 литр
   
Группа: Свой
Сообщений: 655
Регистрация: 17-05-06
Из: Moscow
Пользователь №: 17 168

|
Цитата(zombi @ Mar 5 2011, 14:34)  Т.е. получается что время на запись "тогоже самого" тратится по любому, а вот приводит ли это к износу еепром? Убивается, ждём-с. Сейчас 1' 248' 000 циклов выполнено, пока жива... (Хм, в программке вроде бы не наврал нигде.. в один и тот же адрес пишу 0xFF в количестве 992 штук, затем 8 значений с единичкой в разных разрядах, и в обоих случаях читаю и проверяю совпало ли, и циклы считаю.) Код (ATMega128; здесь USB - мост на UART), на проверку, может ошибка где? CODE #include <stdio.h>
static char str[100];
#define EEPROM_ADDRESS_TO_DESTROY 4094U
uint32_t cycles_; uint16_t cycles_1000_;
void show_cycles(uint8_t is_failed) { if(is_failed) { sprintf(str, "\r\nFAILED ON: %ld", cycles_); } else { sprintf(str, "\r\nCURRENT: %ld", cycles_); } for(uint8_t i = 0; i < 100; i++) { if(str[i]) USB_TransmitByte(str[i]); else break; } }
void eeprom_write_no_check(uint16_t address, uint8_t data) { while(EECR & _BV(EEWE));
EEAR = address; EEDR = data;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { EECR |= _BV(EEMWE); EECR |= _BV(EEWE); } }
uint8_t eeprom_read_no_check(uint16_t address) { while(EECR & _BV(EEWE));
EEAR = address; EECR |= _BV(EERE);
return EEDR; }
__attribute__((OS_main)) int main(void) { USB_Initialize(); sei(); for(;;) { eeprom_write_no_check(EEPROM_ADDRESS_TO_DESTROY, 0xFF); ++cycles_; ++cycles_1000_; if(eeprom_read_no_check(EEPROM_ADDRESS_TO_DESTROY) != 0xFF) { show_cycles(TRUE); for(;;); } if(cycles_1000_ == 1000) { cycles_1000_ = 0; show_cycles(FALSE); for(uint8_t data = 1; data; data <<= 1) { eeprom_write_no_check(EEPROM_ADDRESS_TO_DESTROY, data); ++cycles_; ++cycles_1000_; if(eeprom_read_no_check(EEPROM_ADDRESS_TO_DESTROY) != data) { show_cycles(TRUE); for(;;); } } } if(USB_IsDataReceived()) { if(USB_ReceiveByte() == '?') { show_cycles(FALSE); } } }
return 0; } Если в коде ошибок нет, то поставлю писать что-нить отличное от 0xFF, проверим далее...
Сообщение отредактировал SysRq - Mar 5 2011, 15:03
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|