EEPROM у классических AVR — отдельное от флеш-памяти пространство в сотни байт или несколько килобайт, которое читается и пишется по одному байту и не теряет данные без питания. В нём держат калибровки, настройки и счётчики. Калькулятор отвечает на три вопроса, которые возникают при работе с ним: где лягут переменные, на сколько хватит ресурса и что сделать, чтобы данные не портились.
Объём и время записи
| Микроконтроллер | EEPROM | Запись байта из программы | Ожидание у программатора (tWD_EEPROM) |
|---|---|---|---|
| ATmega328P | 1 КБ | 3,4 мс (3,3 мс в табл. 8-2) | 3,6 мс |
| ATmega32U4 | 1 КБ | 3,4 мс | 9,0 мс |
| ATmega2560 | 4 КБ | 3,4 мс | 3,6 мс |
| ATmega8, ATmega16 | 512 байт | 8,5 мс | 9,0 мс |
| ATmega32 | 1 КБ | 8,5 мс | 9,0 мс |
| ATtiny85 | 512 байт | 3,4 мс | 4,0 мс |
| ATtiny13A | 64 байта | 3,4 мс | 4,0 мс |
| ATtiny2313A | 128 байт | 3,4 мс | 4,0 мс |
Время записи отсчитывает внутренний калиброванный RC-генератор, поэтому от тактовой частоты процессора оно не зависит. У ATmega328P даташит даёт два близких значения: 3,4 мс в таблице режимов EEPM и 3,3 мс — 26 368 тактов генератора 8 МГц — в таблице времени программирования; калькулятор считает по большему. У новых AVR биты EEPM1:0 позволяют разделить стирание и запись по 1,8 мс: байт стирают заранее, а в спешке, например при пропадании питания, только записывают.
Размер страницы (4 или 8 байт) важен только программатору, который может загружать EEPROM страницами. Программа пишет по одному байту, и пока идёт запись, остальные обращения к EEPROM невозможны: следующий байт ждёт сброса бита EEPE.
Ресурс и выравнивание износа
Каждый байт EEPROM выдерживает не меньше 100 000 циклов стирания и записи. Ресурс тратит только запись, и тратит его тот байт, который перезаписывается чаще всего. Если сохранять 16-байтную структуру раз в минуту на одно место, 100 000 циклов закончатся примерно через 69 суток.
Простое выравнивание — кольцо копий. Область EEPROM делят на ячейки размером «запись + служебный байт», каждое сохранение кладут в следующую ячейку, а в служебный байт пишут счётчик, по которому после сброса находят самую новую копию. Если копий N, каждая ячейка перезаписывается в N раз реже. В 1 КБ помещается 60 копий по 17 байт, и та же структура раз в минуту проживёт около 11 лет.
Калькулятор показывает обе цифры и прямо помечает их как оценку: он берёт гарантированный минимум даташита и считает, что при каждом сохранении меняются все байты. Функции eeprom_update_* из avr-libc читают байт перед записью и не трогают совпадающие, так что неизменные поля не изнашиваются.
Запись по регистрам
Регистры EEPROM — адрес EEARH:EEARL (у ATtiny13A и ATtiny2313A один EEAR), данные EEDR и управление EECR. Порядок записи по даташиту ATmega328P:
- Дождаться, пока сбросится EEPE: предыдущая запись закончилась.
- Если программа сама пишет во флеш-память (загрузчик, SPM), дождаться сброса SPMEN.
- Записать адрес в EEAR и данные в EEDR.
- Установить EEMPE, сбросив при этом EEPE.
- Не позже чем через четыре такта установить EEPE.
EEMPE сам сбрасывается через четыре такта, поэтому прерывание между шагами 4 и 5 срывает запись — на это время прерывания запрещают. Окно в четыре такта выдерживает только оптимизированная сборка (например, -Os), где обе записи в EECR — по одной команде; без оптимизации вторая запись может опоздать. В сгенерированном коде шаг 4 записан как EECR = (1 << EEMPE): так заодно обнуляются биты EEPM1:0 (режим «стирание + запись») и EERIE, то есть прерывание готовности EEPROM выключается — если оно нужно, включите его снова после записи. Для чтения достаточно записать адрес и установить EERE: данные появляются в EEDR сразу, процессор при этом стоит четыре такта. У ATmega8, ATmega16 и ATmega32 те же биты называются EEMWE и EEWE, а режимов EEPM нет.
Порча данных при низком питании
Главная причина испорченной EEPROM — не износ, а работа при недостаточном напряжении: при медленном спаде питания процессор продолжает выполнять программу ниже допустимого для своей частоты и может записать мусор. Даташит советует держать микроконтроллер в сбросе, пока питания не хватает, — детектором BOD или внешним супервизором.
Калькулятор сравнивает порог BOD с напряжением, нужным для выбранной частоты. У ATmega328P допустимая частота растёт линейно от 4 МГц при 1,8 В до 10 МГц при 2,7 В и до 20 МГц при 4,5 В, так что для 16 МГц нужно не меньше 3,78 В. У Arduino Uno фьюзы выставляют BOD 2,7 В, а его нижняя граница по даташиту — 2,5 В: между 2,5 и 3,78 В процессор работает вне гарантированной области. Если EEPROM важна, на 16 МГц выбирают порог 4,3 В. Пороги и их коды для всех микроконтроллеров есть в калькуляторе фьюзов AVR.
Ещё одна неожиданность — стирание EEPROM программатором. Команда Chip Erase стирает и флеш-память, и EEPROM, если не запрограммирован фьюз EESAVE; у Arduino Uno он не запрограммирован.
Переменные EEMEM и файл .eep
Атрибут EEMEM из avr-libc кладёт переменную в секцию .eeprom. Порядок отдельных глобальных переменных в секции компилятор не обещает, поэтому калькулятор собирает поля в одну структуру: у AVR нет выравнивания, поля идут подряд, многобайтные значения хранятся младшим байтом вперёд, float — в формате IEEE 754 одинарной точности.
Начальные значения из инициализатора попадают в файл .eep — Intel HEX с адресами от начала EEPROM. Калькулятор показывает этот файл и дамп памяти после его записи; разобрать готовый файл можно в просмотрщике HEX-файлов, а как появляются .hex и .eep при сборке — в статье о файлах прошивки.
Частые вопросы
Сколько раз можно записать EEPROM ATmega328P?
Даташит гарантирует не меньше 100 000 циклов записи и стирания для каждого байта. Если сохранять одну и ту же переменную раз в минуту, этого хватит примерно на 69 суток; если раз в час — на 11 лет. Ресурс расходует только запись: чтение EEPROM не изнашивает. Чтобы растянуть ресурс, данные пишут по кругу в несколько копий, а eeprom_update_* не перезаписывают байты, которые не изменились.
Сколько длится запись байта в EEPROM AVR?
У ATmega328P, ATmega2560, ATmega32U4 и ATtiny — около 3,3–3,4 мс на байт: стирание и запись идут одной операцией, их отсчитывает внутренний калиброванный RC-генератор, поэтому время не зависит от тактовой частоты. У старых ATmega8, ATmega16 и ATmega32 — 8,5 мс. Структура из 17 байт записывается почти 60 мс, и всё это время питание должно держаться.
Почему портится EEPROM AVR при выключении питания?
Когда напряжение медленно падает, процессор какое-то время работает ниже допустимого для своей частоты и может выполнить команды неверно, в том числе записать мусор в EEPROM. Даташит советует держать микроконтроллер в сбросе при недостаточном питании — включить детектор BOD с подходящим порогом или поставить внешний супервизор. Начатая запись байта при сбросе доводится до конца, если напряжения хватает.
Как записать начальные значения EEPROM вместе с прошивкой?
Переменные с атрибутом EEMEM и инициализатором попадают в секцию .eeprom, из которой при сборке получается отдельный файл .eep в формате Intel HEX. Его записывают программатором: avrdude -U eeprom:w:firmware.eep:i. Загрузка скетча через загрузчик Arduino этот файл не записывает.
Источники
- Microchip. ATmega48A/PA/88A/PA/168A/PA/328/P Data Sheet (DS40002061B) — 8.4 — 1 КБ EEPROM, не меньше 100 000 циклов записи и стирания; 8.4.1 — при чтении процессор стоит 4 такта, при записи 2; 8.4.2 — порча EEPROM при низком VCC, совет держать сброс через BOD; 8.6.3 — EECR, порядок записи и EEMPE → EEPE за 4 такта; табл. 8-1 — EEPM: 3,4 мс стирание с записью, 1,8 мс по отдельности; табл. 8-2 — 26 368 тактов RC-генератора, 3,3 мс; табл. 28-12 — страницы по 4 байта; табл. 28-18 — tWD_EEPROM 3,6 мс; табл. 29-12 — пороги BOD; 29.3 — частота от напряжения линейна между 1,8, 2,7 и 4,5 В; фьюз EESAVE
- Microchip (Atmel). ATmega640/1280/1281/2560/2561 datasheet (2549Q) — табл. 8-1 — 26 368 тактов, 3,3 мс; табл. 9-1 — режимы EEPM; табл. 30-8 — 4 КБ страницами по 8 байт; табл. 30-16 — tWD_EEPROM 3,6 мс; табл. 31-6 — пороги BOD; 31.2 — исполнения 2560 и 2560V
- Microchip (Atmel). ATmega16U4/32U4 datasheet (Atmel-7766J) — табл. 5-2 и 5-3 — режимы EEPM и 3,3 мс; табл. 28-12 — страницы; табл. 28-15 — tWD_EEPROM 9,0 мс; табл. 8-1 — семь порогов BOD от 2,0 до 4,3 В; 29.6 — 8 МГц при 2,7 В и 16 МГц при 4,5 В
- Microchip (Atmel). Даташиты ATmega8(L) 2486AA, ATmega16(L) 2466T, ATmega32(L) 2503Q — табл. 1 — 8448 тактов генератора 1 МГц, 8,5 мс; биты EEMWE и EEWE без режимов EEPM; табл. 90, 108, 107 — страницы по 4 байта; tWD_EEPROM 9,0 мс (табл. 97, 115, 114); табл. 15 — BODEN и BODLEVEL: 2,7 или 4,0 В; исполнения L (8 МГц от 2,7 В) и обычные (16 МГц от 4,5 В)
- Microchip (Atmel). Даташиты ATtiny25/45/85 (2586Q), ATtiny13A (DS40002307A), ATtiny2313A/4313 (8246B) — режимы EEPM — 3,4 и 1,8 мс (табл. 5-1, 5-1, 5-4); страницы по 4 байта (табл. 20-9, 17-6, 21-2); tWD_EEPROM 4,0 мс; пороги BOD 1,8/2,7/4,3 В (табл. 21-7, 18-6, 22-5 — у ATtiny2313A в таблице напечатаны двухбитные коды, а фьюзов BODLEVEL три)
- avr-libc. avr/eeprom.h и заголовки устройств (репозиторий avrdudes/avr-libc) — EEMEM — секция .eeprom; данные хранятся младшим байтом вперёд без выравнивания; eeprom_update_* сначала читают байт и не пишут совпадающий; функции ждут EEPE, но не SPMEN; не реентерабельны; пишут в режиме «стирание + запись». E2END и E2PAGESIZE в iom328p.h, iomxx0_1.h, iotnx5.h и других — второй источник размеров для тестов
- Arduino. ArduinoCore-avr, boards.txt — Arduino Uno: 16 МГц, фьюзы high 0xDE (EESAVE не запрограммирован) и extended 0xFD (BOD 2,7 В)
Где пригодится
- Как сохранить настройки ESP32, чтобы они не пропадали после выключения?NVS во флеш-памяти, в Arduino — Preferences вместо EEPROM
- Как записать структуру в EEPROM AVR?EEPROM.put / eeprom_update_block, версия структуры, 3,4 мс на байт
- Почему стирается EEPROM при прошивке Arduino?ISP делает Chip Erase, а EESAVE у Uno не запрограммирован
Встроить калькулятор на свой сайт
Скопируйте код и вставьте его в HTML страницы, статьи или вики. Виджет бесплатный, без рекламы, счётчиков и cookie. Условие одно — ссылка на GAW под рамкой остаётся на месте. Подробнее о виджетах
<iframe src="https://gaw.ru/embed/avr-eeprom/" title="EEPROM AVR: раскладка, ресурс записи и код" width="100%" height="640" style="border:1px solid #e3e5e9;border-radius:8px" loading="lazy" allow="clipboard-write"></iframe>
<p style="margin:6px 0 0;font-size:14px">Калькулятор: <a href="https://gaw.ru/tools/avr-eeprom/">EEPROM AVR: раскладка, ресурс записи и код</a> — GAW.ru</p>Автоподстройка высоты рамки
Если сайт разрешает скрипты, добавьте этот код один раз в любом месте страницы: рамка будет менять высоту вместе с результатом расчёта.
<script>window.addEventListener("message",function(e){if(e.origin!=="https://gaw.ru"||!e.data||e.data.type!=="gaw:embed-height")return;var f=document.querySelectorAll('iframe[src^="https://gaw.ru/embed/"]');for(var i=0;i<f.length;i++)if(f[i].contentWindow===e.source)f[i].style.height=e.data.height+"px"})</script>Обновлено .
Нашли ошибку в расчёте?