Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Энергонезависимая Память AVR
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Br.Misha
Привет!
В ДШ на атмегу написано, что еепром можно перезаписывать 100000 раз. Это касается каждой ячейки отдельно или нет?
Почему спрашиваю? Просто хочу сделать девайс, который будет работать много лет и много раз будет перезаписана. У атмеги8 512 байт, всего мне нужно около 15 байт. Принцип такой: 16 байт используются для хранения даных и 4 байта для хранения счетчика записей. После каждой записи я буду увеличивать счетчик на 1 и когда дойдет до 100000, то буду записывать даные и счетчик в следующие 20 байт, получается, циклов записи будет около 2 милионов (для атмега8). Как вам идея?
alexunder
Цитата(Br.Misha @ Feb 27 2011, 15:27) *
4 байта для хранения счетчика записей. После каждой записи я буду увеличивать счетчик на 1 и когда дойдет до 100000, то буду записывать даные и счетчик в следующие 20 байт, получается, циклов записи будет около 2 милионов (для атмега8). Как вам идея?


Так наверное будет работать, только зачем для счетчика до 100000 использовать 4 байта, когда достаточно 3-х: 2^24 = 16777216? Ну это так, для экономии памяти sm.gif
100000 раз применительно к каждому биту, я считаю.
SysRq
[PDF] AVR101: High Endurance EEPROM Storage
Леонид Иванович
Делал так:

CODE
//----------------------------------------------------------------------------

//Eeprom support module

//----------------------------------------------------------------------------

#include <Main.h>
#include <Eeprom.h>

//------------------------------ Constants: ----------------------------------

#define RBUFF 100 //EEPROM ring buffer size
#define RSIG 0xDA //record header signature

//------------------------------ Variables: ----------------------------------

typedef struct
{
char Sig; //record header signature
bool On; //On flag
int Val; //stored value
} EVal;

__no_init __eeprom int EData[EE_N]; //EEPROM data array
__no_init __eeprom EVal EVals[RBUFF]; //EEPROM ring buffer

static char EePnt = 0; //pointer to currently used record

//-------------------------- Read EEPROM data: -------------------------------

int Eeprom_Read(char a)
{
return(EData[a]); //read parameter
}

//-------------------------- Write EEPROM data: -------------------------------

void Eeprom_Write(char a, int d)
{
if(EData[a] != d) //if parameter changed
{
EData[a] = d; //write parameter
__watchdog_reset(); //watchdog reset
}
}

//-------------------------- Read V from EEPROM: -----------------------------

int Eeprom_ReadV(bool *on)
{
EePnt = RBUFF; //set incorrect pointer value
for(char i = 0; i < RBUFF; i++) //search signature in ring buffer
if(EVals[i].Sig == RSIG) //if signature found
{
EePnt = i; //initialize pointer
break;
}
if(EePnt == RBUFF) //if pointer incorrect (signature not found)
{
EePnt = 0; //set pointer to first array record
*on = 0; //supply off
return(0); //return V = 0
}
*on = EVals[EePnt].On; //read on flag
return(EVals[EePnt].Val); //read V
}

//--------------------------- Write V to EEPROM: -----------------------------

void Eeprom_WriteV(int v, bool on)
{
char NewPnt = EePnt; //save previous pointer value
if(NewPnt++ == RBUFF) //advance pointer
NewPnt = 0; //roll-up pointer
EVals[NewPnt].On = on; //save on flag
EVals[NewPnt].Val = v; //save V
EVals[NewPnt].Sig = RSIG; //save signature at new location
EVals[EePnt].Sig = 0xFF; //clear signature at old location
__watchdog_reset(); //watchdog reset
EePnt = NewPnt; //save new pointer value
}

//----------------------------------------------------------------------------
defunct
Цитата(Br.Misha @ Feb 27 2011, 14:27) *
Как вам идея?

Лучше не ждать когда накрутит 100000, а просто каждую запись писать в следующие n-байт. Напр сделать массив из 20-ти записей по 16 байт, писать вначале 0-ю запись, потом 1-ю ..... 19-ю, опять 0-ю и так покругу. Счетчик в этом случаем может быть 1 байтным и хранить только sequence (порядковый номер) записи. Т.о. вы не только увеличите ресурс в 20 раз но и добъетесь отказоустойчивости, т.к. при отказе любой из записей вы может прочитать предыдущую.
GDI
Только надо еще как то узнать о том что произошел отказ, для этого можно писать еще и какую-то контрольную сумму в каждую запись, и проверять ее при чтении, вот тогда и можно будет определившись что данные испорчены, поискать предыдущие валидные записи.
demiurg_spb
Цитата(GDI @ Mar 1 2011, 17:10) *
Только надо еще как то узнать о том что произошел отказ...
Узнавать-то вроде и не надо. Номер последней записи обновляется _после_ записи данных.
Всё само-собой получается.
Производитель гарантирует 100тыс циклов записи, так что наворачивать еще что-либо сверх рекомендованного в аппноте ИМХО не резонно.
zombi
Цитата(defunct @ Mar 1 2011, 16:54) *
Лучше не ждать когда накрутит 100000, а просто каждую запись писать в следующие n-байт.

