Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Вопрос по работе с EEPROM в WinAVR
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
AlexPT
Здравствуйте! Прошу помочь. Нужны функции записи и чтения из/в EEPROM AT90CAN128. Беру примеры из Даташита и компилирую WinAVR, не работают. Преверяю в AVRStudio - не работают. Вот эти функции из Даташита:

/*********************************
*
* ЗАПИСЬ БАЙТА В int-EEPROM
*
*********************************/
void RTEEPROMwrite (u16 adrEEPROM, u08 databyte)
{
u08 savedSREG;

while(EECR & (1<<EEWE));
savedSREG = SREG // keep setting so it can be restored
SREG &= ~0x80;
EEAR = adrEEPROM; // set address
EEDR = databyte; // set data
EECR |= (1<<EEMWE); // set "write enable" bit
EECR |= (1<<EEWE); // set "write" bit
SREG = savedSREG; // restore SREG
EEAR = 0;

} // end of RTEEPROMwrite

/**********************************
*
* ЧТЕНИЕ БАЙТА ИЗ int-EEPROM
*
**********************************/
u08 RTEEPROMread (u16 adrEEPROM)
{
while(EECR & (1<<EEWE));
EEAR = adrEEPROM; // set address
EECR |= (1<<EERE); // set "read enable" bit
EEAR = 0;
return (EEDR);

} // end of RTEEPROMread

Хотел использовать функции из библиотеки:

uint8_t eeprom_read_byte (const uint8_t *addr);

void eeprom_write_byte (uint8_t *addr,uint8_t value);

Но не понятно как описать и работать с указателями на ячейки в EEPROM.
Tcom
unsigned char EEPROM_read (unsigned int uiAdress)// Чтение eeprom
{
while (EECR & (1<<EEWE));
EEAR = uiAdress;
EECR |= (1<<EERE);
return EEDR;}
void EEPROM_write(unsigned int uiAdress , unsigned char ucData) // Запись eeprom
{
while(EECR & (1<<EEWE));
EEAR = uiAdress ;
EEDR = ucData;
EECR |= (1<<EEMWE);
EECR |= (1<<EEWE);
}

Вот рабочий пример с моей проги под WinAVR омпилятор.
IgorKossak
Цитата(AlexPT @ May 25 2007, 10:09) *
Хотел использовать функции из библиотеки:
uint8_t eeprom_read_byte (const uint8_t *addr);
void eeprom_write_byte (uint8_t *addr,uint8_t value);
Но не понятно как описать и работать с указателями на ячейки в EEPROM.

Очевидно, приведением типа u16 к типу const uint8_t *.
singlskv
Вот это лишнее:
Цитата(AlexPT @ May 25 2007, 11:09) *
EEAR = 0;
aesok
Цитата(AlexPT @ May 25 2007, 11:09) *
Здравствуйте! Прошу помочь. Нужны функции записи и чтения из/в EEPROM AT90CAN128. Беру примеры из Даташита и компилирую WinAVR, не работают. Преверяю в AVRStudio - не работают. Вот эти функции из Даташита:


С каким уровнем оптимизации компилируете? Состояния фюза M103C?

Анатолий.

Цитата(Tcom @ May 25 2007, 11:32) *
unsigned char EEPROM_read (unsigned int uiAdress)// Чтение eeprom
{
while (EECR & (1<<EEWE));
EEAR = uiAdress;
EECR |= (1<<EERE);
return EEDR;}
void EEPROM_write(unsigned int uiAdress , unsigned char ucData) // Запись eeprom
{
while(EECR & (1<<EEWE));
EEAR = uiAdress ;
EEDR = ucData;
EECR |= (1<<EEMWE);
EECR |= (1<<EEWE);
}

Вот рабочий пример с моей проги под WinAVR омпилятор.


А что будет если между строками
EECR |= (1<<EEMWE);
EECR |= (1<<EEWE);

произойдет прерывание?

