|
EEPROM, Оптимальная запись/чтение EEPROM |
|
|
|
Mar 2 2006, 18:07
|
Группа: Новичок
Сообщений: 12
Регистрация: 20-10-05
Пользователь №: 9 894

|
Товарищи,  ! Такая проблемка: при записи в EEPROM на ATMEGE 8515 записывается только первый байт, остальные остаются прежними. Код функции... ..... void RTEEPROMwrite(int location, unsigned char databyte) { unsigned char savedSREG; EEAR = location; // set address EEDR = databyte; // set data savedSREG = SREG; // keep setting so it can be restored while(EECR & (1<<EEWE)); CLI(); // disable interrupts EECR |= BIT(EEMWE);// set "write enable" bit EECR |= BIT(EEWE); // set "write" bit SREG = savedSREG; // restore SREG } В чем может быть проблема? И еще вопросик... Bit EERIE: EEPROM Ready Interrupt Enable - бит отвечающий за прерывание, как им пользоваться и как сделать чтение/запись EEPROM по прерыванию? А то эти пустые циклы как-то не хорошо.
|
|
|
|
|
Mar 2 2006, 18:17
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
У вас ошибка в коде в части с CLI().. вот рабочий вариант, сделайте по подобию: Код ; Write Byte To EEPROM ; --> Acc - byte to write, Z - Address of EEPROM cell ; <-- ничего не возвращает EEPROM_Write: in SREGM, SREG cli out EEARH, ZH out EEARL, ZL out EEDR, AL sbi EECR, EEMWE; EE Master Write Enable sbi EECR, EEWE ; Установить бит 1 в 1 (EE Write Enable) wait_w: ; Ждем до завершения записи sbic EECR, EEWE rjmp wait_w cbi EECR, EEMWE out SREG, SREGM ret
|
|
|
|
|
Mar 2 2006, 18:42
|
Группа: Новичок
Сообщений: 12
Регистрация: 20-10-05
Пользователь №: 9 894

|
Я правильно понял у вас сначала записываются адрес, данные потом EEMWE = 1 и EEWE=1. Дальше ждем пока EEWE не станет равным 0. Далее очищаем EEMWE и т.д. А может кто знает как можно обойтись без пустого цикла ожидания EEWE? Например сделать на прерывании? Интересно то, что мой кусок программу записи в еепром в симуляторе AVR Studio 4 работает нормально, а вот на реальном железе нет!
Сообщение отредактировал Дим - Mar 2 2006, 18:49
|
|
|
|
|
Mar 2 2006, 18:49
|

Гуру
     
Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659

|
Цитата(Дим @ Mar 3 2006, 01:07)  Товарищи,  ! Такая проблемка: при записи в EEPROM на ATMEGE 8515 записывается только первый байт, остальные остаются прежними. Даташиты совсем не читаете, товарисч :-) Во всех даташитах (complete) есть раздел AVR (uC type) memories->EEPROM Data Memory, где даются КОНКРЕТНЫЕ РАБОЧИЕ ПРИМЕРЫ для Си и Асм. Вот, к примеру выдержка из даташита на мега32: Код Assembly Code Example
EEPROM_write:
; Wait for completion of previous write sbic EECR,EEWE rjmp EEPROM_write
; Set up address (r18:r17) in address register out EEARH, r18 out EEARL, r17
; Write data (r16) to data register out EEDR,r16
; Write logical one to EEMWE sbi EECR,EEMWE
; Start eeprom write by setting EEWE sbi EECR,EEWE ret
C Code Example
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);
}
Сообщение отредактировал prottoss - Mar 2 2006, 18:55
--------------------
|
|
|
|
|
Mar 2 2006, 19:45
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(Дим @ Mar 2 2006, 20:42)  Я правильно понял у вас сначала записываются адрес, данные потом EEMWE = 1 и EEWE=1. Дальше ждем пока EEWE не станет равным 0. Далее очищаем EEMWE и т.д. А может кто знает как можно обойтись без пустого цикла ожидания EEWE? Например сделать на прерывании? Правильно поняли, только вначале идет CLI. Можно сделать и по прерыванию, только тогда очередь надо будет организовывать. Вас что смущает ожидание в пару мкс для завершения записи? Цитата(prottoss @ Mar 2 2006, 20:49)  Даташиты совсем не читаете, товарисч :-) Похоже что он читал, только код в даташите во первых с ошибкой, а во вторых несколько своеобразен и не пригоден для корректной работы в обработчике прерывания и вне обработчика прерывания.
Сообщение отредактировал defunct - Mar 2 2006, 19:48
|
|
|
|
|
Mar 2 2006, 20:17
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(prottoss @ Mar 2 2006, 22:01)  "Это что же, во все даташитах от АТМЕЛА на АВРки? Объяните, где ошибка в коде? Да практически во всех... Ошибка в том, что в приведенных функциях не запрещаются прерывания. Из даташита алгоритм записи EEPROM: Цитата 1. Wait until EEWE becomes zero. 2. Wait until SPMEN in SPMCR becomes zero. 3. Write new EEPROM address to EEAR (optional). 4. Write new EEPROM data to EEDR (optional). 5. Write a logical one to the EEMWE bit while writing a zero to EEWE in EECR. 6. Within four clock cycles after setting EEMWE, write a logical one to EEWE.
Caution: An interrupt between step 5 and step 6 will make the write cycle fail, since the EEPROM Master Write Enable will time-out. If an interrupt routine accessing the EEPROM is interrupting another EEPROM Access, the EEAR or EEDR reGister will be modified, causing the interrupted EEPROM Access to fail. It is recommended to have the Global Interrupt Flag cleared during all the steps to avoid these problems. И тем не менее далее в своих примерах игнорируются собственные рекомендации, что приводит к неправильной работе описанных функций.
|
|
|
|
|
Mar 2 2006, 20:35
|