100%
Цитата(defunct @ Mar 1 2011, 16:54) *
Счетчик в этом случаем может быть 1 байтным и хранить только sequence (порядковый номер) записи.

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

Думаю что в качестве указателя желательно применить :
a: "бегущий" бит ноль(единица) в байте (увеличение ресурса в 8 раз);
б: "бегущий" байт 00H(FFH) в массиве X[n] (увеличение ресурса в n раз).
ukpyr
Цитата
4 байта для хранения счетчика записей
хватит и 2х
Dimoza
Цитата(defunct @ Mar 1 2011, 15:54) *
сделать массив из 20-ти записей по 16 байт, писать вначале 0-ю запись, потом 1-ю ..... 19-ю, опять 0-ю и так покругу. Счетчик в этом случаем может быть 1 байтным и хранить только sequence (порядковый номер) записи.

И по возможности не располагать его с 0 адреса в еепром. Вроде даже где-то в апликухах об этом говорилось: в AVR при неблагоприятном стечении обстоятельств значение в нулевой ячейке может быть утеряно.
zombi
Цитата(Dimoza @ Mar 1 2011, 19:30) *
И по возможности не располагать его с 0 адреса в еепром. Вроде даже где-то в апликухах об этом говорилось: в AVR при неблагоприятном стечении обстоятельств значение в нулевой ячейке может быть утеряно.

Ни фигасе! Вот бы найти документальное подтверждение этому.
ArtemKAD
Цитата
Ни фигасе! Вот бы найти документальное подтверждение этому.

Если найдешь Errata на старые AVR (к примеру At90S2313), то там такое было. Если reset проходил во время записи EEPROM, то адрес записи слетал в 0 и портилась нулевая ячейка.
ukpyr
Цитата
И по возможности не располагать его с 0 адреса в еепром.
старая байка, уже давно не актуальная
sgs
Цитата(ukpyr @ Mar 1 2011, 21:53) *
старая байка, уже давно не актуальная

Для рабочего режима - может быть. Однако при отладке с помощью JTAGICE II довольно часто портится именно 0 ячейка EEPROM. С чем это связано - неизвестно. Возможно, с процессом заливки новой программы? Естественно, программирование EEPROM при этом запрещено. Портится именно 0 ячейка, далее - все в порядке...
VladimirYU
Цитата(ukpyr @ Mar 1 2011, 20:53) *
старая байка, уже давно не актуальная

тем не менее IAR при стандартных настройках 0-ую ячейку ЕЕПРОМ не пользует.
demiurg_spb
image-craft тоже не использует по-инерции
avr-gcc использует и лично я не испытываю в связи с этим никаких затруднений.
Petka
Цитата(demiurg_spb @ Mar 2 2011, 15:06) *
....
avr-gcc использует и лично я не испытываю в связи с этим никаких затруднений.

avr-gcc вообще не распределяет eeprom память. Как понимать "avr-gcc использует"?
demiurg_spb
Цитата(Petka @ Mar 2 2011, 20:44) *
avr-gcc вообще не распределяет eeprom память. Как понимать "avr-gcc использует"?

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

Линкер помещает в отдельную секцию данные с атрибутом EEMEM,
а потом утилита objcopy выкусывает её в отдельный файл - образ прошивки eeprom памяти.
И в результате, по умолчанию, данные в eeprom располагаются начиная с нулевого адреса.

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

Поправьте или дополните меня если считаете нужным.
defunct
Цитата(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 ] не менять, пасиба.
SysRq
А всё-таки, EEPROM в AVR страничной организации, или же нет?
В документации, правда, в разделе записи в EEPROM с программатора, указан страничный обмен: к примеру, страница - 8 байт, и минимально адресуемый элемент - 1 байт.
Ежели оно минимально адресуемо байтом, то какой смысл считать в них биты, ибо стирание\запись всё равно для всех восьми? А если из МК при записи в EEPROM одного байта переписывается вся страница, про принципу read-modify-write, то всё и того хуже...
defunct
Цитата(SysRq @ Mar 3 2011, 18:43) *
А всё-таки, EEPROM в AVR страничной организации, или же нет?

