Когда вы записываете данные, время летит быстро
EEPROM повсеместно используется для сохранения параметров настройки и журнала работы во встраиваемых системах. К примеру, вы можете хотеть функцию «черного ящика», для записи последних данных на момент аварии или потери питания. Я видел спецификации с требованием записывать подобные данные каждые несколько секунд.
Но проблема в том, что EEPROM имеет ограниченный ресурс числа записей. После 100,000 или миллиона записей (зависит от конкретного чипа), некоторые из ваших систем начнут испытывать проблемы с отказом EEPROM. (Посмотрите в даташит, чтобы узнать конкретную цифру. Если вы хотите выпустить большое число устройств, «наихудший случай», вероятно, более важен чем «типичный»). Миллион записей кажется большой цифрой, но на самом деле он закончится очень быстро. Давайте посмотрим на примере, предположив, что нам нужно сохранять измеренное напряжение в одну ячейку каждые 15 секунд.
1,000,000 записей при одной записи в 15 секунд дают записи в минуту:
1,000,000 / ( 4 * 60 минут/час * 24 часа/день ) = 173.6 дней.
Другими словами, ваша EEPROM исчерпает резерв в миллион записей менее чем через 6 месяцев.
Ниже приведен график, показывающая время до износа (в годах), основанный на периоде обновления конкретной ячейки EEPROM. Ограничительная линия для продукта с продолжительностью жизни 10 лет составляет одно обновление каждые 5 минут 15 секунд для микросхемы с ресурсом 1 миллион записей. Для EEPROM с ресурсом 100К можно обновлять конкретную ячейку не чаще одного раза в 52 минуты. Это означает, что не стоит и надеяться обновлять ячейку каждые несколько секунд, если вы хотите, чтобы ваш продукт работал годы, а не месяцы. Вышесказанное масштабируется линейно, правда, в настоящем приборе имеются еще и вторичные факторы, такие как температура и режим доступа.
Уменьшить частоту
Самый безболезненный способ решить проблему-это просто записывать данные реже. В некоторых случаях требования к системе это позволяют. Или можно записывать только при каких-либо больших изменениях. Однако, с записью, привязанной к событиям, помните о возможном сценарии, при котором значение будет постоянно колебаться, и вызовет поток событий, которые приведут к износу EEPROM.
(Будет неплохо, если вы сможете определить, сколько раз производилась запись в EEPROM. Но это потребует счётчика, который будет храниться в EEPROM… при этом проблема превращается проблему износа счётчика.)
Прерывание по снижению уровня питания
В некоторых процессорах имеется прерывание по низкому уровню питания, которое можно использовать для записи одного последнего значения в EEPROM, в то время как система выключается по потере питания. В общем случае, вы храните интересующее значение в ОЗУ, и сохраняете его в EEPROM только при выключении питания. Или, возможно, вы записываете EEPROM время от времени, и записываете другую копию в EEPROM как часть процедуры выключения, чтобы убедиться, что самые последние данные запишутся.
Важно убедиться, что есть большой конденсатор по питанию, который будет поддерживать напряжение, достаточное для программирования EEPROM достаточно продолжительное время. Это может сработать, если вам нужно записать одно или два значения, но не большой блок данных. Осторожно, тут имеется большое пространство для ошибки!
Кольцевой буфер
Классическое решение проблемы износа-использовать кольцевой буфер FIFO, содержащий N последних записей значения. Так-же понадобится сохранять указатель на конец буфера в EEPROM. Это уменьшает износ EEPROM на величину, пропорциональную числу копий в этом буфере. Например, если буфер проходит через 10 различных адресов для сохранения одного значения, каждая конкретная ячейка модифицируется в 10 раз реже, и ресурс записи возрастает в 10 раз. Вам также понадобится отдельный счётчик или отметка времени для каждой из 10 копий, чтобы можно было определить, которая из них последняя на момент выключения. Другими словами, понадобится два буфера, один для значения, и один для счетчика. (Если сохранять счетчик по одному и тому-же адресу, это приведёт к его износу, т.к. он должен увеличиваться при каждом цикле записи.) Недостаток этого метода в том, что нужно в 10 раз больше места чтобы получить в 10 раз большую продолжительность жизни. Можно проявить смекалку, и упаковать счетчик вместе с данными. Если вы записываете большое количество данных, добавление нескольких байт для счетчика — не такая уж большая проблема. Но в любом случае, понадобится много EEPROM.
Atmel приготовил аппноут, содержащий все кровавые подробности:
AVR-101: High Endurance EEPROM Storage: www.atmel.com/images/doc2526.pdf
Особый случай для счётчика числа записей
Иногда нужно сохранить счётчик, а не сами значения. К примеру, вы можете хотеть знать число включений прибора, или время работы вашего устройства. Самое плохое в счётчиках, это то, что у них постоянно меняется младший значащий бит, изнашивая младшие ячейки EEPROM быстрее. Но и тут возможно применить некоторые трюки. В аппноуте от Microchip есть несколько умных идей, таких как использование кода Грея, чтобы только один бит из многобайтового счётчика менялся при изменении значения счетчика. Также они рекомендуют использовать корректирующие коды для компенсации износа. (Я не знаю, насколько эффективно будет применение таких кодов, т.к. это будет зависеть от того, насколько независимы будут ошибки в битах в байтах счётчика, используйте на свой страх и риск, прим. авт.). Смотри аппноут: ww1.microchip.com/downloads/en/AppNotes/01449A.pdf
Примечание: для тех, кто хотел бы узнать больше, Microchip подготовил документ, содержащий детальную информацию об устройстве ячеек EEPROM и их износе с диаграммами:
ftp.microchip.com/tools/memory/total50/tutorial.html
Дайте мне знать, если у вас имеются какие-либо интересные идеи по поводу борьбы с износом EEPROM.
Источик: Phil Koopman, «Better Embedded System SW»
betterembsw.blogspot.ru/2015/07/avoiding-eeprom-wearout.html
Примечание переводчика: в последние годы появились микросхемы EEPROM со страничной организацией стирания (подобной микросхемам FLASH), где логически можно адресовать ячейки (читать, записывать и стирать) побайтно, но при этом микросхема невидимо для пользователя стирает всю страницу целиком и перезаписывает новыми данными. Т.е. стерев ячейки по адресу 0, мы фактически стёрли и перезаписали ячейки с адресами 0...255 (при размере страницы 256 байт), поэтому трюк с буфером в этом случае не поможет. При исчерпании ресурс записей у такой микросхемы выходит из строя не одна ячейка, а вся страница целиком. В даташитах для таких микросхем ресурс записи указан для страницы, а не для конкретной ячейки. Смотри, например, даташит на 25LC1024 от Microchip.
Комментарии (13)
Alexsmt
13.10.2015 03:55Классическое решение из флеш памяти:
После стирания у нас все биты в 1.
1. Состояния счетчика можно записывать побитно без стирания как 11111110,11111100,11111000 и т.д.
2. В случае если данные не могут быть равны 0 (например путем добавления бита четности или помехоустойчивых кодов) используем кольцевой буфер, а старые данные забиваем нулями.barabanus
13.10.2015 13:23Для побитного обновления счетчика самое лучшее, что мы можем сделать, это использовать коды Грэя, как и сказано в статье. При этом мы получаем не 8 возможных значений счетчика для восьми бит, а все 256.
Mirn
13.10.2015 13:39нет, так же останутся 8 возможных значений. Коды грея работают как 1->0 так и 1->0.
И какая разница в каком порядке занулить если поставить единицу сложно и надо избегать.barabanus
13.10.2015 14:03Коды Грея дают такое же количество комбинаций для одного и того же количества бит, что и прямой код. На двух битах возможно получить четыре разных значения кодов Грэя, на трех битах — восемь разных значений кодов Грея, и т.д.
Код Грея на ВикипедииProstoTyoma
13.10.2015 14:16Суть в том, что изменение 1 -> 0 делается просто, а 0 -> 1 только через стирание. Коды Грея требуют обеих операций.
kasperos
13.10.2015 15:39получить можно, но EEPROM придется каждый раз стирать, а от этого пытаются уйти
лучший способ: кольцевой буфер, со счетчиком номера в структуре данных, находится вроде за log(n)
sguwenka
13.10.2015 09:22+1Хранение данных в оперативке + ионистор, запись в flash/eeprom только при пропадании основного питания.
Ячейки памяти убивают люди! ;) Писали как-то драйвер по работе с flash, ошиблись в цикле — приращали не адрес, а значение по адресу. Память убивается за несколько секунд…Alexsmt
14.10.2015 02:09+1Ионистор защитит только от пропадания питания.
Какая нибудь другая внезапная гадость типа программного\аппаратного сбоя или разрушение устройства не даст записать последние данные (это из обсуждения реализации регистратора в аварии в московском метро).kasperos
14.10.2015 10:52надежность оборудования в различных ситуациях закладывается на этапе разработки
вы не можете винить разработчиков за то что ваш регистратор расплавился в жерле вулкана и не сохранил данныеAlexsmt
14.10.2015 13:21Естественно, обвинять разработчиков в том, что устройство не выполняет то, чего не требует ТЗ не следует.
А в топике скорее обсуждается вопрос как реализовать хранение актуальных данных, которые переживут внезапное прекращение работы устройства и при этом не затереть флешку до дыр.
Dominikanez
Добивайте EEPROM посредством внедрения FRAM.