Гуру
     
Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659

|
Цитата(defunct @ Mar 3 2006, 03:17)  Цитата(prottoss @ Mar 2 2006, 22:01)  "Это что же, во все даташитах от АТМЕЛА на АВРки? Объяните, где ошибка в коде?
Да практически во всех... Ошибка в том, что в приведенных функциях не запрещаются прерывания. Из даташита алгоритм записи EEPROM: Цитата 1. Wait until EEWE becomes zero. 2. Wait until SPMEN in SPMCR becomes zero. 3. Write new EEPROM address to EEAR (optional). 4. Write new EEPROM data to EEDR (optional). 5. Write a logical one to the EEMWE bit while writing a zero to EEWE in EECR. 6. Within four clock cycles after setting EEMWE, write a logical one to EEWE.
Caution: An interrupt between step 5 and step 6 will make the write cycle fail, since the EEPROM Master Write Enable will time-out. If an interrupt routine accessing the EEPROM is interrupting another EEPROM Access, the EEAR or EEDR reGister will be modified, causing the interrupted EEPROM Access to fail. It is recommended to have the Global Interrupt Flag cleared during all the steps to avoid these problems. И тем не менее далее в своих примерах игнорируются собственные рекомендации, что приводит к неправильной работе описанных функций. А Вы хитрый. ОШИБКЕ ТО В КОДЕ НЕТ, а запрещать прерывания или нет, должен думать сам программист. Если в прерываниях нет обращений к ЕЕПРОМ, то и запрещать прерывания нет смысла. Или если обращения к ЕЕПРОМ ТОЛЬКО В ОДНОМ прерывании опять же нет смысла запрещать остальные прерывания. СМЫСЛ ЕСТЬ только в том случае, если несколько потоков могут читать/писать в/из ЕЕПРОМ. Так что НЕ ПУТАЙТЕ публику, код совершенно рабочий. В вышеприведенном англицком тексте об этом и написанно. Вот Вам вольный перевод: Предостережение: прерывание между шагом 5 и шагом 6 вызовет сбой цикла записи если програма прерывания будет изменять значения EEAR или EEDR. Рекомендуется очищать глобальный флаг прерывания перед исполнением всех шагов во избежание проблем. А если прерывния использует системный клок, как же нам тогда к ЕЕПРОМу то обращаться. Мы запретим прерывание, и клок собъется, мы на работу опазлаем...Однако... :-)))
Сообщение отредактировал prottoss - Mar 2 2006, 20:38
--------------------
|
|
|
|
|
Mar 2 2006, 20:57
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(prottoss @ Mar 2 2006, 22:35)  А Вы хитрый. ОШИБКЕ ТО В КОДЕ НЕТ, а запрещать прерывания или нет, должен думать сам программист. Ошибка есть, в том варианте кода который вы привели. И я совсем не хитрый  , просто если ссылаетесь на даташит, то не отрывайте код от контекста, иначе явные ошибки появляются. Цитата Если в прерываниях нет обращений к ЕЕПРОМ, то и запрещать прерывания нет смысла. Вы вообще когда читаете даташит смысл оттуда понимаете? Вот смотрю, вроде переводите, да только ошибки допускаете, то ли случайно, то ли специально? Если прерывание произойдет между EEMWE = 1 и EEWE=1, то в EEPROM ничего не запишется! Цитата Или если обращения к ЕЕПРОМ ТОЛЬКО В ОДНОМ прерывании опять же нет смысла запрещать остальные прерывания. СМЫСЛ ЕСТЬ только в том случае, если несколько потоков могут читать/писать в/из ЕЕПРОМ. Так что НЕ ПУТАЙТЕ публику, код совершенно рабочий. В вышеприведенном англицком тексте об этом и написанно. Смысл в том, чтобы функция учитывала обращение к EEPROM как из обработчика прерывания так и вне его, что собственно приведенная мной функция и делает. Цитата Вот Вам вольный перевод: Предостережение: прерывание между шагом 5 и шагом 6 вызовет сбой цикла записи если програма прерывания будет изменять значения EEAR или EEDR. .... Перевод у вас неправильный... Первое предложение там такое: "Прерывание между шагом 5 и шагом 6 приведет к сбою цикла записи, потому что EEPROM Master Write будет сброшен по тайм-ауту." .. Ну и далее по тексту. Цитата А если прерывния использует системный клок, как же нам тогда к ЕЕПРОМу то обращаться. Мы запретим прерывание, и клок собъется, мы на работу опазлаем...Однако... :-))) Тогда выход - запись EEPROM вести по прерыванию.. Цитата(beer_warrior @ Mar 2 2006, 22:30)  Господа, а никто не делал библиотечки EEPROM полностью на прерываниях? Давайте сделаем, пригодится. Сейчас накидаю костяк, проверю. Поможете подправить если что?
Сообщение отредактировал defunct - Mar 2 2006, 20:59
|
|
|
|
|
Mar 2 2006, 21:02
|

