Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: EEPROM
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Дим
Товарищи, 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 по прерыванию? А то эти пустые циклы как-то не хорошо.
defunct
У вас ошибка в коде в части с 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
Дим
Я правильно понял у вас сначала записываются адрес, данные потом EEMWE = 1 и EEWE=1. Дальше ждем пока EEWE не станет равным 0. Далее очищаем EEMWE и т.д.
А может кто знает как можно обойтись без пустого цикла ожидания EEWE? Например сделать на прерывании?

Интересно то, что мой кусок программу записи в еепром в симуляторе AVR Studio 4 работает нормально, а вот на реальном железе нет! cranky.gif
prottoss
Цитата(Дим @ 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);

}
defunct
Цитата(Дим @ Mar 2 2006, 20:42) *
Я правильно понял у вас сначала записываются адрес, данные потом EEMWE = 1 и EEWE=1. Дальше ждем пока EEWE не станет равным 0. Далее очищаем EEMWE и т.д.
А может кто знает как можно обойтись без пустого цикла ожидания EEWE? Например сделать на прерывании?

Правильно поняли, только вначале идет CLI.
Можно сделать и по прерыванию, только тогда очередь надо будет организовывать.
Вас что смущает ожидание в пару мкс для завершения записи?

Цитата(prottoss @ Mar 2 2006, 20:49) *
Даташиты совсем не читаете, товарисч :-)

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


"Это что же, во все даташитах от АТМЕЛА на АВРки? Объяните, где ошибка в коде?
defunct
Цитата(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.


И тем не менее далее в своих примерах игнорируются собственные рекомендации, что приводит к неправильной работе описанных функций.
beer_warrior
Господа, а никто не делал библиотечки EEPROM полностью на прерываниях?
Я давно все периферию перевел на прерывания, а вот до EEPROM все руки не доходят даже концепцию продумать.
И сколько чужих исходников видел - все поллят.
prottoss
Цитата(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. Рекомендуется очищать глобальный флаг прерывания перед исполнением всех шагов во избежание проблем.

А если прерывния использует системный клок, как же нам тогда к ЕЕПРОМу то обращаться. Мы запретим прерывание, и клок собъется, мы на работу опазлаем...Однако... :-)))
defunct
Цитата(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 полностью на прерываниях?

Давайте сделаем, пригодится. Сейчас накидаю костяк, проверю.
Поможете подправить если что?
beer_warrior
Цитата
will make the write cycle fail, since the
EEPROM Master Write Enable will time-out

Вклинивание любого кода между 5 и 6 приведет к интересной ситуации - и код выполниться и EEPROM не запишется. Такая же ситуация с self programm.


Давайте сделаем, пригодится. Сейчас накидаю костяк, проверю.
Поможете подправить если что?

С удовольствием.
prottoss
Цитата(defunct @ Mar 3 2006, 03:57) *
Цитата

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

Вы вообще когда читаете даташит смысл оттуда понимаете? Вот смотрю, вроде переводите, да только ошибки допускаете, то ли случайно, то ли специально? Если прерывание произойдет между EEMWE = 1 и EEWE=1, то в EEPROM ничего не запишется!

Цитата
Или если обращения к ЕЕПРОМ ТОЛЬКО В ОДНОМ прерывании опять же нет смысла запрещать остальные прерывания. СМЫСЛ ЕСТЬ только в том случае, если несколько потоков могут читать/писать в/из ЕЕПРОМ. Так что НЕ ПУТАЙТЕ публику, код совершенно рабочий. В вышеприведенном англицком тексте об этом и написанно.

Смысл в том, чтобы функция учитывала обращение к EEPROM как из обработчика прерывания так и вне его, что собственно приведенная мной функция и делает.

Цитата
Вот Вам вольный перевод:
Предостережение: прерывание между шагом 5 и шагом 6 вызовет сбой цикла записи если програма прерывания будет изменять значения EEAR или EEDR.
....

Перевод у вас неправильный...
Первое предложение там такое:
"Прерывание между шагом 5 и шагом 6 приведет к сбою цикла записи, потому что EEPROM Master Write будет сброшен по тайм-ауту." ..
Ну и далее по тексту.


Каюсь, моя неправда. Не внимательно прочитал...

Но все равно, как то коряво получается... обламывать прерывания перед записью в ЕЕПРОМ... А нельзя ли биты EEMWE и EEWE записывать в EECR одновременно? Кто нибудь пробовал так делать?
defunct
Цитата(prottoss @ Mar 2 2006, 23:51) *
А нельзя ли биты EEMWE и EEWE записывать в EECR одновременно? Кто нибудь пробовал так делать?

Нельзя, даже смысла пробовать нет. Master Write это считайте предохранитель. Для того чтобы разрешить запись в EEPROM необходимо этот "предохранитель" снять, и если за следующие 4 такта не будет установлен флаг записи, тогда проц автоматически поставит "предохранитель" назад. Одновременная запись в WE и MWE рассматривается процом как возможный "глюк", вызванный сбоем, и соответственно игнорируется.
defunct
Вот что у меня получилось с прерываниями.. Выигрыш по скорости в сравнении с тупым ожиданием примерно в два раза. Стоит ли оно того? проверил на 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();
  }
}


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


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

Смотрел окончательный результат, получается то же, что если самому писать функцию чтения - записи в Епром.
vet
Цитата(defunct @ Mar 3 2006, 04:23) *
Вот что у меня получилось с прерываниями.. Выигрыш по скорости в сравнении с тупым ожиданием примерно в два раза.

Цифра "в 2 раза" к чему относится? время записи в EEPROM, полагаю, не изменилось.
defunct
Цитата(vet @ Mar 3 2006, 08:22) *
Цифра "в 2 раза" к чему относится? время записи в EEPROM, полагаю, не изменилось.

Цифра два относится к освобожденному времени простоя, которое обычно тратится на ожидания завершения записи. Напр., если с ожиданием тратилось ~100 тактов на запись байта EEPROM, то теперь ~50.. (все это относительно, ускорение будет зависеть от частоты чипа и от оптимизации).
ArtemK
По поводу буферизированной записи в EEPROM по прерыванию.
Чем не устроил код из Application Note "AVR104: Buffered Interrupt Controlled EEPROM Writes"???

Source Code
defunct
Цитата(ArtemK @ Mar 3 2006, 11:25) *
По поводу буферизированной записи в EEPROM по прерыванию.
Чем не устроил код из Application Note "AVR104: Buffered Interrupt Controlled EEPROM Writes"???

хотя бы тем, что он только под IAR и использует как минимум в три раза больше RAM чем приведенный выше код. interrupt latency в нем много выше. Да и по функциональности в appnote есть запись только одного байта, а в приведенном коде - запись любых структур.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.