Работа с внутренней EEPROM

Интересует работа с внутренней EEPROM, с внешней вы описали но мне такие обемы пока ненужны и хотелось бы пока научиться использовать собственные резервы мк

На асме я делал так

  1. //запись в память:
  2. LDI R16,0 ; Загружаем адрес нулевой ячейки
  3. LDI R17,0 ; EEPROM
  4. LDI R21,45 ; и хотим записать в нее число 45
  5. RCALL EEWrite ; вызываем процедуру записи.
  6.  
  7. //чтение:
  8. LDI R16,0 ; Загружаем адрес нулевой ячейки
  9. LDI R17,0 ; EEPROM из которой хотим прочитать байт
  10. RCALL EERead ; вызываем процедуру чтения. После которой
  11. ; в R21 будет считанный байт.
  12. //процедуры чтения и записи
  13. EEWrite:
  14. SBIC EECR,EEWE ; Ждем готовности памяти к записи. Крутимся в цикле
  15. RJMP EEWrite ; до тех пор пока не очистится флаг EEWE
  16.  
  17. CLI ; Затем запрещаем прерывания.
  18. OUT EEARL,R16 ; Загружаем адрес нужной ячейки
  19. OUT EEARH,R17 ; старший и младший байт адреса
  20. OUT EEDR,R21 ; и сами данные, которые нам нужно загрузить
  21.  
  22. SBI EECR,EEMWE ; взводим предохранитель
  23. SBI EECR,EEWE ; записываем байт
  24.  
  25. SEI ; разрешаем прерывания
  26. RET ; возврат из процедуры
  27.  
  28.  
  29. EERead:
  30. SBIC EECR,EEWE ; Ждем пока будет завершена прошлая запись.
  31. RJMP EERead ; также крутимся в цикле.
  32. OUT EEARL, R16 ; загружаем адрес нужной ячейки
  33. OUT EEARH, R17 ; его старшие и младшие байты
  34. SBI EECR,EERE ; Выставляем бит чтения
  35. IN R21, EEDR ; Забираем из регистра данных результат
  36. RET

Как это реализовать на си?

В том-то и прелесть Си, что

В том-то и прелесть Си, что можно переложить необходимость установки и контроля спец.битов на плечи компилятора. Обычно чтение и запись в EEPROM делается обычным присваиванием ("="). НО! Необходимо определить переменную в EEPROM.
Для CVAVR это так:

  1. char temp; //переменная в RAM
  2. eeprom my_eeprom1; //переменная в EEPROM
  3. eeprom my_eeprom2 @0x01; //переменная в EEPROM по адресу 0x01
  4. temp = my_eeprom1; //Чтение
  5. my_eeprom2 = temp; //Запись

Для IAR:

  1. char temp;
  2. __no_init __eeprom char my_eeprom1;//__no_init делает переменную не инициализированной
  3. __no_init __eeprom char my_eeprom2 @0x01;//
  4. temp = my_eeprom1; //Чтение
  5. my_eeprom2 = temp; //Запись

Для WinAVR по-моему так:

  1. #include 'avr/eeprom.h' //Подключаем библиотеку,кавычки заменить на треугольные скобки
  2. char temp;
  3. EEMEM char my_eeprom1;
  4. EEMEM char my_eeprom2;//Как расположить по адресу не знаю, может кто подскажет
  5. temp = eeprom_read_byte(&my_eeprom1);//Чтение
  6. eeprom_write_byte(&my_eeprom2, temp);//Запись

В том-то и прелесть Си, что

А какую библиотеку надо подключить в IAR для такого обращения

  1. char temp;
  2. __no_init __eeprom char my_eeprom1;//__no_init делает переменную не инициализированной
  3. __no_init __eeprom char my_eeprom2 @0x01;//
  4. temp = my_eeprom1; //Чтение
  5. my_eeprom2 = temp; //Запись

??????????????????????????????????????????

библиотеки для работы с внутренней EEPROM

Обязательно подрубить надо библиотеку:

  1. #include <avr/pgmspace.h> //библиотека для работы с внутренней памятью данных

  1. char peremennaya[] PROGMEM = "Hello"; //пример записи переменной в внутреннюю EEPROM

Дома код есть как пример работы. я что-то делал сам код не помню. Буду дома выложу!

По-моему, ты описал запись не

По-моему, ты описал запись не в EEPROM, а в программную FLASH память. PROGMEM - это programm memory, а не eeprom.

