Защита памяти eeprom
PIC Урок 11. Внутренняя энергонезависимая память EEPROM. Часть 1
Очень многие знают, что в контроллерах PIC помимо основной оперативной памяти, а также памяти для хранения прошивки существует ещё и энергонезависимая память типа EEPROM.
Данная память сделана по технологии электрического стирания информации, что в отличие от её предшественника EPROM, в котором стирание производилось только при помощи ультрафиолетовых лучей, позволило использовать данный тип памяти практически повсеместно. Как мы знаем, ещё существует энергонезависимая память типа Flash, которая стоит намного дешевле, но у которой также есть существенный минус. Там невозможно стереть отдельный байт, стирание производится только блоками, что не совсем удобно в некоторых случаях, особенно когда информации требуется хранить немного, и информация данная представляет собой небольшие настроечные параметры. Поэтому нам стоит также остановиться на данном типе памяти. И причем не только из-за того, что он присутствует в контроллере, а из-за того, что это очень удобно для хранения некоторых величин, которые нужны нам будут даже после того, как контроллер потерял питание.
По идее, с данной памятью мы должны были познакомиться в более ранних занятиях, так как в технической документации на наши микроконтроллеры она находится в одной из первых частей, но мне хотелось для лучшего понимания и запоминания материала показать работу с EEPROM как-то наглядно. Мы подключали с вами четырёхразрядный индикатор, но четырёх разрядов для полноценного показа работы с энергонезависимой памятью, я думаю, мягко говоря, недостаточно, но после прошлого занятия, в котором мы изучили работу с 80-символьным дисплеем LCD, мы можем вполне оценить работу с памятью EEPROM.
Работать мы также будем с контроллером PIC16F877A, расположенном на удобной отладочной плате. Судя по технической документации на данный микроконтроллер, памяти EEPROM у него 256 байт. Этого вроде бы по нынешним меркам не так много, но вполне достаточно, чтобы хранить какую-то информацию, которая должна у нас остаться после отключения питания.
Теперь давайте познакомимся со спецификой работы данной памяти у нашего контроллера, а также с регистрами, используемыми для этого.
Существуют два регистра для записи и чтения памяти EEPROM. Это регистр, в котором хранятся данные, – EEDATA, а также регистр, в который мы посылаем адрес перед записью или чтения определённого байта, – EEADR. Также существует регистр управления EECON1, в котором находятся определённые биты настройки работы с памятью EEPROM, а также есть нефизический регистр EECON2, который мы используем для защиты от случайной записи данной памяти.
Также с помощью определённых конфигурационных битов мы можем защитить память EEPROM от стирания и перезаписи программатором.
Теперь немного подробнее про регистр управления EECON1
Теперь о назначении определённых битов данного регистра.
EEPGD – бит доступа к памяти (относится к памяти Flash)
1 – доступ к памяти для программы,
– доступ к памяти для данных.
WRERR (EEPROM Error Flag bit) — флаг ошибки записи данных в память EEPROM
1 – операция записи данных прервана (случился сброс либо по сигналу MCLR, либо по переполнению WDT в нормальном режиме),
– операция записи данных завершена.
WREN (EEPROM Write Enable bit) – бит разрешения записи данных в память EEPROM
1 – запись данных разрешена,
– запись данных запрещена.
WR (Write Control bit) – включение (инициализация) записи данных в память EEPROM
1 – инициализация цикла записи памяти EEPROM. Включается программно,
– цикл записи EEPROM закончен. Установка в 0 (сброс) осуществляется только аппаратным путём. Программно данный флаг сбросить невозможно.
RD (Read Control bit) – включение (инициализация) чтение данных из памяти EEPROM.
1 – инициализация цикла чтения памяти EEPROM. Включается программно,
– цикл чтения EEPROM закончен. Установка в 0 (сброс) осуществляется только аппаратным путём. Программно данный флаг сбросить также невозможно.
Чтение байта из памяти EEPROM производится следующим образом.
Первым делом мы должны удостовериться, что биты RD и WR регистра EECON1 у нас сброшены, то есть у нас в данный момент все циклы записи/чтения памяти EEPROM завершены. Затем мы записываем в регистр EEADR адрес считываемого байта, затем устанавливаем в 1 бит RD регистра EECON1 и считываем значение регистра EEDATA.
А вот запись байта в память EEPROM в целях безопасности происходит несколько посложнее.
Сначала мы также убеждаемся в сброшенном бите WR, затем разрешаем запись с помощью установки бита WREN регистра EECON1. Затем желательно запретить прерывания с помощью сброса бита GIE регистра INTCON, перед этим сохранив его значение, а то вдруг он уже был сброшен. А вот теперь мы делаем интересную вещь. Мы последовательно передаём байты 0x55 и 0xAA в регистр ЕЕСОN2. И только после этого мы пишем данные в память EEPROM, устанавливая бит инициализации записи WR. Затем мы возвращаем значение бита GIE в регистр INTCON, разрешив тем самым глобальные прерывания, если они до этого были разрешены. Потом мы сбрасываем бит WREN.
Чтобы нам теперь данную теорию понять и закрепить, мы должны отработать это на практике.
Поэтому создадим проект с именем EEPROM_LCD на основе проекта прошлого занятия LCD2004_8BIT.
Подключим нашу схему вместе с программатором и дисплеем, блок питания пока в целях безопасности не подключаем.
Откроем данный проект в MPLAB X, зайдём в его настройки и убедимся, что у нас схема не будет питаться от программатора и сохраним настройки проекта.
Теперь мы можем смело подключить блок питания, также попытаться собрать наш проект и прошить его в контроллер. Работоспособность нашего кода мы поймём по появившимся строкам на дисплее
Создадим каркас нашей будущей библиотеки для работы с памятью EEPROM с помощью двух файлов EEPROM.h и EEPROM.c следующего стандартного содержания
EEPROM.h:
#ifndef _EEPROM_H_H
#define _EEPROM_H_H
#include // include processor files — each processor file is guarded.
#endif /* _EEPROM_H */
EEPROM.c:
#include «EEPROM.h»
Также нашу библиотеку, а заодно и строковую, подключим в файле main.h
#include «EEPROM.h»
#include
Вернёмся в файл EEPROM.c и напишем функцию записи байта в память EEPROM по определённому адресу, руководствуясь объяснению, как это делается, написанному выше. Заодно сразу добавим и функцию чтения байта по определённому адресу
void EEPROM_WriteByte ( unsigned char addr, unsigned char dt)
unsigned char status;
while (WR);
EEADR = addr;
EEDATA = dt;
WREN= 1 ;
status = GIE;
GIE = 0 ;
EECON2 = 0x55 ;
EECON2 = 0xAA ;
WR= 1 ;
GIE = status;
WREN= 0 ;
unsigned char EEPROM_ReadByte( unsigned char addr)
while (RD || WR);
EEADR=addr;
RD = 1 ;
return EEDATA;
Также нам будет интересно писать и читать данные других типов.
Добавим функции записи и чтения двухбайтовой целочисленной беззнаковой величины в память EEPROM и из неё
void EEPROM_WriteWord( unsigned char addr, unsigned int ucData)
EEPROM_WriteByte(addr, ( unsigned char ) ucData);
unsigned char dt = ucData>> 8 ;
EEPROM_WriteByte(addr +1 , dt);
unsigned int EEPROM_ReadWord( unsigned char addr)
unsigned int dt = EEPROM_ReadByte(addr +1 )* 256 ;
dt += EEPROM_ReadByte(addr);
return dt;
Здесь у нас всё ещё проще. Мы читаем и пишем раздельно старший и младший байты, пользуясь уже добавленными функциями чтения и записи байтов.
Теперь добавим ещё функции записи и чтения четырёхбайтовых величин (двойных слов)
void EEPROM_WriteDword( unsigned char addr, unsigned long ucData)
EEPROM_WriteWord(addr, ( unsigned int ) ucData);
unsigned int dt = ucData>> 16 ;
EEPROM_WriteWord(addr +2 , dt);
unsigned long EEPROM_ReadDword( unsigned char addr)
unsigned long dt = EEPROM_ReadWord(addr +2 )* 65536 ;
dt += EEPROM_ReadWord(addr);
return dt;
Функции написаны в аналогичном стиле, только внутри используются функции записи и считывания двухбайтовых величин.
Теперь давайте запишем строку символов по определённому адресу
void EEPROM_WriteString( unsigned char addr, char * str1)
unsigned char n;
for (n= 0 ;str1[n]!= ‘