Анатолий.
AlexPT
С EEAR = 0 это опечатка. Компилирую с уровнем оптимизации 0. Что такое фюз М103С я не знаю (я только недавно начал работать с WinAVR, так что прошу отнестисть с пониманием), но такого слова в makefile нет.
Хотелось бы по подробнее узнать по приведению типа u16 к типу const uint8_t*. Если можно поясните на примере.
Приведенный пример попробывал, не работает да он практически не отличается Даташитовского. Может необходима какая-то запись в makefile или .h файлы.
aesok
Цитата(AlexPT @ May 25 2007, 13:56) *
С EEAR = 0 это опечатка. Компилирую с уровнем оптимизации 0. Что такое фюз М103С я не знаю


Про М103С извините ошибся, подумал что речь идет о ATmega128.

Посмотрите код который генериться для строк:
EECR |= (1<<EEMWE);
EECR |= (1<<EEWE);

Не уровне оптимизации -O0:
Код
  EECR |= (1<<EEMWE);
  92:    80 91 3c 00     lds    r24, 0x003C
  96:    84 60           ori    r24, 0x04; 4
  98:    80 93 3c 00     sts    0x003C, r24
  EECR |= (1<<EEWE);
  9c:    80 91 3c 00     lds    r24, 0x003C
  a0:    82 60           ori    r24, 0x02; 2
  a2:    80 93 3c 00     sts    0x003C, r24


И на -O1:
Код
  EECR |= (1<<EEMWE);
  8e:    e2 9a           sbi    0x1c, 2; 28
  EECR |= (1<<EEWE);
  90:    e1 9a           sbi    0x1c, 1; 28


В первом случае не соблюдается условие установки бита EEWE не позже 4 циклов после установки EEMWE.

Не используйте уровень оптимизации -O0, он нужен в очень редких случаях для отладки.
Используйте библиотечные функции, как с ними работать описано в avr-libc-user-manual в директори WinAVR/doc/avr-libc.

Анатолий.
AlexPT
Большое спасибо за подсказку с оптимизацией. Все заработало.
defunct
В WinAVR есть готовые функции для работы с eeprom.
смотрите eeprom.h.
Предпочтительнее использовать их, т.к. они работают вне зависимости от уровня оптимизации.

#include <avr/eeprom.h>

eeprom_write_byte
eeprom_read_byte
и т.п.
Mikron
добрый вечер
решил поднять тему, просто проблема с Atmega128 в WinAVR как и у автора почти
Код
unsigned char EEPROM_read(unsigned int uiAdress)// Чтение
{
    while (EECR & (1<<EEWE));
    EEAR = 0x10;
    EECR |= (1<<EERE);
    return EEDR;
}

void EEPROM_write(unsigned int uiAdress , unsigned char ucData) // Запись
{
    char cSREG;
    while(EECR & (1<<EEWE));
    EEAR = uiAdress;
    EEDR = ucData;

    cSREG = SREG;
    cli();
    EECR |= (1<<EEMWE);
    EECR |= (1<<EEWE);
    SREG = cSREG;
}

функция записи почему то не работает, так как читаю постоянно 0xff
оптимизация -O1
подскажите пожалуйста в чем дело
alexeyv
используйте библиотечные функции.
Например, для записи
Код
  
  eeprom_write_word ((void*)0x10, power_s );
  eeprom_write_word ((void*)0x12, syplsec );
  eeprom_write_word ((void*)0x14, worksec );


Например, для чтения (в цикле)
Код
  
#define EEPROM_BASE  0x10
  for(byte i=0; i<PARAM_COUNT; i++)
    sav_param.masu[i] = eeprom_read_word((void *)(EEPROM_BASE + i*sizeof(word)));

Mikron
alexeyv, спасибо, но в даташите я не нашел
нужно ли как-то еще настраивать контроллер на запись/чтение
или достаточно использовать только библиотечные функции?
ARV
Цитата(Mikron @ Sep 30 2010, 08:58) *
alexeyv, спасибо, но в даташите я не нашел
нужно ли как-то еще настраивать контроллер на запись/чтение
или достаточно использовать только библиотечные функции?
достаточно библиотечных, только не забывайте о том, что запись длится относительно долго
777777
Цитата(aesok @ May 25 2007, 14:12) *
Посмотрите код который генериться для строк:
EECR |= (1<<EEMWE);
EECR |= (1<<EEWE);

Не уровне оптимизации -O0:


