Переменная в eeprom по определенному адресу

Обсуждаем контроллеры компании Atmel.
Ответить
Вымогатель припоя
Аватара пользователя
Сообщения: 672
Зарегистрирован: Ср фев 29, 2012 01:58:32
Откуда: Харьков, Украина

Сообщение eess9 »

Привет всем!

Пишу на си в avr studio. В eeprom полно переменных, но одна из них должна четко находится по адресу 0х00 (т.к. к ней обращается bootloader со своей секции). Переменная uint8_t (в 1 байт), но как ее разместить четко по этому адресу, чтобы не заморачиватся больше.
Думал об ассемблерных вставках, почитал инет, но прояснилось не очень...
Заранее благодарен.
Реклама
Поставщик валерьянки для Кота
Сообщения: 2222
Зарегистрирован: Вт ноя 27, 2007 11:32:06
Откуда: Tashkent

Сообщение uk8amk »

Адреса вроде как назначаются в порядке описания переменных.
Если необходима жесткая привязка по адресам, то описывайте функции чтения-записи еепром вручную.

Согласно даташита на М8:

Код: Выделить всё

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);
}

unsigned char EEPROM_read(unsigned int uiAddress)
{
/* Wait for completion of previous write */
while(EECR & (1<<EEWE))
;
/* Set up address register */
EEAR = uiAddress;
/* Start eeprom read by writing EERE */
EECR |= (1<<EERE);
/* Return data from data register */
return EEDR;
}
ЗЫ. Говорить о переменных в EEPROM не совсем корректно т.к. это не RAM.
Реклама
YS
Друг Кота
Аватара пользователя
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05

Сообщение YS »

Если в AVR Studio, значит компилятор - AVR GCC. А коли так, то можно действовать именно так, как сказали выше - писать руками. С одной поправкой - работа с EEPROM уже описана в avr/eeprom.h

AVR GCC, в отличие от IAR, не поддерживает прозрачную запись в EEPROM - значения писать туда (читать из) надо руками с помощью функций eeprom_read_xxx / eeprom_write_xxx. А всякие спецификаторы типа EEMEM в этом случае - не более чем синтаксический сахар; переменную, объявленную со спецификатором EEMEM, все равно нельзя использовать в выражении напрямую.

Так что можно не париться и, если нужно четкое распределение по адресам, делать так:

Код: Выделить всё

#define ee_var ((uint8_t*)0x00)
А потом так:

Код: Выделить всё

#include <avr/io.h>
#include <avr/eeprom.h>
#include <stdint.h>

#define ee_var ((uint8_t*)0x00)

void main(void)
{
  eeprom_write_byte(ee_var,0xAA);

  while (1);
}

Можно, конечно, заморочиться и создать в конфиге линкера специальную секцию для нулевого адреса EEPROM (и потом прописать ее для переменной в __attribute__(...) ), но, IMHO, оно того не стоит.
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Контактная информация:
Вымогатель припоя
Аватара пользователя
Сообщения: 672
Зарегистрирован: Ср фев 29, 2012 01:58:32
Откуда: Харьков, Украина

Сообщение eess9 »

Спасибо YS. Я собственно так и думаю. Просто чего меня смущает: в этом случае компилятор сам раскидывает переменные в адресном пространстве eeprom. Логично, что он начнет с 0x00. Строка

Код: Выделить всё

eeprom_write_byte(0x00,0x01);
не сотрет переменную по адресу 0х00? Конечно есть предположение, что компилятор увидев эту запись начнет писать переменные с адреса 0х01. Но я в этом далеко не уверен.
Реклама
Эиком - электронные компоненты и радиодетали
YS
Друг Кота
Аватара пользователя
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05

Сообщение YS »

есть предположение, что компилятор увидев эту запись начнет писать переменные с адреса 0х01
Нет, не начнет. Для него такая "переменная" ничего не значит.

