Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Запись,чтение EEPROM
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
glebka
Делаю проект на MEGA 168, использюю ICC. Пишу 4 слова в EEPROM, читаю только последнее записанное.Пример взял из даташита.В чем может быть проблема.
IgorKossak
После записи каждого байта неплохо бы дождаться окончания этой процедуры (около 8 мс).
KRS
Цитата(glebka @ Jul 4 2006, 13:27) *
Делаю проект на MEGA 168, использюю ICC. Пишу 4 слова в EEPROM, читаю только последнее записанное.Пример взял из даташита.В чем может быть проблема.

Без исходников сказать ничего нельзя!
Здесь уже неоднократно поднималась тема EEPROM
например http://electronix.ru/forum/index.php?showtopic=16140 (правда для IAR)
но там есть исходники их можно адаптировтаь
glebka
Код такой

void EEPromWrite( unsigned int Addr, unsigned char Val )
{
macroGlobalIntDisable;
EEAR=Addr;
EEDR=Val;

//Write logical one to EEMPE
EECR|=(1<<EEMPE);

//Start eeprom write by setting EEPE
EECR|=(1<EEPE);

while(EECR&(1<<EEPE)){};
DelayMilliSec( 10 );
macroGlobalIntEnable;
macroToggleWatchdog;

return;
}


unsigned char EEPromRead( unsigned int Addr )
{
macroGlobalIntDisable;



//Setup nadress register
//EEAR=Addr;
EEARH=0x00;
EEARL=Addr;

//start eepromread by writing EERE
EECR|+(1<<EERE);

//Return data from Data register
//Wait for complection of previous read
while(EECR&(1<<EEPE)){};
macroGlobalIntEnable;
return EEDR;
}
IgorKossak
DelayMilliSec( 10 );
Совершенно лишняя процедура, я имел в виду совсем другое.
А именно
Код
while(EECR&(1<<EEPE)){};
KRS
При чтении не надо ждать окончания записи, тем более после установки бита EERE и запрещать прерывания не обязательно (если конечно в прерываниях вы не обращаетесь к EEPROM)

и что значит
EECR|+(1<<EERE);

может быть?
EECR|=(1<<EERE);

А еще при записи, прерывания луше разрешить до ожидания окончания записи и ждать при включенных прерываниях
IgorKossak
Похоже в Этом
Код
EEAR=Addr;
может быть ошибка.
EEAR обрабатывается как 16-битный регистр?
И вообще, проинспектируйте полученный после компиляции ассемблерный листинг (если это возможно в данной среде).
beer_warrior
А не может ли быть следующего:
1.Читаете по указателю с последнего места записи - те указатель не возвращается к началу?
2.Пишете все по одному адресу - указатель не сдвигался?
glebka
Цитата(beer_warrior @ Jul 4 2006, 14:17) *
А не может ли быть следующего:
1.Читаете по указателю с последнего места записи - те указатель не возвращается к началу?
2.Пишете все по одному адресу - указатель не сдвигался?


Прописал в макро номера страниц и при записе, и при чтении просто читаю макро и использую

EEPromWrite( EEPROM_SERID_BYTE0_ADDR,gSerialID[0]);


Вопрос к IgorKossak если можно по поддробней про обработку адресса,как это сделать правильно.
IgorKossak
Цитата(glebka @ Jul 4 2006, 13:33) *
...Вопрос к IgorKossak если можно по поддробней про обработку адресса,как это сделать правильно.

Имелось в виду следующее: поскольку доступ к 16-битным регистрам 8-битным ядром осуществляется за две команды, то имеет значение очерёдность такого доступа, а именно:
- читать надо сначала младший, потом старший;
- писать надо сначала старший, потом младший;
- обращение должно быть ТОЛЬКО парным, т. е. не должно быть обращения к одной из двух половин без обращения ко второй.
Подробнее в описании в главе "Accessing 16-bit Registers".
KRS
Цитата(IgorKossak @ Jul 5 2006, 11:12) *
Цитата(glebka @ Jul 4 2006, 13:33) *

...Вопрос к IgorKossak если можно по поддробней про обработку адресса,как это сделать правильно.

Имелось в виду следующее: поскольку доступ к 16-битным регистрам 8-битным ядром осуществляется за две команды, то имеет значение очерёдность такого доступа, а именно:
- читать надо сначала младший, потом старший;
- писать надо сначала старший, потом младший;
- обращение должно быть ТОЛЬКО парным, т. е. не должно быть обращения к одной из двух половин без обращения ко второй.
Подробнее в описании в главе "Accessing 16-bit Registers".

Это относится только к регистрам которые могут железом поменяться (таймеры) для адреса eeprom это не действует можно в любом порядке читать и писать!
glebka
Уррра.заработалою.

Код

unsigned char EEPromRead( unsigned int Addr )
{

//Setup adress register
EEAR=(Addr&0xFF);


//start EEPOM read by writing EERE
SetBit(EECR,0);

//Return data from Data register
return EEDR;
}

void EEPromWrite( unsigned int Addr, unsigned char Val )
{
macroGlobalIntDisable;
EEAR = Addr; // Load address
EEDR = Val; // Load data to be written



//Set logical one to EEMPE
SetBit(EECR,2);

//Set logical one to EEPE
SetBit(EECR,1);

macroToggleWatchdog;
while(EECR&(1<<EEPE)){};

macroGlobalIntEnable;

return;
}
IgorKossak
Совет по оптимизации:
Код

unsigned char EEPromRead( unsigned int Addr )
{
unsigned char data;

macroGlobalIntDisable; // на тот случай если в каком-нибудь прерывании между
// следующими двумя строками кода поменяется
// содержимое EEAR
//Setup adress register
EEAR=(Addr&0xFF);


//start EEPOM read by writing EERE
SetBit(EECR,0);
data = EEDR;
macroGlobalIntEnable;
//Return data from Data register
return data;
}

