Меню

Содержание

Введение

Доброго времени суток. Прошлая моя статья про параметры в EEPROM была, мягко говоря, немного недопонята. Видимо, я как-то криво описал цель и задачу которая решалась. Постараюсь в этот раз исправиться, описать более подробно суть решаемой проблемы и в этот раз расширим границы задачи.

А именно поговорим о том, как хранить параметры, которые необходимо писать в EEPROM постоянно.

Многим может показаться, что это очень специфическая проблема, но на самом деле множество устройств именно этим и занимаются — постоянно пишут в EEPROM. Счетчик воды, тепловычислитель, одометр, всяческие журналы действий пользователя и журналы, хранящие историю измерений, да просто любое устройство, которое хранит время своей работы.

Особенность таких параметров заключается в том, что их нельзя писать просто так в одно и то же место EEPROM, вы просто израсходуете все циклы записи EEPROM. Например, если, необходимо писать время работы один раз в 1 минуту, то нетрудно посчитать, что с EEPROM в 1 000 000 циклов записей, вы загубите его меньше чем за 2 года. А что такое 2 года, если обычное измерительное устройство имеет время поверки 3 и даже 5 лет.

Кроме того, не все EEPROM имеют 1 000 000 циклов записей, многие дешевые EEPROM все еще производятся по старым технологиям с количеством записей 100 000. А если учесть, что 1 000 000 циклов указывается только при идеальных условиях, а скажем при высоких температурах это число может снизиться вдвое, то ваша EEPROM способно оказаться самым ненадежным элементом уже в первый год работы устройства.

Поэтому давайте попробуем решить эту проблему, и сделать так, чтобы обращение к параметрам было столь же простым как в прошлой статье, но при этом EEPROM хватало бы на 30 лет, ну или на 100 (чисто теоретически).

Итак, в прошлой статье, я с трудом показал, как сделать, так, чтобы с параметрами в EEPROM можно было работать интуитивно понятно, не задумываясь, где они лежат и как осуществляется доступ к ним

Напомню:

Для начала проясню, для чего вообще нужно обращаться по отдельности к каждому параметру, этот момент был упущен в прошлой статье. Спасибо товарищам @Andy_Big и @HiSER за замечания.

Все очень просто, существует огромный пласт измерительных устройств, которые используют полевые протоколы такие как HART, FF или PF, где пользовательские команды очень атомарные. Например, в HART протоколе есть отдельные команды — запись единиц изменения, запись верхнего диапазона, запись времени демпфирования, калибровка нуля, запись адрес опроса и т.д. Каждая такая команда должна записать один параметр, при этом успеть подготовить ответ и ответить. Таких параметров может быть до 500 — 600, а в небольших устройствах их около 200.

Если использовать способ, который пользователь @HiSER- это будет означать, что для перезаписи одного параметра размером в 1 byte, я должен буду переписать всю EEPROM. А если алгоритм контроля целостности подразумевает хранение копии параметров, то для 200 параметров со средней длиной в 4 байта, мне нужно будет переписать 1600 байт EEPROM, а если параметров 500, то и все 4000.

Малопотребляющие устройства или устройства, питающиеся от от токовой петли 4-20мА должны потреблять, ну скажем 3 мА, и при этом они должны иметь еще достаточно энергии для питания модема полевого интерфейса, графического индикатора, да еще и BLE в придачу. Запись в EEPROM очень энергозатратная операция. В таких устройствах писать нужно мало и быстро, чтобы средний ток потребления был не высоким.

Очевидно, что необходимо, сделать так, чтобы микроконтроллер ел как можно меньше. Самый простой способ, это уменьшить частоту тактирования, скажем до 500 КГц, или 1 Мгц (Сразу оговорюсь, в надежных применениях использование режима низкого потребления запрещено, поэтому микроконтроллер все время должен работать на одной частоте). На такой частоте, простая передача 4000 байт по SPI займет около 70 мс, прибавим к этому задержку на сохранение данных в страницу (в среднем 7мс на страницу), обратное вычитывание, и вообще обработку запроса микроконтроллером и получим около 3 секунд, на то, чтобы записать один параметр.

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

Но вернемся к нашей основной проблеме — мы хотим постоянно писать параметры.

Серия M25Pxx последовательной Flash-памяти с секторным стиранием

