Перейти к содержанию
    

Энергонезависимая Память AVR

image-craft тоже не использует по-инерции

avr-gcc использует и лично я не испытываю в связи с этим никаких затруднений.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

....

avr-gcc использует и лично я не испытываю в связи с этим никаких затруднений.

avr-gcc вообще не распределяет eeprom память. Как понимать "avr-gcc использует"?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

avr-gcc вообще не распределяет eeprom память. Как понимать "avr-gcc использует"?

Хорошо. Под avr-gcc я имел ввиду весь тулчейн, точно так же как и CV, ICC и IAR.

 

Линкер помещает в отдельную секцию данные с атрибутом EEMEM,

а потом утилита objcopy выкусывает её в отдельный файл - образ прошивки eeprom памяти.

И в результате, по умолчанию, данные в eeprom располагаются начиная с нулевого адреса.

 

Вся эта канитель конфигурится через Makefile и программист может изменить массу параметров,

в том числе и стартовый адрес eeprom данных.

 

Поправьте или дополните меня если считаете нужным.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если просто хранить номер записи то младший бит будет меняться с каждым увеличением.

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

Например, если записи всего две, то младший бит в 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 ] не менять, пасиба.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А всё-таки, EEPROM в AVR страничной организации, или же нет?

В документации, правда, в разделе записи в EEPROM с программатора, указан страничный обмен: к примеру, страница - 8 байт, и минимально адресуемый элемент - 1 байт.

Ежели оно минимально адресуемо байтом, то какой смысл считать в них биты, ибо стирание\запись всё равно для всех восьми? А если из МК при записи в EEPROM одного байта переписывается вся страница, про принципу read-modify-write, то всё и того хуже...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А всё-таки, EEPROM в AVR страничной организации, или же нет?

Всегда был байтовой насколько помню. - можно стирать/записать произвольный байт.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

To defunct.

Я не могу понять что такое это sequence, где оное хранится и какова его размерность?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Всегда был байтовой насколько помню. - можно стирать/записать произвольный байт.
Тогда нет смысла мудрить с отдельными битами, ибо для всего байта erase\write выполняется. Нет write-only команды.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Тогда нет смысла мудрить с отдельными битами, ибо для всего байта erase\write выполняется. Нет write-only команды.

Осталось только выяснить : приводит ли к исчепанию ресурса стирание(запись значения FFH) в ячейку которая и до того была FFH

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Осталось только выяснить : приводит ли к исчепанию ресурса стирание(запись значения FFH) в ячейку которая и до того была FFH
Полезно перед записью каждого байта проверять на равенство записанному. Уменьшается износ и часто сильно ускоряется обновление параметров. В одном проекте не хватало заряда конденсатора для сохранения в EEPROM после пропадания питания (больше 0.5сек), добавил проверку - успевало записать за десятки миллисекунд.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я не могу понять что такое это sequence, где оное хранится и какова его размерность?

Хранится в каждой записи. Размерность должна быть такой, чтобы максимальное значение sequence было больше числа возможных записей, тогда всегда можно достоверно определить наиболее свежую.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Размерность должна быть такой, чтобы максимальное значение sequence было больше числа возможных записей, тогда всегда можно достоверно определить наиболее свежую.
Может быть и небольшой размерности, но период записываемых в него значений должен быть некратен количеству копий записей. Тогда по сбою последовательности легко находится место налезания головы буфера на хвост.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

что такое это sequence, где оное хранится и какова его размерность?

Sequence это первый байт структуры Cfg (она вся пишется во флеш, последние ее два байта - CRC16).

Структура Cfg - пишется покругу во флеш, при каждой записи sequence увеличивается на 1. При старте девайса - последовательно вычитываются записи начиная с нулевой, там где обнаруживается разница

sn[i+1] - sn[ i ] != 1

(т.е. следующий Sequence отличается от текущего не на единицу), и будет i - номер искомой самой свежей записи.

 

Тогда нет смысла мудрить с отдельными битами, ибо для всего байта erase\write выполняется. Нет write-only команды.

Я и не предлагал :laughing:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Хранится в каждой записи. Размерность должна быть такой, чтобы максимальное значение sequence было больше числа возможных записей, тогда всегда можно достоверно определить наиболее свежую.

Sequence это первый байт структуры Cfg (она вся пишется во флеш, последние ее два байта - CRC16).

Спасибо! Разобрался. Действительно очень красиво все получается.

:beer:

 

Осталось только выяснить : приводит ли к исчепанию ресурса стирание(запись значения FFH) в ячейку которая и до того была FFH

Полезно перед записью каждого байта проверять на равенство записанному. Уменьшается износ и часто сильно ускоряется обновление параметров. В одном проекте не хватало заряда конденсатора для сохранения в EEPROM после пропадания питания (больше 0.5сек), добавил проверку - успевало записать за десятки миллисекунд.

Т.е. получается что время на запись "тогоже самого" тратится по любому, а вот приводит ли это к износу еепром?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Т.е. получается что время на запись "тогоже самого" тратится по любому, а вот приводит ли это к износу еепром?
Убивается, ждём-с. Сейчас 1'248'000 циклов выполнено, пока жива...

 

(Хм, в программке вроде бы не наврал нигде.. в один и тот же адрес пишу 0xFF в количестве 992 штук, затем 8 значений с единичкой в разных разрядах, и в обоих случаях читаю и проверяю совпало ли, и циклы считаю.)

 

Код (ATMega128; здесь USB - мост на UART), на проверку, может ошибка где?

#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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...