Страница 1 из 1

Запись во внутренюю EEPROM

Добавлено: Вс авг 07, 2016 08:22:05
kotriks
Ребята помогите реализовать запись во внутренюю еепром, щас у меня стоит внешняя память но решил откинуть дабы жрало меньше.
На внешней запись в еепром была так реализована

Код: Выделить всё

void writeData(unsigned char c1){ 
i2c_start(); 
i2c_write(0xa0);
i2c_write(addr>>8); 
i2c_write(addr & 0x00FF); 
page_stop_status=0;     

i2c_write(c1); 
    
} 
из даташита запись, чтение

Код: Выделить всё

void EEPROM_write(unsigned int uiAddress, unsigned char ucData)
{
/* Wait for completion of previous write */
while(EECR & (1<<EEPE))
;
/* Set up address and Data Registers */
EEAR = uiAddress;
EEDR = ucData;
/* Write logical one to EEMPE */
EECR |= (1<<EEMPE);
/* Start eeprom write by setting EEPE */
EECR |= (1<<EEPE);
}

unsigned char EEPROM_read(unsigned int uiAddress)
{
/* Wait for completion of previous write */
while(EECR & (1<<EEPE))
;
/* Set up address register */
EEAR = uiAddress;
/* Start eeprom read by writing EERE */
EECR |= (1<<EERE);
/* Return data from Data Register */
return EEDR;
}
как реализовать запись с продолжением, тоесть не стирая старых данных дописывая их. ну и чтение всез данных из еепром по юарт.

Re: Запись во внутренюю EEPROM

Добавлено: Вс авг 07, 2016 08:53:03
uk8amk
Не понятно в чём проблема.
Доступ к байту внутренней EEPROM происходит независимо от содержимого остальных байт.

Код: Выделить всё

EEPROM_write(Address+0, Data1);
EEPROM_write(Address+1, Data2);
EEPROM_write(Address+2, Data3);

EEPROM_write(Address2+99, Data1);
EEPROM_write(Address2+0, Data2);
EEPROM_write(Address2+2, Data3);

Re: Запись во внутренюю EEPROM

Добавлено: Вс авг 07, 2016 08:54:13
COKPOWEHEU
Разработчики компиляторов часто пишут свои функции для работы с EEPROM, так что по регистрам лазать не обязательно. Например, в gcc это заголовочный файл <avr/eeprom.h> и функции eeprom_read_byte(), eeprom_read_word() и т.д.
Что значит "запись с продолжением"?
Можно использовать переменную в качестве адреса последнего записанного байта, тогда при каждом включении запись будет начинаться с начала.
Можно пожертвовать частью диапазона входных данных для флага конца записанной области. Например, записываете значения 10-битного АЦП, то есть 16-битные числа в диапазоне 0x0000 - 0x3FF, тогда флагом конца записи может быть чистая EEPROM - 0xFFFF. Если для того же АЦП используете 8-битную точность, можно объединить значения 0xFE и 0xFF (считать что напряжения, соответствующим значениям, равны и вместо 0xFF записывать 0xFE), тогда флагом конца станет число 0xFF.
Можно отвести переменную в EEPROM, которая бы считала число записанных байт. Правда, у EEPROM ограничен ресурс перезаписи, но и тут можно извращаться. Например, завести указатель на две переменные - на количество записанных байт и на количество перезаписей первой переменной. Меняться они будут синхронно. Когда дойдете до определенного предела - указатель перескакивает с изношенных ячеек на новые и можно пользоваться дальше. Уж 10 миллионов перезаписей вам наверняка хватит.
В общем, зависит от задачи.

Re: Запись во внутренюю EEPROM

Добавлено: Вс авг 07, 2016 09:14:39
kotriks
COKPOWEHEU писал(а):Разработчики компиляторов часто пишут свои функции для работы с EEPROM, так что по регистрам лазать не обязательно. Например, в gcc это заголовочный файл <avr/eeprom.h> и функции eeprom_read_byte(), eeprom_read_word() и т.д.
Что значит "запись с продолжением"?
Можно использовать переменную в качестве адреса последнего записанного байта, тогда при каждом включении запись будет начинаться с начала.
Можно пожертвовать частью диапазона входных данных для флага конца записанной области. Например, записываете значения 10-битного АЦП, то есть 16-битные числа в диапазоне 0x0000 - 0x3FF, тогда флагом конца записи может быть чистая EEPROM - 0xFFFF. Если для того же АЦП используете 8-битную точность, можно объединить значения 0xFE и 0xFF (считать что напряжения, соответствующим значениям, равны и вместо 0xFF записывать 0xFE), тогда флагом конца станет число 0xFF.
Можно отвести переменную в EEPROM, которая бы считала число записанных байт. Правда, у EEPROM ограничен ресурс перезаписи, но и тут можно извращаться. Например, завести указатель на две переменные - на количество записанных байт и на количество перезаписей первой переменной. Меняться они будут синхронно. Когда дойдете до определенного предела - указатель перескакивает с изношенных ячеек на новые и можно пользоваться дальше. Уж 10 миллионов перезаписей вам наверняка хватит.
В общем, зависит от задачи.
с продолжением значит не затирая старые данные записал в 1 яйчейку выключил девайс включил записал ещёё он дальше в след яйчеку записал.