Да, когда переменные объявляются как переменные со спецификатором EEMEM, компилятор сам раскидывает адреса. Я к тому, что все переменные я бы заменил на такие дефайны, и отслеживал бы их пересечение/непересечение руками. Да, слегка неудобно, но в EEPROM и не бывает десятков переменных...

Если переменных все же много, и отслеживать их положение руками страсть как не хочется (и играться с линкером тоже), можно исхитриться так: завести структуру со всеми необходимыми переменными, создать указатель на нее и положить ее в EEPROM. Поля структуры всегда хранятся в порядке объявления, так что тут неожиданностей 100% не будет; при этом компилятор раскидает адреса сам.

Код: Выделить всё

#include <avr/io.h>
#include <avr/eeprom.h>
#include <stdint.h>

typedef struct {

  uint8_t my_param_1;
  uint32_t my_param_2;
  uint16_t my_param_3[5];

//...

} my_eeprom_config;

#define ee_conf ((my_eeprom_config *)0x00)

my_eeprom_config sram_copy_of_ee_config;

void main(void)
{
  eeprom_read_block(&sram_copy_of_ee_config,ee_conf,sizeof(my_eeprom_config));

  //...

  eeprom_write_block(&sram_copy_of_ee_config,ee_conf,sizeof(my_eeprom_config));

  //...

  while (1);
}
Единственно только, надо помнить про выравнивание. Но для AVR его, ЕМНИП, по-умолчанию нет.
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Контактная информация:
Реклама
Вымогатель припоя
Аватара пользователя
Сообщения: 672
Зарегистрирован: Ср фев 29, 2012 01:58:32
Откуда: Харьков, Украина

Сообщение eess9 »

Поиграть с линкером я как раз не против. Только никогда этого не делал. Почитал пару статеек в инете, чего то прояснилось, но явно не все.
Мне надо создать отдельную секцию в секции .eeprom. Правильно?
Что я для этого должен сделать: записать туда, куда показано на прикрепленном рисунке примерно следующее

Код: Выделить всё

-Wl,--section-start=.MySection=0xXXXX
, где 0xXXXX - где адрес первого байта eeprom моего контроллера.
И объявить переменную примерно так:

Код: Выделить всё

uint8_t __attribute__((section(".MySection"))) Peremennaya = 0;

К ней я уже могу обращаться стандартными функциями из eeprom.h
Я все правильно понял?
Вложения
Безымянный.jpg
(241.66 КБ) 705 скачиваний
Реклама
Вымогатель припоя
Сообщения: 630
Зарегистрирован: Пн июн 14, 2010 13:07:29
Откуда: Жуковский

Сообщение a_skr »

Работаю в WinAVR с makefile, но смысл тот же.

Код: Выделить всё

-Wl,--section-start,.eeprom=0x810001
Это укажет на то, что eeprom начинается с 1-го адреса, а не с нулевого. Т.е. ВСЕ переменные EEMEM расположатся, начиная с 1-го адреса. Стандартные функции eeprom_*_*() будут работать корректно:

Код: Выделить всё

char EEMEM a, b, c,...
eeprom_write_byte(&a, 0x55);
Для работы с неиспользуемым нулевым адресом нужно явно указать его при вызове этих функций. Кроме того, если нужна генерация .eep файла с инициализированными переменными EEMEM, то для obj-copy надо указать: --change-section-lma .eeprom=1. Где это в студии - не знаю. В моем makefile тут:

Код: Выделить всё

# Create final output files (.hex, .eep) from ELF output file.
...
%.eep: %.elf
	@echo
	@echo $(MSG_EEPROM) $@
	-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
	--change-section-lma .eeprom=1 --no-change-warnings -O $(FORMAT) $< $@ || exit 0
P.S.
Еще для отладки/симуляции через COFF тоже, возможно, надо поменять надо .eeprom-0x810000 на .eeprom-0x810001:

Код: Выделить всё

# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
COFFCONVERT = $(OBJCOPY) --debugging
COFFCONVERT += --change-section-address .data-0x800000
COFFCONVERT += --change-section-address .bss-0x800000
COFFCONVERT += --change-section-address .noinit-0x800000
COFFCONVERT += --change-section-address .eeprom-0x810000
Но в этом не уверен.
Вымогатель припоя
Аватара пользователя
Сообщения: 672
Зарегистрирован: Ср фев 29, 2012 01:58:32
Откуда: Харьков, Украина

Сообщение eess9 »

Уважаемый a_skr, спасибо, но мне, увы, это не помогло.
Все, что есть с eeprom в моем makefile:

Код: Выделить всё

"C:\Program Files (x86)\Atmel\Atmel Studio 6.0\extensions\Atmel\AVRGCC\3.4.0.65\AVRToolchain\bin\avr-objcopy.exe" -O ihex -R .eeprom -R .fuse -R .lock -R .signature  "WS Multichannel (ATXmega256A3U).elf" "WS Multichannel (ATXmega256A3U).hex"
	"C:\Program Files (x86)\Atmel\Atmel Studio 6.0\extensions\Atmel\AVRGCC\3.4.0.65\AVRToolchain\bin\avr-objcopy.exe" -j .eeprom  --set-section-flags=.eeprom=alloc,load --change-section-lma .eeprom=0  --no-change-warnings -O ihex "WS Multichannel (ATXmega256A3U).elf" "WS Multichannel (ATXmega256A3U).eep" || exit 0
	"C:\Program Files (x86)\Atmel\Atmel Studio 6.0\extensions\Atmel\AVRGCC\3.4.0.65\AVRToolchain\bin\avr-objdump.exe" -h -S "WS Multichannel (ATXmega256A3U).elf" > "WS Multichannel (ATXmega256A3U).lss"
что делать с этим я не знаю.
YS
Друг Кота
Аватара пользователя
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05

Сообщение YS »

eess9, я бы не стал ковырять конфиг линкера. ИМХО оно того не стоит - больно долго все это утрясать. Тем более, что, как показывает практика, не стоит ковырять без нужды то, что генерируется автоматически...

А чем Вам не нравится вариант со структурой? Все просто, логично и совершенно стандартно.
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Контактная информация:
Вымогатель припоя
Аватара пользователя
Сообщения: 672
Зарегистрирован: Ср фев 29, 2012 01:58:32
Откуда: Харьков, Украина

Сообщение eess9 »

Да, так и сделаю, просто контроллер ATXmega128A3U. У него в 2 килобайтах eeprom хранится 4 массива uint8_t по 100 значений в каждом, 4 массива uint16_t по 100 значений в каждом и еще массив переменной структуры 15 штук по байт этак 15 в каждом. Поэтому почти все 2 килобайта заполнены. И именно поэтому не хотелось все это ворошить, т.к. уж очень много всего. Все массивы могут меняться во время работы (в смысле не константы), поэтому как я не извращался, выпихнуть их во флеш ну нет никакой возможности, т.к. их надо изменять.
YS
Друг Кота
Аватара пользователя
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05

Сообщение YS »

И именно поэтому не хотелось все это ворошить
Так а особо ворошить не придется. Просто объявления убираем под структуру, а потом автозаменой меняем все обращения по старым именам переменных на "имя_структуры.старое_имя_переменной".
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Контактная информация:
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 2482
Зарегистрирован: Пт авг 27, 2010 05:57:06
Откуда: Тюмень

Сообщение vitalik_1984 »

YS писал(а):а потом автозаменой меняем все обращения по старым именам переменных на "имя_структуры.старое_имя_переменной".
В пятой студии для этого достаточно будет правым кликом выбрать меню переименовать переменную :roll: Или горячая клавиша shift+alt+R И все , остальное студия сама сделает...
Контактная информация:
Вымогатель припоя
Аватара пользователя
Сообщения: 672
Зарегистрирован: Ср фев 29, 2012 01:58:32
Откуда: Харьков, Украина

Сообщение eess9 »

Спасибо, так и сделал.
Ответить

Вернуться в «AVR»