реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> EEPROM, Оптимальная запись/чтение EEPROM
Дим
сообщение Mar 2 2006, 18:07
Сообщение #1





Группа: Новичок
Сообщений: 12
Регистрация: 20-10-05
Пользователь №: 9 894



Товарищи, help.gif! Такая проблемка: при записи в 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 по прерыванию? А то эти пустые циклы как-то не хорошо.
Go to the top of the page
 
+Quote Post
defunct
сообщение Mar 2 2006, 18:17
Сообщение #2


кекс
******

Группа: Свой
Сообщений: 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
Go to the top of the page
 
+Quote Post
Дим
сообщение Mar 2 2006, 18:42
Сообщение #3





Группа: Новичок
Сообщений: 12
Регистрация: 20-10-05
Пользователь №: 9 894



Я правильно понял у вас сначала записываются адрес, данные потом EEMWE = 1 и EEWE=1. Дальше ждем пока EEWE не станет равным 0. Далее очищаем EEMWE и т.д.
А может кто знает как можно обойтись без пустого цикла ожидания EEWE? Например сделать на прерывании?

Интересно то, что мой кусок программу записи в еепром в симуляторе AVR Studio 4 работает нормально, а вот на реальном железе нет! cranky.gif

Сообщение отредактировал Дим - Mar 2 2006, 18:49
Go to the top of the page
 
+Quote Post
prottoss
сообщение Mar 2 2006, 18:49
Сообщение #4


Гуру
******

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



Цитата(Дим @ Mar 3 2006, 01:07) *
Товарищи, help.gif ! Такая проблемка: при записи в 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


--------------------
Go to the top of the page
 
+Quote Post
defunct
сообщение Mar 2 2006, 19:45
Сообщение #5


кекс
******

Группа: Свой
Сообщений: 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
Go to the top of the page
 
+Quote Post
prottoss
сообщение Mar 2 2006, 20:01
Сообщение #6


Гуру
******

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



Цитата(defunct @ Mar 3 2006, 02:45) *
Похоже что он читал, только код в даташите во первых с ошибкой, а во вторых несколько своеобразен и не пригоден для корректной работы в обработчике прерывания и вне обработчика прерывания.


"Это что же, во все даташитах от АТМЕЛА на АВРки? Объяните, где ошибка в коде?


--------------------
Go to the top of the page
 
+Quote Post
defunct
сообщение Mar 2 2006, 20:17
Сообщение #7


кекс
******

Группа: Свой
Сообщений: 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.


И тем не менее далее в своих примерах игнорируются собственные рекомендации, что приводит к неправильной работе описанных функций.
Go to the top of the page
 
+Quote Post
beer_warrior
сообщение Mar 2 2006, 20:30
Сообщение #8


Профессионал
*****

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



Господа, а никто не делал библиотечки EEPROM полностью на прерываниях?
Я давно все периферию перевел на прерывания, а вот до EEPROM все руки не доходят даже концепцию продумать.
И сколько чужих исходников видел - все поллят.


--------------------
Вони шукають те, чого нема,
Щоб довести, що його не існує.
Go to the top of the page
 
+Quote Post
prottoss
сообщение Mar 2 2006, 20:35
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 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


--------------------
Go to the top of the page
 
+Quote Post
defunct
сообщение Mar 2 2006, 20:57
Сообщение #10


кекс
******

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



Цитата(prottoss @ Mar 2 2006, 22:35) *
А Вы хитрый. ОШИБКЕ ТО В КОДЕ НЕТ, а запрещать прерывания или нет, должен думать сам программист.

Ошибка есть, в том варианте кода который вы привели. И я совсем не хитрый smile.gif, просто если ссылаетесь на даташит, то не отрывайте код от контекста, иначе явные ошибки появляются.

Цитата
Если в прерываниях нет обращений к ЕЕПРОМ, то и запрещать прерывания нет смысла.

Вы вообще когда читаете даташит смысл оттуда понимаете? Вот смотрю, вроде переводите, да только ошибки допускаете, то ли случайно, то ли специально? Если прерывание произойдет между 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
Go to the top of the page
 
+Quote Post
beer_warrior
сообщение Mar 2 2006, 21:02
Сообщение #11


Профессионал
*****

Группа: Свой
Сообщений: 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


--------------------
Вони шукають те, чого нема,
Щоб довести, що його не існує.
Go to the top of the page
 
+Quote Post
prottoss
сообщение Mar 2 2006, 21:51
Сообщение #12


Гуру
******

Группа: Свой
Сообщений: 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 одновременно? Кто нибудь пробовал так делать?


--------------------
Go to the top of the page
 
+Quote Post
defunct
сообщение Mar 2 2006, 23:44
Сообщение #13


кекс
******

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



Цитата(prottoss @ Mar 2 2006, 23:51) *
А нельзя ли биты EEMWE и EEWE записывать в EECR одновременно? Кто нибудь пробовал так делать?

Нельзя, даже смысла пробовать нет. Master Write это считайте предохранитель. Для того чтобы разрешить запись в EEPROM необходимо этот "предохранитель" снять, и если за следующие 4 такта не будет установлен флаг записи, тогда проц автоматически поставит "предохранитель" назад. Одновременная запись в WE и MWE рассматривается процом как возможный "глюк", вызванный сбоем, и соответственно игнорируется.
Go to the top of the page
 
+Quote Post
defunct
сообщение Mar 3 2006, 01:23
Сообщение #14


кекс
******

Группа: Свой
Сообщений: 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
Go to the top of the page
 
+Quote Post
Георгий
сообщение Mar 3 2006, 05:32
Сообщение #15


Местный
***

Группа: Свой
Сообщений: 269
Регистрация: 17-11-05
Из: Киров-Москва
Пользователь №: 10 957



А если не заморачиваться и положиться на компилятор?
Я пока стал делать так :
Код
__eeprom char State0; // текущее состояние, хранимое в EEPROM


Код
//Считаем состояние из EEPROM и выведем
// в PORTB
  PORTB = State0;

Смотрел окончательный результат, получается то же, что если самому писать функцию чтения - записи в Епром.


--------------------
Обычно последним смеется тот, кто хуже соображает!
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 13th July 2025 - 14:44
Рейтинг@Mail.ru


Страница сгенерированна за 0.01517 секунд с 7
ELECTRONIX ©2004-2016