Если рассмотреть различные виды микросхем последовательной долговременной памяти с высокой плотностью, то M25Pxx с тактовой частотой 25 MГц оказываются существенно быстрее, чем многие другие типы схем Flash-памяти с последовательной выборкой. Благодаря их высокой скорости, возможности последовательного считывания, экономичности, малого размера корпусов и небольшой стоимости, семейство последовательной Flash-памяти ST находит широкое применение в различного рода приложениях.

Высокоскоростное низковольтное семейство M25Pxx последовательно считывает и записывает данные по четырехпроводной SPI-совместимой шине с тактовой частотой до 25 MГц. Использование M25Pxx придает дополнительные возможности всем приложениям, требующих быстрой загрузки кода, типа дополнительных плат персонального компьютера, включая графические карты, SCSI и сетевые карты, привод жесткого диска и автомобильные радиоприемники.

Семейство последовательной Flash-памяти ST позволяет загружать в оперативную память 1 Мб за 43 мс при минимальном числе команд, что делает их удобными при использовании. Технические и программные средства защиты предохраняют хранимую информацию от перезаписи.

Для снижения потребляемой мощности эти микросхемы работают от одного источника питания от 2,7 В до 3,6 В и имеют режим пониженного энергопотребления с потребляемым током менее 1 мкА. Кроме того, четырехпроводной интерфейс значительно уменьшает число выводов устройства используемых для управления передачей данных по шине, что обеспечивает высокую интеграцию и меньшую стоимость по сравнению с другими подобными схемами. Микросхемы памяти серии M25Pxx выпускаются в широком и узком S08, LGA и MLP корпусах. Обобщенные данные о параметрах микросхем данной серии представлены в таблице 6.

Таблица 6. Последовательная Flash, шина SPI, высокоскоростная, секторное или полное стирание, 2,7…3,6 В (-V)

Размер Обозначение Описание Корпус
512 кб M25P05-AV 512 кб (x8), 25 МГц шина SPI, 2 сектора по 256 кб, 256 байт страница, последовательное чтение за 21 мс, 4 режима защиты записи SO8, MLP8
1 Мб M25P10-АV 1 Mб (x8), 25 МГц шина PSI, 4 сектора по 256 кб, 256 байт страница, последовательное чтение за 42 мс, 4 режима защиты записи SO8, MLP8
2 Мб M25P20-V 2 Mб (x8), 25 МГц, 4 сектора по 512 кб, 256 байт страница, последовательное чтение за 84 мс, 4 режима защиты записи SO8, MLP8
4 Мб M25PE40-V 4 Mб (x8), 25 МГц, 8 секторов по 512 кб, 256 байт страница, последовательное чтение за 168 мс, 4 режима защиты записи SO8, MLP8
8 Мб M25P80-V 8 Mб (x8), 20 МГц, 16 секторов по 512 кб, 256 байт страница, последовательное чтение за 335 мс, 4 режима защиты записи SO8W, MLP8
16 Mб M25P16-V * 16Mб (X8), 25 MГц, 32 сектора по 512 кб, 256 байт страница, последовательное чтение за 670 мс, 4 режима защиты записи LGA, MLP

* в разработке

Для оценки и программирования M25PXX имеется удобный программатор/считыватель (Рис. 5). Этот программатор подключается непосредственно к компьютеру и обеспечивает пользователю прямой доступ и управление последовательной Flash-памятью M25xxx в любой конфигурации.

Рис. 5. Программатор для М25Рхх

Arduino EEPROM примеры использования

Для начала рассмотрим запись в EEPROM Arduino числа больше, чем 255, например число 999. При записи в EEPROM число 999 будет разбиваться на множитель (старший байт) и недостающее число (младший байт), занимая при этом уже две ячейки в энергонезависимой памяти (т.е. 999 = 3×256 + 231). Чтобы вывести сохраненное число на монитор порта, его нужно будет «собрать» с помощью функции .

Скетч. Запись в память EEPROM int, float