Re: Запись во внутренюю EEPROM

Добавлено: Вс авг 07, 2016 11:06:47
kotriks
с записью я разобрался,

Код: Выделить всё

volatile unsigned int addrr = 0;

void write(unsigned char c1){ 

EEPROM_write(addrr, c1); 
addrr = addrr + 1;
if (addrr == 512)
    addrr = 0;
}
а вот как читать с еепром с выводлом в терминал не могу понять :(

Re: Запись во внутренюю EEPROM

Добавлено: Вс авг 07, 2016 13:39:08
kotriks
читает всю память

Код: Выделить всё

for (i = 0; i < 512; i++)
    putchar(EEPROM_read(i));
не знаю можно на внутренней реализовать запись с того месте где закончилась, запись после перезагрузки процессора, а то он постоянно с начала пишет.

Re: Запись во внутренюю EEPROM

Добавлено: Вс авг 07, 2016 14:26:39
COKPOWEHEU
kotriks писал(а): с продолжением значит не затирая старые данные записал в 1 яйчейку выключил девайс включил записал ещёё он дальше в след яйчеку записал.
Зачем спрашивать если не читаете ответов? Я написал несколько способов как это делается. Точно можно сказать только зная задачу.
а то он постоянно с начала пишет.
Он пишет не "с начала" а в ту и только ту ячейку которую ему укажут.

Re: Запись во внутренюю EEPROM

Добавлено: Вс авг 07, 2016 14:48:32
kotriks
но как сделать указатель чтобы запись шла в пустую следующюю яйчейку, а не уже записанную?? :(

Re: Запись во внутренюю EEPROM

Добавлено: Вс авг 07, 2016 17:17:48
COKPOWEHEU
Ну вам что, код написать?
Ладно, вот вариант с хранением количества байт в ОЗУ

Код: Выделить всё

void eeprom_append_byte(char data){
  static uint8_t *pos = NULL; //чтобы не было предупреждения о переводе uint8_t --> char
  eeprom_write_byte(pos, data);
  pos++;
}
и вариант с хранением в EEPROM

Код: Выделить всё

#define COUTN_POS 0x00F0
void eeprom_append_byte(char data){
  uint8_t *pos;
  eeprom_read_block(&pos, (void*)COUNT_POS, sizeof(uint8_t*)); //немного магии с преобразованием типов переменных
  eeprom_write_byte(pos,data);
  pos++;
  eeprom_write_block((void*)COUNT_POS, &pos, sizeof(uint8_t));
}

Re: Запись во внутренюю EEPROM

Добавлено: Вс авг 07, 2016 20:37:48
uk8amk
Нужно определиться что произойдёт по достижении конца памяти. Если запись на этом останавливается, то достаточно проверить свободны ли оставшиеся ячейки памяти. Если же память представляет собой что-то вроде кольцевого буфера, то подход зависит от записываемой информации. Например одометр на приборной панели одного автомобиля считает пройденные километры и записывает с определённым интервалом значения в EEPROM. При включении достаточно просканировать память, максимальное значение и будет самой последней записью. Другой пример. Устройство хранит журнал событий за несколько лет. С каждой записью сохраняется 32-разрядный идентификатор(по сути счётчик). Это позволяет генерировать уникальные идентификаторы в течение десятков лет, т.е. значительно больше чем предполагаемый срок службы оборудования.

Re: Запись во внутренюю EEPROM

Добавлено: Пн авг 08, 2016 03:03:10
kotriks
COKPOWEHEU писал(а):Ну вам что, код написать?
Ладно, вот вариант с хранением количества байт в ОЗУ

Код: Выделить всё

void eeprom_append_byte(char data){
  static uint8_t *pos = NULL; //чтобы не было предупреждения о переводе uint8_t --> char
  eeprom_write_byte(pos, data);
  pos++;
}
и вариант с хранением в EEPROM

Код: Выделить всё

#define COUTN_POS 0x00F0
void eeprom_append_byte(char data){
  uint8_t *pos;
  eeprom_read_block(&pos, (void*)COUNT_POS, sizeof(uint8_t*)); //немного магии с преобразованием типов переменных
  eeprom_write_byte(pos,data);
  pos++;
  eeprom_write_block((void*)COUNT_POS, &pos, sizeof(uint8_t));
}
Спасибо канешно, но откуда вы такие переменные берёте в код вижене иж нет :)
Нужно определиться что произойдёт по достижении конца памяти. Если запись на этом останавливается, то достаточно проверить свободны ли оставшиеся ячейки памяти. Если же память представляет собой что-то вроде кольцевого буфера, то подход зависит от записываемой информации. Например одометр на приборной панели одного автомобиля считает пройденные километры и записывает с определённым интервалом значения в EEPROM. При включении достаточно просканировать память, максимальное значение и будет самой последней записью. Другой пример. Устройство хранит журнал событий за несколько лет. С каждой записью сохраняется 32-разрядный идентификатор(по сути счётчик). Это позволяет генерировать уникальные идентификаторы в течение десятков лет, т.е. значительно больше чем предполагаемый срок службы оборудования.
по окончанию памяти я вставил while(1); чтобы проц в ступор вставал :)

