|
|
  |
Кто использовал EEPROM AVR, подскажите что не так? |
|
|
|
Feb 5 2009, 15:01
|
Местный
  
Группа: Участник
Сообщений: 245
Регистрация: 15-08-07
Пользователь №: 29 795

|
Не получается сохранить данные в 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. Потратил много времени на поиск причины, но где ошибка, так и не понял.
|
|
|
|
|
Feb 5 2009, 17:56
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(Sirko @ Feb 5 2009, 18:01)  Не получается сохранить данные в EEPROM ATMega8515. Оптимизация включена полная ? Покажите листинг на асм. Между записью этих флагов дб не более 4 тактов проца: Код EECR |= _BV(EEMWE); // Установить флаг EEMWE EECR |= _BV(EEWE); // Начать запись в EEPROM в листинге, а у Вас там после считывания еще и OR присутствует, тч при отключенной оптимизации вполне вероятно >4 тактов
|
|
|
|
|
Feb 5 2009, 18:10
|

Чайник, 1 литр
   
Группа: Свой
Сообщений: 655
Регистрация: 17-05-06
Из: Moscow
Пользователь №: 17 168

|
Цитата(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 для этих строк получается жуткая конструкция, и тоже ничего не запишется. Ошибок других тоже не вижу, с примерами кода в ДШ совпадает - singlskv опередил
|
|
|
|
|
Feb 5 2009, 18:35
|
Местный
  
Группа: Участник
Сообщений: 245
Регистрация: 15-08-07
Пользователь №: 29 795

|
Народ, Огромное Вам Спасибо. Конечно же -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(); } Может подскажите, как написать Си код, что бы без оптимизации нормально компилился. Еще раз всем огромное Спасибо.
Сообщение отредактировал rezident - Feb 5 2009, 20:05
Причина редактирования: Уменьшение видимого объема цитаты исходника.
|
|
|
|
|
Feb 5 2009, 20:09
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(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));//Ждать завершения предыдущей записи Зачем ждать если в это время можно что-нить другое делать ? А ждать там мб несколько миллисекунд... Хотя конечно если реалтайм совсем не нужен, то можно и так...
|
|
|
|
|
Feb 6 2009, 09:48
|

Профессионал
    
Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357

|
Цитата(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(); }
Причина редактирования: Уменьшение видимого размера цитируемых исходников.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|