#include <EEPROM.h>  // импортируем библиотеку    int num = 999;                      // разбиваем число на 2 байта  byte hi  = highByte(num);   // старший байт  byte low = lowByte(num);  // младший байт    void setup() {    Serial.begin(9600);    // запускаем монитор порта       EEPROM.update(1, hi);     // записываем старший байт в ячейку 1     EEPROM.update(2, low); // записываем младший байт в ячейку 2      delay(1000);      byte val1 = EEPROM.read(1);  // считываем 1 байт по адресу ячейки    byte val2 = EEPROM.read(2);  // считываем 1 байт по адресу ячейки      Serial.println("highByte - "+String(val1));  // выводим старший байт на монитор    Serial.println("lowByte  - "+String(val2));  // выводим младший байт на монитор      int NUM = word(hi, low);       // "собираем" число из байтов    Serial.println("int num  - "+String(NUM));    // выводим полученное число  }    void loop() {  }

Пояснения к коду:

  1. для записи данных в ячейку в программе использована функция , которая перезаписывает ячейку только в случае различия сохраняемых данных с данными в ячейке EEPROM Arduino Uno;
  2. основная проблема с сохранением больших чисел (int, float) в память EEPROM заключается в том, чтобы случайно не перезаписать нужную ячейку новой информацией. Для этого нужно учитывать размер сохраняемых данных в ПЗУ, используя функции и .

Скетч. Запись строк в EEPROM (String)

#include <EEPROM.h>  // импортируем библиотеку    int address = 10;  // адрес первой ячейки для записи    long cod = 8904; // разбиваем телефонный номер на две части  long tel = 2768282;  String email = ""; // сохраняем в строке адрес почты    long COD; // создаём новые переменные для чистоты эксперимента  long TEL;  String EMAIL;    void setup() {    Serial.begin(9600);  // запускаем монитор порта      EEPROM.put(address, cod);      // сохраняем код телефона в памяти Ардуино    address += sizeof(cod);              // узнаем адрес следующей свободной ячейки    EEPROM.put(address, tel);       // сохраняем номер телефона в памяти Ардуино    address += sizeof(tel);                // узнаем адрес следующей свободной ячейки    EEPROM.put(address, email);  // сохраняем электронную почту в памяти      address = 10;  // адрес первой ячейки для чтения      Serial.print("Phone: ");  // выводим телефонный номер на монитор    Serial.print(EEPROM.get(address, COD));    address += sizeof(COD);    Serial.println(EEPROM.get(address, TEL));    address += sizeof(TEL);      Serial.print("Email: ");  // выводим электронную почту на монитор    Serial.println(EEPROM.get(address, EMAIL));  }    void loop() {  }

Пояснения к коду:

  1. перед сохранением новых данных в памяти, следует узнать размер данных, которые были сохранены, чтобы начать запись в новой ячейке;
  2. удалив из кода строчки для записи данных, вы можете каждый раз при запуске программы считывать все сохраненные данные из ПЗУ Ардуино.

Микросхемы памяти EPROM компании ST

Компания STMicroelectronics (ST) производит весьма конкурентоспособные микросхемы памяти EPROM. Непрерывные усовершенствования технологии производства приводят к расширению их возможностей, более высокой емкости и понижению напряжения питания. Компания находится в числе мировых лидеров-производителей памяти типа OTP и EPROM с ультрафиолетовым стиранием, которая удобна для разработки, производства и для замены масочной ROM ввиду того, что они программируются на завершающей стадии производства.

Выпускаемые микросхемы обладают емкостью от 64 кбит до 64 Мбит при питании 5 и 3 В, достаточным быстродействием, различными корпусами, в том числе и для поверхностного монтажа. Организация памяти устройств может быть типа x8, x16 и x8/x16. Расшифровка обозначений микросхем памяти ST вида OTP и UV EPROM приведена на Рис.5.

Рис. 5. Маркировка микросхем EPROM ST

Набор продукции включает стандартные микросхемы с питанием 5 В и 3,3 В, усовершенствованные микросхемы семейства Tiger Range с питанием 3 В (2,7…3,6 В) и микросхемы нового семейства FlexibleROM.

Микросхемы этих типов памяти доступны в FDIP керамических корпусах с окошком и PDIP пластиковых двурядных корпусах, а также в корпусах PLCC и TSOP для поверхностного монтажа. Основные параметры стандартных микросхем памяти EPROM приведены в таблице 1.

Таблица 1. OTP и UV EPROM