Профессионал
    
Группа: Свой
Сообщений: 1 065
Регистрация: 8-10-05
Из: Kiev, UA
Пользователь №: 9 380

|
Цитата will make the write cycle fail, since the EEPROM Master Write Enable will time-out Вклинивание любого кода между 5 и 6 приведет к интересной ситуации - и код выполниться и EEPROM не запишется. Такая же ситуация с self programm. Давайте сделаем, пригодится. Сейчас накидаю костяк, проверю. Поможете подправить если что? С удовольствием.
Сообщение отредактировал beer_warrior - Mar 2 2006, 21:06
--------------------
Вони шукають те, чого нема, Щоб довести, що його не існує.
|
|
|
|
|
Mar 2 2006, 21:51
|

Гуру
     
Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659

|
Цитата(defunct @ Mar 3 2006, 03:57)  Цитата Если в прерываниях нет обращений к ЕЕПРОМ, то и запрещать прерывания нет смысла.
Вы вообще когда читаете даташит смысл оттуда понимаете? Вот смотрю, вроде переводите, да только ошибки допускаете, то ли случайно, то ли специально? Если прерывание произойдет между EEMWE = 1 и EEWE=1, то в EEPROM ничего не запишется! Цитата Или если обращения к ЕЕПРОМ ТОЛЬКО В ОДНОМ прерывании опять же нет смысла запрещать остальные прерывания. СМЫСЛ ЕСТЬ только в том случае, если несколько потоков могут читать/писать в/из ЕЕПРОМ. Так что НЕ ПУТАЙТЕ публику, код совершенно рабочий. В вышеприведенном англицком тексте об этом и написанно. Смысл в том, чтобы функция учитывала обращение к EEPROM как из обработчика прерывания так и вне его, что собственно приведенная мной функция и делает. Цитата Вот Вам вольный перевод: Предостережение: прерывание между шагом 5 и шагом 6 вызовет сбой цикла записи если програма прерывания будет изменять значения EEAR или EEDR. .... Перевод у вас неправильный... Первое предложение там такое: "Прерывание между шагом 5 и шагом 6 приведет к сбою цикла записи, потому что EEPROM Master Write будет сброшен по тайм-ауту." .. Ну и далее по тексту. Каюсь, моя неправда. Не внимательно прочитал... Но все равно, как то коряво получается... обламывать прерывания перед записью в ЕЕПРОМ... А нельзя ли биты EEMWE и EEWE записывать в EECR одновременно? Кто нибудь пробовал так делать?
--------------------
|
|
|
|
|
Mar 3 2006, 01:23
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Вот что у меня получилось с прерываниями.. Выигрыш по скорости в сравнении с тупым ожиданием примерно в два раза. Стоит ли оно того? проверил на IAR'е и gcc, вроде работает, только кода много получается - без оптимизации около 500 байт для чипов с EEPROM > 256 байт, и около 400 для чипов с EEPROM <= 256 байт. Код /* файл ee_mgr.c */ // Использование динамической памяти отбросил (не актуально для мелкоконтроллеров с менее 8k RAM)
#include <avr\io.h> #include "ee_mgr.h"
#ifndef _ee_mgr_header_present // объявление возможных ошибок #define ERROR_MSG_TOO_LONG 0 #define ERROR_BUSY -1 #define ERROR_NOT_ENOUGH_FREE_SPACE -2 // объявление констант #define EE_BUFFER_LENGTH 16 #endif
#define FALSE 0 #define TRUE 1 #define CARDINAL unsigned char #define cli asm("cli") #define EE_ReadyForAction (EECR & (1 << EEWE))
// реализована пока только функции записи в EEPROM, // чтение по прерыванию сделать нельзя да и было бы медленнее! char EE_Buf[EE_BUFFER_LENGTH]; // общий буфер для чтения и запис CARDINAL EE_CurrentPos = 0; CARDINAL EE_Count = 0; WORD EE_StartAddress; char EE_Busy = FALSE;
int EEPROMWriteMsg(WORD address, void *msg, int count) { char *amsg; CARDINAL i; if (count > EE_BUFFER_LENGTH) return ERROR_MSG_TOO_LONG; if (EE_Busy) return ERROR_BUSY; if ((address + count) > E2END) return ERROR_NOT_ENOUGH_FREE_SPACE;
amsg = msg; EE_CurrentPos = 0; for(i=0; i < count; i++) EE_Buf[i] = amsg[i];
EE_Busy = TRUE; EE_Count = count; EE_StartAddress = address; return count; }
// апаратно зависимая функция инициализации записи EEPROM void InitializeEEPROMWriteByte(WORD address, char data) { char sreg_mirror; sreg_mirror = SREG; cli; EEAR = address; EEDR = data; EECR |= (1 << EEMWE); EECR |= (1 << EEWE)|(1 << EERIE); SREG = sreg_mirror; }
// функция для вызова в основном цикле программы void EEPROMDispatch(void) { char data_byte; WORD address; if ((!EE_Busy)|(!EE_ReadyForAction)) return; // Запись очередного байта if (EE_Count == EE_CurrentPos) // сообщение полностью записано { EE_Busy = FALSE; return; }
data_byte = EE_Buf[EE_CurrentPos]; address = EE_StartAddress + EE_CurrentPos; InitializeEEPROMWriteByte(address, data_byte); EE_CurrentPos++; } это header (учитывается размер EEPROM'а, для маленьких чипов) Код /* файл ee_mgr.h */ #define _ee_mgr_header_present // объем буфера под EEPROM очередь #define EE_BUFFER_LENGTH 32
#ifdef E2END #if (E2END < 0x100) #define WORD unsigned char #else #define WORD short #endif #else #define WORD int #endif
#ifndef EERIE #define EERIE 3 #endif
// коды возможных ошибок при обращении к функции записи #define ERROR_BUSY -1 #define ERROR_NOT_ENOUGH_FREE_SPACE -2 #define ERROR_MSG_TOO_LONG 0
// Макрос, который необходимо вызывать в обработчике прерывания EEPROM_Ready #define EEPROMReadyHandler EECR &= ~(1 << EERIE)
void EEPROMDispatch(void); // функция для вызова в основном цикле программы
int EEPROMWriteMsg(WORD address, void *msg, int count); // запись любых структур Пример применения (gcc): Код SIGNAL (SIG_EE_READY) { EEPROMReadyHandler; }
int main( void ) { char str[] = "zzz"; EEPROMWriteMsg(0x20, str, sizeof(str)); asm("sei"); for(;;) { EEPROMDispatch(); } } Принимается любая критика!
Сообщение отредактировал defunct - Mar 3 2006, 02:18
|
|
|
|
|
Mar 3 2006, 05:32
|
Местный
  
Группа: Свой
Сообщений: 269
Регистрация: 17-11-05
Из: Киров-Москва
Пользователь №: 10 957

|
А если не заморачиваться и положиться на компилятор? Я пока стал делать так : Код __eeprom char State0; // текущее состояние, хранимое в EEPROM Код //Считаем состояние из EEPROM и выведем // в PORTB PORTB = State0; Смотрел окончательный результат, получается то же, что если самому писать функцию чтения - записи в Епром.
--------------------
Обычно последним смеется тот, кто хуже соображает!
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|