Всегда был байтовой насколько помню. - можно стирать/записать произвольный байт.
zombi
To defunct.
Я не могу понять что такое это sequence, где оное хранится и какова его размерность?
SysRq
Цитата(defunct @ Mar 3 2011, 19:47) *
Всегда был байтовой насколько помню. - можно стирать/записать произвольный байт.
Тогда нет смысла мудрить с отдельными битами, ибо для всего байта erase\write выполняется. Нет write-only команды.
zombi
Цитата(SysRq @ Mar 3 2011, 20:00) *
Тогда нет смысла мудрить с отдельными битами, ибо для всего байта erase\write выполняется. Нет write-only команды.

Осталось только выяснить : приводит ли к исчепанию ресурса стирание(запись значения FFH) в ячейку которая и до того была FFH
ukpyr
Цитата
Осталось только выяснить : приводит ли к исчепанию ресурса стирание(запись значения FFH) в ячейку которая и до того была FFH
Полезно перед записью каждого байта проверять на равенство записанному. Уменьшается износ и часто сильно ускоряется обновление параметров. В одном проекте не хватало заряда конденсатора для сохранения в EEPROM после пропадания питания (больше 0.5сек), добавил проверку - успевало записать за десятки миллисекунд.
aaarrr
Цитата(zombi @ Mar 3 2011, 19:58) *
Я не могу понять что такое это sequence, где оное хранится и какова его размерность?