Обьем Обозначение Описание Корпус
Питание 5 В
64 кб M27C64A 64 кб (x8), 100 — 200 нс FDIP28W, PLCC32
256 кб M27C256B 256 кб (x8), 45 — 150 нс FDIP28W, PDIP28, PLCC32, TSOP28
512 кб M27C512 512 кб (x8), 45 — 150 нс FDIP28W, PDIP28, PLCC32, TSOP28
  M27C516 512 кб (x16), 35 — 100 нс PLCC44, TSOP40B
1 Мб M27C1001 1 Мб (x8), 35 — 150 нс FDIP32W, PDIP32, PLCC32, TSOP32A
  M27C1024 1 Мб (x16), 35 — 150 нс FDIP40W, PDIP40, PLCC44, TSOP40B
2 Мб M27C2001 2 Мб (x8), 35 — 100 нс FDIP32W, PDIP32, PLCC32, TSOP32A
  M27C202 2 Мб (x16), 45 — 100 нс FDIP40W, PDIP40, PLCC44, TSOP40B
4 Мб M27C4001 4 Мб (x8), 35 — 150 нс FDIP32W, PDIP32, PLCC32, TSOP32A
  M27C4002 4 Мб (x16), 45 — 150 нс FDIP40W, PDIP40, PLCC44, TSOP40A
  M27C400 4 Мб (x8/x16), 50 — 100 нс FDIP40W, PDIP40
8 Мб M27C801 8 Мб (x8), 45 — 150 нс FDIP32W, PDIP32, PLCC32, TSOP32A
  M27C800 8 Мб (x8/x16), 50 — 120 нс FDIP42W, PDIP42, PLCC44, SO44
16 Мб M27C160 16 Мб (x8/x16), 50 — 120 нс FDIP42W, PDIP42, PLCC44, SO44
32 Мб M27C322 32 Мб (x16), 50 — 100 нс FDIP42W, PDIP42, PSDIP42
  M27C320 32 Мб (x8/x16), 50 — 100 нс TSOP48, SO44
64 Мб* M27C642 64 Мб (x16), 80 — 100 нс FDIP42W, PDIP42
  M27C640 64 Мб (x8/x16), 80 — 100 нс TSOP48
Питание 3,3 В
16 Мб M27V160 16 Мб (x8/x16), 100 — 150 нс FDIP42W, PDIP42, SO44
32 Мб M27V322 32 Мб (x16), 100 — 150 нс FDIP42W, PDIP42

* в разработке

Важные страницы

  • Каталог ссылок на дешёвые Ардуины, датчики, модули и прочие железки с AliExpress у проверенных продавцов
  • Подборка библиотек для Arduino, самых интересных и полезных, официальных и не очень
  • Полная документация по языку Ардуино, все встроенные функции и макро, все доступные типы данных
  • Сборник полезных алгоритмов для написания скетчей: структура кода, таймеры, фильтры, парсинг данных
  • Видео уроки по программированию Arduino с канала “Заметки Ардуинщика” – одни из самых подробных в рунете
  • Поддержать автора за работу над уроками
  • Обратная связь – сообщить об ошибке в уроке или предложить дополнение по тексту (alex@alexgyver.ru)

Возможно, вам также будет интересно

Все статьи цикла: Современные микросхемы памяти. Часть 1, (Компоненты и технологии №4’2002) Современные микросхемы памяти. Часть 2, (Компоненты и технологии №6’2002) Введение Подсистемы памяти являются неотъемлемой частью практически всех современных устройств вычислительной техники, за исключением, пожалуй, некоторых малых контроллеров. В настоящее время в мире насчитывается более ста производителей тех или иных микросхем памяти. Существуют фирмы,

Промышленный ряд тиристоров и триаков (симисторов) Philips предоставляет широкие возможности для создания устройств управления мощностью. Соблюдение же десяти несложных правил по использованию тиристоров и триаков поможет избежать трудностей и ошибок при проектировании. Тиристоры Тиристор — управляемый диод, в котором управление током от анода к катоду происходит за счет малого тока управляющего электрода (затвора). Открытое состояние