Re: Запись во внутренюю EEPROM

Добавлено: Пн авг 08, 2016 06:42:42
COKPOWEHEU
Что значит откуда я беру такие переменные? Я их в коде объявляю, это обычный способ для Си. Единственное что специфично именно для avr-gcc это eeprom_read_byte(), eeprom_read_block(), eeprom_write_block(), их вам придется менять на свои аналоги.

Re: Запись во внутренюю EEPROM

Добавлено: Пн авг 08, 2016 07:42:10
Аlex
kotriks писал(а): Спасибо канешно, но откуда вы такие переменные берёте в код вижене иж нет :)
А чё, в кодевижене разве нет функций записи и чтения EEPROM ?
Совершенно не понятно, в чём проблема :dont_know:

Re: Запись во внутренюю EEPROM

Добавлено: Пн авг 08, 2016 15:43:00
COKPOWEHEU
С cvavr не работал, так что могу ошибаться. Но вроде там функций работы с EEPROM и flash нет. Вместо этого каким-то образом (сегменты памяти что ли?) помечается каждая переменная и работа с ними идет как с обычными, без спецфункций, то есть особенности работы с EEPROM и flash возложены на компилятор.

Re: Запись во внутренюю EEPROM

Добавлено: Пн авг 08, 2016 18:29:52
Барсик
COKPOWEHEU писал(а):то есть особенности работы с EEPROM и flash возложены на компилятор.
Так оно и есть. Объявил переменную как eeprom и дело в шляпе. Пиши в неё просто операцией присвоения и читай так же. Причём этот CodeVision хитрый. Перед тем как писать в EEPROM, он, сволочь, проверяет что уже там записано. Если то же самое, что требуется записать, то ничего туда не пишет. Я смотрел осциллографом реальное время записи в EEPROM, и чуть мозг себе не сломал. Не мог понять, почему в одном случае это время, как и полагается, миллисекунды, а в другом - микросекунды.

Re: Запись во внутренюю EEPROM

Добавлено: Пн авг 08, 2016 21:25:36
Alkul
Простите, я может чего не понимаю, но в даташите на AVR-контроллеры есть примеры записи и чтения EEPROM как на асме, так и на Си.
В чем проблема самому написать функцию, используя Си-шный код из даташита?
При чем тут функции кодевижна? Есть язык Си, в котором программист может создать совершенно любую функцию.
Или я не прав?

Re: Запись во внутренюю EEPROM

Добавлено: Пн авг 08, 2016 22:36:09
COKPOWEHEU
Правы, но зачем изобретать велосипед? Тем более что разработчики компилятора должны, по идее, лучше разбираться в особенностях контроллеров, чем любители. Вон, гуру cvavr утверждает, что при тамошнем способе ячейка сначала проверяется, могут запрещаться прерывания, могут быть ассемблерные вставки и так далее. Кроме того, это более стандартизованный способ, а значит, лучше в плане читаемости.
Но, разумеется, никто вам не запретит пользоваться своими функциями.

Re: Запись во внутренюю EEPROM