-O0 это полное отсутствие оптимизации, компилировать программу без нее глупо. Обычно это импользуется тогда, когда вы подозреваете оптимизатор в глючности, тогда отключив оптимизацию можно убедиться, что проблема в самой программе.

Обычно для боевой программы используется уровень -Os

Цитата(AlexPT @ May 25 2007, 11:09) *
savedSREG = SREG // keep setting so it can be restored
SREG &= ~0x80;

А к чему такие сложности? Не проще ли написать cli(), sei()
aesok
Цитата(777777 @ Sep 30 2010, 10:40) *
-O0 это полное отсутствие оптимизации, ....
Обычно для боевой программы используется уровень -Os


Спасибо большое, я об этом уже 3 года как не знаю, побегу сейчас на рабору перекомпилирую проект, может заработаент!!!

Цитата(777777 @ Sep 30 2010, 10:40) *
А к чему такие сложности? Не проще ли написать cli(), sei()


Такие сложности нужны для того, чтобы функция EEPROM_write делала только то что от нее требуется - записывала байт в EEPROM, и не делела то чего не должна, тоесть чтобы она не разрешала прерывания.

Анатолий.
777777
Цитата(aesok @ Sep 30 2010, 10:50) *
Такие сложности нужны для того, чтобы функция EEPROM_write делала только то что от нее требуется - записывала байт в EEPROM, и не делела то чего не должна, тоесть чтобы она не разрешала прерывания.

Так вот для этого и используются псевдофункции cli() и sei(). А зачем при этом еще и сохранять SREG - для меня загадка smile.gif

Цитата(aesok @ Sep 30 2010, 10:50) *
Спасибо большое, я об этом уже 3 года как не знаю, побегу сейчас на рабору перекомпилирую проект, может заработаент!!!

Ответ не тебе, а топикстартеру, а то что он трехлетней давности - что ж, не заметил...
alexeyv
Цитата(Mikron @ Sep 30 2010, 10:58) *
alexeyv, спасибо, но в даташите я не нашел
нужно ли как-то еще настраивать контроллер на запись/чтение
или достаточно использовать только библиотечные функции?

1. Перед использованием необходимо подключить заголовочный файл
#include <avr/eeprom.h>
Настраивать ничего не надо
Посмотрите файл <avr/eeprom.h>, там вы найдете еще несколько необходимых функций и макросов для работы с EEPROM

2. Если в EEPROM хранятся данные которые не надо терять при каждом программировании МК, то необходимо выставить FUSE-бит EESAVE

3. Т.к. запись происходит медленно и ресурс EEPROM ограничен, то запись необходимо производить как можно реже и в местах где быстродействие вашего алгоритма не критично (например, в прерываниях не рекомендуется). При перезаписи значений используйте функции eeprom_update_ХХХ

4. У некоторых МК встречал баг - при записи в EEPROM по адресу 0х00 процессор перестает работать. Так что не используйте этот адрес




to 777777
Цитата
А зачем при этом еще и сохранять SREG - для меня загадка


Сохранение/восстановление SREG - для использования функции в критических местах/секциях (например, в прерываниях), чтобы корректно восстановить флаг глобального разрешения прерываний (т.к. функция его меняет). То есть если они были разрешены, то после выполнения функции останутся разрешены, а если запрещены - то останутся запрещены
aesok
Цитата(777777 @ Sep 30 2010, 11:05) *
Так вот для этого и используются псевдофункции cli() и sei(). А зачем при этом еще и сохранять SREG - для меня загадка smile.gif


Код
cli ();
....
sei();


В этом примере код вначале запрещает прерываня, потом выполняет критичискую секцию затем разрешает преравания. Этот код кроме своей прямой функции выполняет еще одну паразитную, он ВСЕГДА разрешает преравания. Особенно опасно если он используеться в библиотечной функии, код которой програмисту не виден. Почему например при вызове функции EEPROM_write дожны разрешиться преравания? Ведь из имени этой функции следуеть что они пишет в EEPROM, про разрешения прерываний ни слова.


Код
u08 savedSREG;
savedSREG = SREG // keep setting so it can be restored
cli ();
...
SREG = savedSREG; // restore SREG


Этот код не изменяет состояния флага разрешения прерывиний. и никакого паразитного влияния на состояние флага не оказывает.

Анатолий.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.