Хранится в каждой записи. Размерность должна быть такой, чтобы максимальное значение sequence было больше числа возможных записей, тогда всегда можно достоверно определить наиболее свежую.
Сергей Борщ
QUOTE (aaarrr @ Mar 4 2011, 00:21) *
Размерность должна быть такой, чтобы максимальное значение sequence было больше числа возможных записей, тогда всегда можно достоверно определить наиболее свежую.
Может быть и небольшой размерности, но период записываемых в него значений должен быть некратен количеству копий записей. Тогда по сбою последовательности легко находится место налезания головы буфера на хвост.
defunct
Цитата(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 команды.

Я и не предлагал laughing.gif
zombi
Цитата(aaarrr @ Mar 4 2011, 01:21) *
Хранится в каждой записи. Размерность должна быть такой, чтобы максимальное значение sequence было больше числа возможных записей, тогда всегда можно достоверно определить наиболее свежую.

Цитата(defunct @ Mar 4 2011, 18:02) *
Sequence это первый байт структуры Cfg (она вся пишется во флеш, последние ее два байта - CRC16).

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

Цитата(ukpyr @ Mar 4 2011, 01:06) *
Цитата(zombi @ Mar 3 2011, 20:13) *

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

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

Т.е. получается что время на запись "тогоже самого" тратится по любому, а вот приводит ли это к износу еепром?
SysRq
Цитата(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, проверим далее...
zombi
Цитата(SysRq @ Mar 5 2011, 15:29) *
Убивается, ждём-с. Сейчас 305 тысяч циклов выполнено, пока жива...

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

Ого, 305.000 ! Оч. интересно! Ждемс!
Но мне кажется что для проверки работоспособности надо бы через некоторое количество циклов (к примеру 10.000 ~ 100.000) попробывать записать инверсные данные
SysRq
Цитата(zombi @ Mar 5 2011, 16:00) *
Но мне кажется что для проверки работоспособности надо бы через некоторое количество циклов (к примеру 10.000 ~ 100.000) попробывать записать инверсные данные
Примерно так и делаю, посмотрите код выше.
Если одинаковые значения не пишутся, то сейчас всего тысяч 6 циклов... 05.gif
314
Почему-то всегда казалось, что тип флеш, использованный в АВР, убивается только записью нулей... laughing.gif
SysRq
Выключил на 1'800'000. Изменил в исходнике 0xFF на 0x00, адрес на 1 вниз, перешил, запустил. Ждём, убьётся ли записью нулей...
zombi
Цитата(SysRq @ Mar 5 2011, 16:54) *
Примерно так и делаю, посмотрите код выше.
Если одинаковые значения не пишутся, то сейчас всего тысяч 6 циклов... 05.gif

Ага, вроде правильно все.

Цитата(SysRq @ Mar 5 2011, 19:23) *
Выключил на 1'800'000. Изменил в исходнике 0xFF на 0x00, адрес на 1 вниз, перешил, запустил. Ждём, убьётся ли записью нулей...

Наверное можно предположить что ограничение 100.000 циклов это максимальное количество изменеий каждого БИТА еепром.
SysRq
Цитата(zombi @ Mar 5 2011, 23:23) *
Наверное можно предположить что ограничение 100.000 циклов это максимальное количество изменеий каждого БИТА еепром.
Запись 0x00 я остановил на ~800 тысячах, не дождался. Запись чередования 0xFF\0x00 остановил на 401 тысяче, ибо уже не верил что оно пишет в EEPROM вообще.
Сейчас посмотрел - таки, пишет! Запустил заново, добавив ещё запись 0x55 в EEDR _перед_ чтением...
zombi
Цитата(SysRq @ Mar 5 2011, 23:34) *
Запись 0x00 я остановил на ~800 тысячах, не дождался. Запись чередования 0xFF\0x00 остановил на 401 тысяче, ибо уже не верил что оно пишет в EEPROM вообще.
Сейчас посмотрел - таки, пишет! Запустил заново, добавив ещё запись 0x55 в EEDR _перед_ чтением...

400.000 это уже слишком! А проц какой?
В понедельник тоже буду попробывать на 162-й атмеге.
SysRq
Результат записи 0x00 (по приведённому выше алгоритму): убилось на 3'238'008 цикле laughing.gif
CODE
// ...
CURRENT: 3236000
CURRENT: 3237000
CURRENT: 3238000
FAILED ON: 3238008

// Перезапуск по питанию

CURRENT: 1000
FAILED ON: 1008

// Перезапуск по питанию

CURRENT: 1000
CURRENT: 2000
CURRENT: 3000
CURRENT: 4000
CURRENT: 5000
WRITTEN: 36 // Проверка записи всё в тот же адрес
READ: 36 // Результат чтения
WRITTEN: 34
READ: 34
WRITTEN: 30
READ: 30
CURRENT: 6000
CURRENT: 7000
CURRENT: 8000
CURRENT: 9000
FAILED ON: 9008
zombi
Цитата(SysRq @ Mar 6 2011, 09:24) *
Результат записи 0x00 (по приведённому выше алгоритму): убилось на 3'238'008 цикле laughing.gif

Т.е. получается что на износ влияет любой процесс записи?
И абсолютно без разницы что было в ячейке до него.
Но 3'238'008 циклов! Этож какой запас прочности!!! В 32 раза!

P.S. а убития записью 0хFF возможно просто не дождались.
SysRq
Результат записи постоянно меняющегося значения: убилось на 3'327'762 цикле.
CODE
// ...
CURRENT: 3326000
CURRENT: 3327000
FAILED ON: 3327762

// перезапуск

// ...
CURRENT: 99000
CURRENT: 100000
FAILED ON: 100889

// перезапуск

// ...
CURRENT: 101000
CURRENT: 102000
FAILED ON: 102918


--

Собстно, выводы:
а) страничной организации нет, ибо я убивал соседние адреса в рамках возможной страницы;
б) убивается, похоже, именно записью нуля: см. поведение после перезапуска в логах.

PS: ATMega128-16AU @ 14.7456 @ комнатная температура.

aaarrr
Цитата(zombi @ Mar 6 2011, 11:14) *
Но 3'238'008 циклов! Этож какой запас прочности!!! В 32 раза!

Не забывайте, что эксперимент проведен в тепличных условиях. 100K гарантируется для любых.
zombi
Провел эксперимент с ATmega162-16AU @ 5V @ 16MHz @ t комнатная.
Чередующиеся записи 0х55 - 0xAA по постоянному адресу.
Убилось после выполнения 3.146.000 записей.
Работоспособность ячейки проверялась (после каждых 2.000 записей 0х55 / 0хAA) записью бегущего нуля и единицы.
Перезапуск с соседним адресом - результат примерно тотже (>3.000.000).
В обоих случаях ячейки убились полностью (один из разрядов постоянно в нуле).
Juk1976
Народ!!!
Да не мучайте себя.
Используйте FRAMку и будет вам счастье.
Вот делов-то.
aaarrr
Цитата(Juk1976 @ Mar 17 2011, 00:59) *
Используйте FRAMку и будет вам счастье.
Вот делов-то.

Ну а если бюджет не позволяет?
314
At24cXX - I2C- dip8 - 0.2-0.3$ более 1е6 записи/стирания
nand7
Попробуйте провести эксперимент на температуре 125 или 100С, например. Дойдет ли хотя бы до 200тыс?
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.