Добавлено: Вт авг 09, 2016 04:13:35
Alkul
COKPOWEHEU писал(а):Правы, но зачем изобретать велосипед? Тем более что разработчики компилятора должны, по идее, лучше разбираться в особенностях контроллеров, чем любители.
Да какой там, помилуй бог, велосипед? Там все просто, как три копейки. Два служебных регистра и регистровая пара адреса. Любитель, если он хочет в этой сфере как-то расти, должен изучать матчасть. Я понимаю, что программирование на Си, особенно у новичков, вообще не способствует изучению особенностей применяемого МК - зачем? есть компилятор, он все знает. Прямо как фонвизинский Митрофанушка: "зачем знать географию, есть извозчик, он довезет".
COKPOWEHEU писал(а):Вон, гуру cvavr утверждает, что при тамошнем способе ячейка сначала проверяется, могут запрещаться прерывания, могут быть ассемблерные вставки и так далее. Кроме того, это более стандартизованный способ, а значит, лучше в плане читаемости.
Ну, наворотить можно много чего. Тем не менее, под спойлером я еще раз привожу Си-шные функции для чтения и записи байта из даташита на МК. Какая религия может запретить их применение? Не зная, какой МК использует тредстартер, привожу функции из даташита на "народную" ATmeg'у 8. Но не думаю, что для других МК эти функции будут отличаться. Естественно, что для использования этих функций надо файл-описатель МК подключать. Либо самому объяснить компилятору, что такое эти EEAR, EEDR и т.д.
Очевидно, что если автор использует прерывания, то в этих функциях перед началом циклов записи-чтения прерывания надо запрещать, а в конце функции - разрешать. Еще красивее - сначала проверить бит I регистра SREG, и если он установлен, то прерывания запрещать, в конце снова разрешать, а если бит сброшен, то ничего не делать с прерываниями.
Спойлер

Код: Выделить всё

void EEPROM_write(unsigned int uiAddress, unsigned char ucData)
{
/* Wait for completion of previous write */
while(EECR & (1<<EEWE))
;
/* Set up address and data registers */
EEAR = uiAddress;
EEDR = ucData;
/* Write logical one to EEMWE */
EECR |= (1<<EEMWE);
/* Start eeprom write by setting EEWE */
EECR |= (1<<EEWE);
}

unsigned char EEPROM_read(unsigned int uiAddress)
{
/* Wait for completion of previous write */
while(EECR & (1<<EEWE))
;
/* Set up address register */
EEAR = uiAddress;
/* Start eeprom read by writing EERE */
EECR |= (1<<EERE);
/* Return data from data register */
return EEDR;
}
По-моему, у авторе проблемы не с доступом к EEPROM, а с алгоритмизированием вообще.
Вот, к примеру, делать вот так
kotriks писал(а):по окончанию памяти я вставил while(1); чтобы проц в ступор вставал :)
в общем случае неправильно. Не должен МК уходить в бесконечный цикл при невозможности записи в EEPROM. И вообще в любую память. А еще шире - при невозможности любого действия МК не должен "зависать".

Если запись дошла до конца EEPROM, очевидно, что надо начинать запись сначала. А если там настолько важные данные, которые нельзя потерять, значит, надо принимать меры к тому, чтобы такая ситуация в принципе не могла произойти.
kotriks писал(а):но как сделать указатель чтобы запись шла в пустую следующюю яйчейку, а не уже записанную?? :(
Вам уже пример программы привели, но я просто продублирую саму идею.
По фиксированному адресу (например, 0х00) в EEPROM выделяете необходимое кол-во байт, в зависимости от объема EEPROM, в которых храните адрес первой свободной ячейки в EEPROM. После старта МК читаете содержимое ячеек, хранящих адрес свободной ячейки и вуаля, используете этот адрес в функциях чтения или записи. После каждой записи в EEPROM инкрементировать адрес и переписывать ячейки, хранящие адрес. Все. Если дошли до конца EEPROM, то следующий адрес вычисляется, как 0х00+количество ячеек, хранящих адрес.
Напишите свою функцию, производящую все эти действия, при этом для физических актов чтения-записи ваша функция должна пользоваться теми функциями, которые я показал выше.
Для корректной работы в исходном состоянии нужно создать и файл *.eep, в котором в адресных ячейках разместить первый свободный адрес и вместе с заливкой программы прошить и EEPROM.
А можно использовать на адрес, а смещение, это как удобней, для EEPROM особой разницы нет.
Задача-то элементарная.

Re: Запись во внутренюю EEPROM

Добавлено: Ср авг 10, 2016 10:03:30
kotriks
COKPOWEHEU писал(а):Ну вам что, код написать?
Ладно, вот вариант с хранением количества байт в ОЗУ

Код: Выделить всё

void eeprom_append_byte(char data){
  static uint8_t *pos = NULL; //чтобы не было предупреждения о переводе uint8_t --> char
  eeprom_write_byte(pos, data);
  pos++;
}
и вариант с хранением в EEPROM

Код: Выделить всё

#define COUTN_POS 0x00F0
void eeprom_append_byte(char data){
  uint8_t *pos;
  eeprom_read_block(&pos, (void*)COUNT_POS, sizeof(uint8_t*)); //немного магии с преобразованием типов переменных
  eeprom_write_byte(pos,data);
  pos++;
  eeprom_write_block((void*)COUNT_POS, &pos, sizeof(uint8_t));
}
Оказывается все эти переменные есть в 3 квавре. спасибо!

Re: Запись во внутренюю EEPROM

Добавлено: Пн авг 15, 2016 00:21:22
Orion33
Удалено.