Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Кто использовал EEPROM AVR, подскажите что не так?
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Sirko
Не получается сохранить данные в EEPROM ATMega8515.

Упростил код до минимума

Код
[font="Courier New"]int main(void){
     u08 eeData = 0x22;
     u16 eeAddr = 20;
     while(EECR & _BV(EEWE));       //    Ждать завершения предыдущей записи
     EEAR = (eeAddr & 0x01ff);      //    Проинициализировать регистр адреса
     EEDR = eeData;
     EECR |= _BV(EEMWE);            //    Установить флаг EEMWE
     EECR |= _BV(EEWE);             //    Начать запись в EEPROM

     while(EECR & _BV(EEWE));       //    Ждать завершения предыдущей записи
//   EEAR = 0;                      //    Сбросить адрес EEPEROM в "0"

     while(EECR & _BV(EEWE));       //    Ждать завершения предыдущей записи
     EEAR = (eeAddr & 0x01ff);      //    Проинициализировать регистр адреса
     EECR |= _BV(EERE);             //    Выполнить чтение
     eeData = EEDR;

     while(EECR & _BV(EEWE));       //    Ждать завершения предыдущей записи
//   EEAR = 0;                      //    Сбросить адрес EEPEROM в "0"[/font]

и тем не менее на выходе 0xFF.
Потратил много времени на поиск причины, но где ошибка, так и не понял. unsure.gif
zombi
В СИ не пишу.
Вот так на асме делаю. Работает.
Код
; RH,RL - адрес
; RA - данные
WREPR:    SBIC    EECR,1
    RJMP    WREPR
    OUT    EEARH,RH
    OUT    EEARL,RL
    OUT    EEDR,RA
    SBI    EECR,2
    SBI    EECR,1
    RET
Палыч
Цитата(Sirko @ Feb 5 2009, 18:01) *
Потратил много времени на поиск причины, но где ошибка, так и не понял.
Может причина в низком Vcc?
Sirko
На всякий случай глянул, Vcc 4.96V
haker_fox
Вот точно рабочий код (ATmega168). На классы можно внимания не обращать.
Код
uint8_t TEEPROM::writeU8(uint16_t addr, uint8_t a)
{
    while(EECR & (1 << EEPE));
    EEAR = addr;
    EEDR = a;
        
        // тут очень желательно запретить все прерывания
    EECR|= (1 << EEMPE);
    EECR|= (1 << EEPE);
        // а тут их снова можно включить

    return EEPROM_OK_RESULT;
}

uint8_t TEEPROM::readU8(uint16_t addr)
{
    while(EECR & (1 << EEPE));
    EEAR = addr;
    EECR|= (1 << EERE);
    return EEDR;
}


Причины неработоспособности Вашего кода на первый взгляд, увы, не вижу... Вот только _BV не нравится мне... И зачем адрес умножать на 0x1ff?
singlskv
Цитата(Sirko @ Feb 5 2009, 18:01) *
Не получается сохранить данные в EEPROM ATMega8515.
Оптимизация включена полная ?
Покажите листинг на асм.

Между записью этих флагов дб не более 4 тактов проца:
Код
     EECR |= _BV(EEMWE);            //    Установить флаг EEMWE
     EECR |= _BV(EEWE);             //    Начать запись в EEPROM

в листинге, а у Вас там после считывания еще и OR присутствует, тч при отключенной оптимизации вполне вероятно >4 тактов
SysRq
Цитата(haker_fox @ Feb 5 2009, 19:42) *
Вот только _BV не нравится мне...

_BV(x) в WinAVR вроде нормально работает... эквивалентно (1 << (x)) как минимум...

Цитата(Sirko @ Feb 5 2009, 18:01) *
Код
     EECR |= _BV(EEMWE);            //    Установить флаг EEMWE
     EECR |= _BV(EEWE);             //    Начать запись в EEPROM

Если между этими строчками сработает прерывание, то не запишется.
Если оптимизация вдруг отключена, то вместо sbi для этих строк получается жуткая конструкция, и тоже ничего не запишется.

Ошибок других тоже не вижу, с примерами кода в ДШ совпадает biggrin.gif

-
singlskv опередил smile.gif
Sirko
Народ, Огромное Вам Спасибо.
Конечно же -O0 имело место быть.

Уже даже начал кусочек ASMa цитировать, как обратил внимание на "кучу, кучу всего".
Жалко времени, гадко, что у самого ума не хватило, но опыта нет, а опыт - сын ...

Включил оптимизацию, все заработало.
Не знаю, как дальше пойдет дело, но просьба, если не сложно, прокоментируйте фрагмент кода, с которого все началось.
Возможно есть откровенные бока.
На счет маски 0x01ff - это была последняя надежда, хоть и глупая (где-то увидел).

CODE
void
EEPROM_write(volatile u08 bankNumber, volatile void *data, volatile u08 length){
cli();
u16 address = 1 + bankNumber * length;
u16 endAddress = address + length;
u08* pointer = (u08*) data;
while(address < endAddress){
while(EECR & _BV(EEWE)); // Ждать завершения предыдущей записи
EEAR = address++; // Проинициализировать регистр адреса
EEDR = *(pointer++);
EECR |= _BV(EEMWE); // Установить флаг EEMWE
EECR |= _BV(EEWE); // Начать запись в EEPROM
}
while(EECR & _BV(EEWE)); // Ждать завершения предыдущей записи
EEAR = 0; // Сбросить адрес EEPEROM в "0"
sei();
}

void
EEPROM_read(volatile u08 bankNumber, volatile void *data, volatile u08 length){
cli();
u16 address = 1 + bankNumber * length;
u16 endAddress = address + length;
u08* pointer = (u08*) data;
while(address < endAddress){
while(EECR & _BV(EEWE)); // Ждать завершения предыдущей записи
EEAR = address++; // Проинициализировать регистр адреса
EECR |= _BV(EERE); // Выполнить чтение
*(pointer++) = EEDR;
}
while(EECR & _BV(EEWE)); // Ждать завершения предыдущей записи
EEAR = 0; // Сбросить адрес EEPEROM в "0"
sei();
}


Может подскажите, как написать Си код, что бы без оптимизации нормально компилился.

Еще раз всем огромное Спасибо.
SysRq
Цитата(Sirko @ Feb 5 2009, 21:35) *
Может подскажите, как написать Си код, что бы без оптимизации нормально компилился.

WinAVR\avr\include\avr\eeprom.h rolleyes.gif
singlskv
Цитата(Sirko @ Feb 5 2009, 21:35) *
Может подскажите, как написать Си код, что бы без оптимизации нормально компилился.
ИМХО, не нужно и пытаться без оптимизации что либо компилить, иначе Вы очень сильно
рискуете когда перестанет хватать флеши или скорости и Вы оптимизацию включите.
Вместо ловли ошибок по-одной по мере увеличения проги, Вы рискуете получить массу ошибок казалось бы на ровном месте...

Цитата
Код
    cli();
    while(EECR & _BV(EEWE));            //    Ждать завершения предыдущей записи
..............................................
        EECR |= _BV(EEMWE);            //    Установить флаг EEMWE
        EECR |= _BV(EEWE);            //    Начать запись в EEPROM
.............................................
    while(EECR & _BV(EEWE));            //    Ждать завершения предыдущей записи
.............................................                        //    Сбросить адрес EEPEROM в "0"
    sei();

запрещать прерывания необходимо только на время:
EECR |= _BV(EEMWE);
EECR |= _BV(EEWE);

ну и мне всегда не нравилось вот такое:
while(EECR & _BV(EEWE));//Ждать завершения предыдущей записи

Зачем ждать если в это время можно что-нить другое делать ?
А ждать там мб несколько миллисекунд...
Хотя конечно если реалтайм совсем не нужен, то можно и так...
demiurg_spb
Цитата(singlskv @ Feb 5 2009, 23:09) *
while(EECR & _BV(EEWE));//Ждать завершения предыдущей записи
Зачем ждать если в это время можно что-нить другое делать ?
А ждать там мб несколько миллисекунд...
Это точно. Проверять на занятость eeprom имеет смысл лишь единожды перед началом новых с ним операций.
777777
Цитата(Sirko @ Feb 5 2009, 21:35) *
Может подскажите, как написать Си код, что бы без оптимизации нормально компилился.

Это еще что за глупости? Оптимизация - обязательная часть процесса компиляции, без нее получается код в 4...5 раз больше и, соответственно, медленнее. Вы тоже наслушались страшилок об ошибках оптимизации? Отключение оптимизации IMHO предназначено исключительно для того, чтобы в случае, если вам покажется что в оптимизации ошибка, вы могли ее отключить и убедиться, что на самом деле ошибка в вашем коде.

У меня для работы с EEPROM есть два файла - eerw.h и eerw.c, я их просто подключаю к проекту и пользуюсь их функциями. Для записи там используется кольцевой буфер - если запись уже идет, то данные помещаются в этот буфер, а по прерыванию по завершении предыдущего цикла записи выбираются из буфера и ставятся на запись.
В основной программе нужно только вызвать EEInit() в начале, там где программируются порты и пр.
CODE
//
// eerw.h
//

#define EE_SIZE 16 // размер кольцевого буфера для записи в EEPROM

typedef struct tagEEdata
{
uint8_t Adr;
uint8_t Data;
} CEEdata;

void EEinit();
uint8_t ReadEE(uint8_t adr);
uint16_t ReadEE2(uint8_t adr);
uint32_t ReadEE4(uint8_t adr);
void WriteEE(uint8_t data, uint8_t adr);
void WriteEE2(uint16_t data, uint8_t adr);
void WriteEE4(uint32_t data, uint8_t adr);
void WriteNextByte();

CODE
//
// eerw.c - функции для чтения/записи в EEPROM
//

#include <avr/io.h>
#include <avr/interrupt.h>
#include "eerw.h"

CEEdata EEdata[EE_SIZE]; // буфер данных для записи в EEPROM
CEEdata *pInPtr, *pOutPtr; // указатели для записи в EEPROM

/*
* работа с EEPROM
*/

void EEinit()
{
pInPtr = pOutPtr = EEdata;
}

uint8_t ReadEE(uint8_t adr)
{
while(EECR & _BV(EEWE))
{}
EEAR = adr;
EECR |= _BV(EERE);
return EEDR;
}

uint16_t ReadEE2(uint8_t adr)
{
uint16_t res1 = ReadEE(adr), res2 = ReadEE(adr+1);
return res1 | (res2<<8);
}

uint32_t ReadEE4(uint8_t adr)
{
uint32_t res1 = ReadEE2(adr), res2 = ReadEE2(adr+2);
return res1 | (res2<<16);
}

void WriteEE(uint8_t data, uint8_t adr)
{
pInPtr->Adr = adr;
pInPtr->Data = data;
if(++pInPtr == &EEdata[EE_SIZE])
pInPtr = EEdata;
cli();
if((EECR & _BV(EERIE)) == 0)
{
EECR |= _BV(EERIE);
WriteNextByte();
}
sei();
}

void WriteEE2(uint16_t data, uint8_t adr)
{
WriteEE(data, adr);
WriteEE((data&0xff00)>>8, adr+1);
}

void WriteEE4(uint32_t data, uint8_t adr)
{
WriteEE2(data, adr);
WriteEE2((data&0xffff0000)>>16, adr+2);
}

void WriteNextByte()
{
EEAR = pOutPtr->Adr;
EEDR = pOutPtr->Data;
if(++pOutPtr == &EEdata[EE_SIZE])
pOutPtr = EEdata;
cli();
EECR |= _BV(EEMWE);
EECR |= _BV(EEWE);
sei();
}

/*
* Обработчик прерывания от EEPROM
*/

ISR(EE_RDY_vect)
{
if(pOutPtr == pInPtr)
EECR &= ~_BV(EERIE);
else
WriteNextByte();
}
Andrew_k5
while (i<17) //kolvo bayt
{
while (EECR.1 != 0); //povtor poka ne budut zapisani
EEAR =i; //adress
EEDR =DataTransfer[i]; //dannie
EECR.2 = 1;
EECR.1 = 1;
i++;
}
Точно работает
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.