эээ... точно. затупил :-)

эээ... точно. затупил :-)

Александр Бондаренко ну а в

Александр Бондаренко ну а в avr gcc как это реализовать синтаксис кодевижина и студии различны

код на avr gcc

  1. <avr/eeprom.h> //подключаем библиотеку
  2.  
  3. #define __EEGET ( var, addr)
  4.  
  5. (var) = eeprom_read_byte ((const uint8_t *)(addr)) //чтение из eeprom
  6.  
  7.  
  8. #define __EEPUT ( addr, val)
  9.  
  10. eeprom_write_byte ((uint8_t *)(addr), (uint8_t)(val)) запись в eeprom

nongnu.org/avr-libc/user-manual/group__avr__eeprom.html
тут синтаксис по avr gcc

а немного подробней что зачем

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

Даташит на mega8 говорит по

Даташит на mega8 говорит по этому поводу вот так:

  1. unsigned char EEPROM_read(unsigned int uiAddress)
  2. {
  3. /* Wait for completion of previous write */
  4. while(EECR & (1<<EEWE))
  5. ;
  6. /* Set up address register */
  7. EEAR = uiAddress;
  8. /* Start eeprom read by writing EERE */
  9. EECR |= (1<<EERE);
  10. /* Return data from data register */
  11. return EEDR;
  12. }
  13.  
  14. void EEPROM_write(unsigned int uiAddress, unsigned char ucData)
  15. {
  16. /* Wait for completion of previous write */
  17. while(EECR & (1<<EEWE))
  18. ;
  19. /* Set up address and data registers */
  20. EEAR = uiAddress;
  21. EEDR = ucData;
  22. /* Write logical one to EEMWE */
  23. EECR |= (1<<EEMWE);
  24. /* Start eeprom write by setting EEWE */
  25. EECR |= (1<<EEWE);
  26. }

максимально просто и подробно.

нужен еще более подробный

нужен еще более подробный пример - как вызывать все это из основной программы, какие значения может принимать uiAddress? произвольные, как придумает пользователь, от 0 до 255? а в attiny eeprom вроде 128 байт..
правильно понимаю, что функции работают с байтами?

не совсем врубаюсь в смысл девятой строчки, а еще 23 и 25
но с этим всем все более-менее понятно станет после чтения даташита.
вот лучше расскажите, как успеть записывать в еепром только в момент отключения питания, чтобы не тратить ресурсы понапрасну (ведь количество перезаписей ограничено)
видел у мужика однного использовался некий компаратор -напряжение на схемы входе и напряжение на выходе со стабилизатора. как только на входе становилось меньше, чем на выходе стабилизатора -микроконтроллер понимал, что сейчас грядет poweroff и успевал за счет энергии в емкости записать рабочие значения в память.
самого кода я не видел, и не уверен, насколько эта идея применима к питанию от батареек...
и потом, как быстро в схеме пропадает напряжение? сколько времни остается на запись?

Куда уже подробней????

Куда уже подробней???? Конкретная функция для контроллера (у них может быть разный объем еепрома) копипастится из даташита. Какие значения uiAddress - смотришь сколько еепрома у контроллер, береш логарифм по основанию 2 и получаеш количество бит необходимых для адресации. Если памяти больше 256 байт но меньше 64кб, то используется 2 регистра для адресации.

Если вылезешь за пределы адресного пространства EEPROM'a - можно получить очень забавную и тяжелонаходимую багу.

Я детектил пропажу питания следующим образом: ставил диод по питанию, емкий кондер (около 200мкф), тоже по питанию и выводил внешнее прерывание int0 за диод. Как только пропадало питание - срабатывало int0, но контроллер при этом питается от конденсатора. А диод не дает остальной периферии красть заряд на кондере.

Также заострю внимание на том, что еепром капризен к питающему напряжению. Т.е. данные который пишутся на "последнем дыхании" могут быть повреждены.

vakula, а нарисуйте, плз,

vakula, а нарисуйте, плз, схему включения этого диода/кондера? и какие именно использовать? так, чтобы хватило dword записать в память?

сейчас у меня устройство питается от 9В кроны через вот такой модуль питания
embeddedmarket.com/products/Dual-Voltage-Output-Board-5V-3-3V/
от 3,3В (5В использовать типа не могу - работаю с uart портом низковольтным)