Нарушения в работе электросети напряжения переменного тока являются причиной большинства отказов самого различного оборудования. Ущерб от них может быть неуловимым, как, например, случайная потеря данных, так и серьезным, например, выход из строя источника питания, нарушение в работе светодиодного освещения, простой дорогостоящего промышленного оборудования и повреждение медицинской аппаратуры В полной мере это также касается и бытовой техники — электроплит, микроволновых печей, холодильников, персональных компьютеров и телевизоров.

Прерывание по снижению уровня питания

В некоторых процессорах имеется прерывание по низкому уровню питания, которое можно использовать для записи одного последнего значения в EEPROM, в то время как система выключается по потере питания. В общем случае, вы храните интересующее значение в ОЗУ, и сохраняете его в EEPROM только при выключении питания. Или, возможно, вы записываете EEPROM время от времени, и записываете другую копию в EEPROM как часть процедуры выключения, чтобы убедиться, что самые последние данные запишутся

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

Осторожно, тут имеется большое пространство для ошибки!

Запись целых чисел

Запись целых чисел в энергонезависимую память EEPROM осуществить достаточно просто. Внесение чисел происходит с запуском функции EEPROM.write(). В скобках указываются необходимые данные. При этом числа от 0 до 255 и числа свыше 255 записываются по-разному. Первые вносятся просто – их объем занимает 1 байт, то есть одну ячейку. Для записи вторых необходимо использовать операторов highByte() высший байт и lowByte() низший байт.

Число делится на байты и записывается отдельно по ячейкам. Например, число 789 запишется в две ячейки: в первую пойдет множитель 3, а во вторую – недостающее значение. В итоге получается необходимое значение:

3 * 256 + 21 = 789

Для воссоединения» большого целого числа применяется функция word(): int val = word(hi, low). Нужно читывать, что максимальное целое число для записи – 65536 (то есть 2 в степени 16). В ячейках, в которых еще не было иных записей, на мониторе будут стоять цифры 255 в каждой.

Запись чисел с плавающей запятой и строк

Числа с плавающей запятой и строк – это форма записи действительных чисел, где они представляются из мантиссы и показателя степени. Запись таких чисел в энергонезависимую память EEPROM производится с активацией функции EEPROM.put(), считывание, соответственно, – EEPROM.get().

При программировании числовые значения с плавающей запятой обозначаются, как float, стоит отметить, что это не команда, а именно число. Тип Char (символьный тип) – используется для обозначения строк. Процесс записи  чисел на мониторе запускается при помощи setup(), считывание – с помощью loop().

В процессе на экране монитора могут появиться значения ovf, что значит «переполнено», и nan, что значит «отсутствует числовое значение». Это говорит о том, что записанная в ячейку информация не может быть воспроизведена, как число с плавающей точкой. Такой ситуации не возникнет, если достоверно знать, в какой ячейке какой тип информации записан.

Традиционная невеселая рубрика “А что в России?”

И, конечно же, мой рассказ был бы неполон без упоминания о том, что происходит в России. К сожалению, хорошего можно рассказать немного. Производство памяти – это именно что производство, а с микроэлектронными заводами у России довольно печальная ситуация. Соответственно, речи о собственных чипах DRAM и flash-памяти нет и в обозримом будущем не предвидится. А что есть?

Во-первых, есть какое-то количество микросхем SRAM. Самый технологически продвинутый продукт – микросхема 1663РУ1, представляющая собой 16 Мбит статической памяти по нормам 90 нм, производства завода “Микрон”. Кроме этого чипа, есть и другие, в основном предназначенные для аэрокосмических применений.

Во-вторых, «Микрон» на нормах 180 нм имеет опцию производства EEPROM, с максимальным заявленным в серийных продуктах (RFID-микроконтрроллерах) размером блока в 16 кбит. Это отличное решение для недорогих МК, но, к сожалению, мало подходящее для производства больших накопителей информации.

Кроме статической памяти и EEPROM, есть еще одно производство – “Крокус-наноэлектроника”, производящая MRAM. Расположенная в Москве фабрика КНЭ – единственная в России, умеющая работать с пластинами диаметром 300 мм. Правда, Крокус-нано не обладает полным циклом производства, а может делать только металлизацию и совмещенные с ней магнитные слои, формирующие ячейку MRAM. Транзисторная часть при этом должна быть изготовлена на другой фабрике (иностранной, потому что в России с пластинами 300 мм работать некому). На сайте КНЭ заявлена доступность микросхем объемом от 1 до 4 Мбит, скоростью считывания 35 нс и записи 35/90/120/150 нс. Еще немного света на функционирование и происхождение этих чипов проливают также заявленные в качестве продуктов на официальном сайте сложнофункциональные блоки MRAM, совместимые с техпроцессами китайской фабрики SMIC и израильской TowerJazz. Вероятно, именно эти производители являются технологическими партнерами и при производстве собственных чипов КНЭ.