void EEPromWrite( unsigned int Addr, unsigned char Val )
{
macroToggleWatchdog;
while(EECR&(1<<EEPE)){}; // Это лучше делать здесь, а не в конце,
// т. к. не всегда пишутся два байта подряд
macroGlobalIntDisable;

// а ещё лучше записать так:
// for (;;)
// {
// macroGlobalIntDisable;
// if (EECR&(1<<EEPE))
// macroGlobalIntEnable;
// else
// break;
// }
// в этом случае нахождение системы в состоянии
// с запрещёнными прерываниями будет минимальным
// Этот цикл желательно также вставить в начало
// функции EEPromRead вместо macroGlobalIntDisable

EEAR = Addr; // Load address
EEDR = Val; // Load data to be written



//Set logical one to EEMPE
SetBit(EECR,2);

//Set logical one to EEPE
SetBit(EECR,1);

macroGlobalIntEnable;

return;
}
IgorKossak
Цитата(KRS @ Jul 5 2006, 11:40) *
Цитата(IgorKossak @ Jul 5 2006, 11:12) *

Цитата(glebka @ Jul 4 2006, 13:33) *

...Вопрос к IgorKossak если можно по поддробней про обработку адресса,как это сделать правильно.

Имелось в виду следующее: поскольку доступ к 16-битным регистрам 8-битным ядром осуществляется за две команды, то имеет значение очерёдность такого доступа, а именно:
- читать надо сначала младший, потом старший;
- писать надо сначала старший, потом младший;
- обращение должно быть ТОЛЬКО парным, т. е. не должно быть обращения к одной из двух половин без обращения ко второй.
Подробнее в описании в главе "Accessing 16-bit Registers".

Это относится только к регистрам которые могут железом поменяться (таймеры) для адреса eeprom это не действует можно в любом порядке читать и писать!

Согласен, здесь это не актуально, но чтобы не плодить правила и когда-нибудь не ошибиться в связи с этим, я бы следовал этому правилу всегда. Тем более, что это не накладно.
Crystaly
Цитата(glebka @ Jul 5 2006, 13:03) *
Уррра.заработалою.

Код

unsigned char EEPromRead( unsigned int Addr )
{

//Setup adress register
EEAR=(Addr&0xFF);


//start EEPOM read by writing EERE
SetBit(EECR,0);

//Return data from Data register
return EEDR;
}

void EEPromWrite( unsigned int Addr, unsigned char Val )
{
macroGlobalIntDisable;
EEAR = Addr; // Load address
EEDR = Val; // Load data to be written



//Set logical one to EEMPE
SetBit(EECR,2);

//Set logical one to EEPE
SetBit(EECR,1);

macroToggleWatchdog;
while(EECR&(1<<EEPE)){};

macroGlobalIntEnable;

return;
}

Я пишу на ассемблере, но дело не в этом. Я когда-то тоже писал в EEPROM несколько байт подряд, ждал предыдущей записи. Когда байтов было 2 - все ОК. Но когда стало 4 - не работало. Я долго парился пока не обнаружил, что просто повторно срабатывает прерывание (запись шла внутри прерывания) - слишком долго это все.
Короче я сделал такую вещь - небольшая структура типа буфера, похожая на стек (но не совсем стек, скорее куча), состоит из тела, указателя, размера.
Тело - содержит пакеты из трех байт, два байта адрес и один байт данные, размер тела = 3*N байт, где N-размер тела в пакетах;
Указатель - 2 байта, содержат адрес вершины кучи;
Размер - 1 байт, содержит количество положенных пакетов в кучу. Если =0 - куча пустая.
Подпрограммы такие: ПОЛОЖИТЬ_В_КУЧУ и ОБСЛУЖИТЬ_КУЧУ. В начале программы кучу инициализировать - указатель на начало тела, размер=0.
ПОЛОЖИТЬ_В_КУЧУ вызывается в любом месте программы, где надо записать в EEPROM очередное число. Берет адрес, данные, ложит в кучу по указателю, передвигает указатель на 3, увеличивает размер на 1. На время работы с кучей запретить прерывания.
ОБСЛУЖИТЬ_КУЧУ вызывается сравнительно редко по прерыванию, проверяет размер кучи если =0 ничего не делает, иначе проверяет завершилась ли предыдущая запись в EEPROM, если нет - ничего не делает, если да - берет из кучи по указателю данные, адрес, направляет в регистры EEPROM, запускает запись, передвигает указатель на 3 обратно, уменьшает размер на 1. Все.
Вот такая штука значительно облегчила мне жизнь smile.gif
XsanyaX
Извиняюсь за оффтопик,но зачем такие сложности.... В ICC есть готовые функции (вернее макросы) EEPROM_READ() и EEPROM_WRITE() объявленные в eeprom.h, они сами занимаются опросом готовности EEPROM. В хелпе по ICC всё расписано.
Вот пример из этого же хелпа:
#pragma data:eeprom
int foo = 0x1234;
char table[] = { 0, 1, 2, 3, 4, 5 };
#pragma data:data
...
int i;
EEPROM_READ((int)&foo, i); // i now has 0x1234
Crystaly
Дело не просто в опросе готовности. Дело в том, что не надо ждать вхолостую готовность. Вы в программе фактически просто отправляете данные в EEPROM без ожидания готовности со скоростью программы хоть тридцать байт друг за дружкой без всяких ожиданий. А они уже "сами без вашего участия" своим чередом со скоростью EEPROM улетят. Если не устраивает куча (нельзя вдруг нарушать последовательность записи) - можно добавить еще один указатель и сделать полноценный буфер-очередь.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.