на этом модуле большая трехногая - L7805 вроде бы
а с обратной стороны малая - 1117 3.3

потом планирую придумать что-нибудь для того, чтобы работало от бортовой сети автомобиля, но все равно должно работать от 3,3В.

то есть для attiny2313

то есть для attiny2313 uiAddress может принимать значения от 0 до 127?
и нужно просто для себя запомнить, что я храню в ячейке 0, что - в ячейке 1, а что - в ячейке 127?
по питанию - в смысле последовательно от разъема питания?
короче говоря, идея понятна. а что, если не секрет, выполнялось в прерывании?
уж не запись ли в память? то есть конденсатора в 200мкф хватало?
кстати, любопытно, а как происходит переключение питания с сети на батарейку (в каких-нибудь ноутбуках, к примеру)

...и никакой выгоды от

...и никакой выгоды от использования Си-компилятора нет. Этот код будет работать во всех средах, но лучше почитать описание компилятора и использовать возможности оного...

Какая выгода от Си

Какая выгода от Си компилятора, если нужно тупо вбить данные в регистры?

Применяй синтаксис WinAvr...

Применяй синтаксис WinAvr...

ну вот вроде объяснили

ну вот вроде объяснили разобрался

для работы с EEPROM надо подключить к проекту модуль и пользоваться функциями eeprom_read_XXX() и eeprom_write_XXX(), где вместо XXX использовать byte, word, dword или block соответственно для чтениязаписи байта, двухбайтного int, 4 байтного long или структуры произвольного размера.

очень рекомендую вместо eeprom_write_XXX() использовать eeprom_update_XXX(), которая перед тем, как записать, проверит, что там уже в EEPROM содержится, и не станет записывать, если данные уже точно такие же - это существенно повышает ресурс жизни EEPROM.

так же рекомендую в своих проектах работать не с ячейками, а с переменными, определенными в секции памяти EEPROM, тогда адреса EEPROM компилятор будет распределять между переменными самостоятельно, и вам не надо будет даже про них знать:
Код:

  1. #include <avr/io.h>
  2. #include <avr/eeprom.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5.  
  6. EEMEM int var1 = 123;
  7. EEMEM char estr[] = "Demo";
  8.  
  9. int main(void){
  10. char str[20];
  11. if((int)eeprom_read_word(&var1) != 123){
  12. eeprom_update_block(estr,"Demon",6); // если в EEPROM было записано
  13. //"Demo", то тут допишется только последняя 'e' и ноль
  14. }
  15. eeprom_read_block(str, estr, 20);
  16. //printf("%s",str);

Это синтаксис CV AVR

printf - в синтаксисе WinAVR GCC такого оператора нету вообще!
Парень, разберись в чем ты пишешь.

А вот тут говорят, что есть

А вот тут говорят, что есть http://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html#ga4c04... ...или я чего напутал.
printf - это же форматированный вывод. Функция библиотеки 'stdio.h'.

И куда и как выводят при

И куда и как выводят при помощи этой функции данные в микроконтроллере?
Для CV AVR эта функция идет как часть библиотеки для работы с ЖКИ индикатором.

Ну как куда... В стандартную

Ну как куда... В стандартную консоль :)) Это стандартная функция ANSI C. http://www.csse.uwa.edu.au/programming/ansic-library.html#stdio

да мне он и ненужен я просто

да мне он и ненужен я просто юзал оттуда две операции записи и чтения еепром
собственно это
В WinAVR делается так:
eeprom_read_xxxx(uint8_t *adr) - считывает из EEPROM переменную, расположенную по адресу adr. вместо xxxx пишите byte, word или dword соответственно для чтения переменной размером в байт, 2 байта или 4 байта.
аналогично для записи имеются функции eeprom_write_xxxx(uint8_t *adr, ....) - вместо многоточия тип соответствующей переменной.
таким образом, получается примерно следующее:
Код:
#include (avr/eeprom.h) // скобки, естественно, угловые - форум не дает вставить нормальные

EEMEM uint8_t ee_var; // переменная размером в байт в EEPROM

int main(void){
uint8_t my_var;

my_var = eeprom_read_byte(&ee_var); // считали значение из EEPROM
...

eeprom_write_byte(&ee_var, my_var); // сохранили значение в EEPROM
}

И почему это именно оператор //printf("%s",str); разве это не может быть функцией передачи по уарту просто код не полностью дан пример работы только с еепром