Уменьшить частоту

Самый безболезненный способ решить проблему-это просто записывать данные реже. В некоторых случаях требования к системе это позволяют. Или можно записывать только при каких-либо больших изменениях. Однако, с записью, привязанной к событиям, помните о возможном сценарии, при котором значение будет постоянно колебаться, и вызовет поток событий, которые приведут к износу EEPROM. (Будет неплохо, если вы сможете определить, сколько раз производилась запись в EEPROM. Но это потребует счётчика, который будет храниться в EEPROM… при этом проблема превращается проблему износа счётчика.)

EEPROM Library V2.0 for Arduino

Written by: Christopher Andrews.

This copy is slightly modified, for use with Teensy.

What is the EEPROM library.

Th EEPROM library provides an easy to use interface to interact with the internal non-volatile storage found in AVR based Arduino boards. This library will work on many AVR devices like ATtiny and ATmega chips.

How to use it

The EEPROM library is included in your IDE download. To add its functionality to your sketch you’ll need to reference the library header file. You do this by adding an include directive to the top of your sketch.

The library provides a global variable named , you use this variable to access the library functions. The methods provided in the EEPROM class are listed below.

You can view all the examples here.

Library functions

This function allows you to read a single byte of data from the eeprom.
Its only parameter is an which should be set to the address you wish to read.

The function returns an containing the value read.

The method allows you to write a single byte of data to the EEPROM.
Two parameters are needed. The first is an containing the address that is to be written, and the second is a the data to be written ().

This function does not return any value.

This function is similar to however this method will only write data if the cell contents pointed to by is different to . This method can help prevent unnecessary wear on the EEPROM cells.

This function does not return any value.

This function will retrieve any object from the EEPROM.
Two parameters are needed to call this function. The first is an containing the address that is to be written, and the second is the object you would like to read.

This function returns a reference to the passed in. It does not need to be used and is only returned for conveience.

This function will write any object to the EEPROM.
Two parameters are needed to call this function. The first is an containing the address that is to be written, and the second is the object you would like to write.

This function uses the update method to write its data, and therefore only rewrites changed cells.

This function returns a reference to the passed in. It does not need to be used and is only returned for conveience.

Subscript operator:

This operator allows using the identifier like an array.
EEPROM cells can be read and written directly using this method.

This operator returns a reference to the EEPROM cell.

unsigned char val;

//Read first EEPROM cell.
val = EEPROM;

//Write first EEPROM cell.
EEPROM = val;

//Compare contents
if( val == EEPROM ){
  //Do something...
}

This function returns an containing the number of cells in the EEPROM.

Advanced features

This library uses a component based approach to provide its functionality. This means you can also use these components to design a customized approach. Two background classes are available for use: & .

class

This object references an EEPROM cell.
Its purpose is to mimic a typical byte of RAM, however its storage is the EEPROM.
This class has an overhead of two bytes, similar to storing a pointer to an EEPROM cell.

EERef ref = EEPROM; //Create a reference to 11th cell.

ref = 4; //write to EEPROM cell.

unsigned char val = ref; //Read referenced cell.

class

This object is a bidirectional pointer to EEPROM cells represented by objects.
Just like a normal pointer type, this type can be dereferenced and repositioned using
increment/decrement operators.

EEPtr ptr = 10; //Create a pointer to 11th cell.

*ptr = 4; //dereference and write to EEPROM cell.

unsigned char val = *ptr; //dereference and read.

ptr++; //Move to next EEPROM cell.

This function returns an pointing to the first cell in the EEPROM.
This is useful for STL objects, custom iteration and C++11 style ranged for loops.

This function returns an pointing at the location after the last EEPROM cell.
Used with to provide custom iteration.

Note: The returned is invalid as it is out of range. Infact the hardware causes wrapping of the address (overflow) and actually references the first EEPROM cell.