Страница 1 из 1
Переменная в eeprom по определенному адресу
Добавлено: Пн ноя 25, 2013 18:58:21
eess9
Привет всем!
Пишу на си в avr studio. В eeprom полно переменных, но одна из них должна четко находится по адресу 0х00 (т.к. к ней обращается bootloader со своей секции). Переменная uint8_t (в 1 байт), но как ее разместить четко по этому адресу, чтобы не заморачиватся больше.
Думал об ассемблерных вставках, почитал инет, но прояснилось не очень...
Заранее благодарен.
Re: Переменная в eeprom по определенному адресу
Добавлено: Пн ноя 25, 2013 19:42:00
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.
Re: Переменная в eeprom по определенному адресу
Добавлено: Ср ноя 27, 2013 16:37:37
YS
Если в AVR Studio, значит компилятор - AVR GCC. А коли так, то можно действовать именно так, как сказали выше - писать руками. С одной поправкой - работа с EEPROM уже описана в avr/eeprom.h
AVR GCC, в отличие от IAR, не поддерживает прозрачную запись в EEPROM - значения писать туда (читать из) надо руками с помощью функций
eeprom_read_xxx / eeprom_write_xxx. А всякие спецификаторы типа EEMEM в этом случае - не более чем синтаксический сахар; переменную, объявленную со спецификатором EEMEM, все равно нельзя использовать в выражении напрямую.
Так что можно не париться и, если нужно четкое распределение по адресам, делать так:
А потом так:
Код: Выделить всё
#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, оно того не стоит.
Re: Переменная в eeprom по определенному адресу
Добавлено: Чт ноя 28, 2013 16:03:49
eess9
Спасибо
YS. Я собственно так и думаю. Просто чего меня смущает: в этом случае компилятор сам раскидывает переменные в адресном пространстве eeprom. Логично, что он начнет с 0x00. Строка
не сотрет переменную по адресу 0х00? Конечно есть предположение, что компилятор увидев эту запись начнет писать переменные с адреса 0х01. Но я в этом далеко не уверен.
Re: Переменная в eeprom по определенному адресу
Добавлено: Чт ноя 28, 2013 20:34:36
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 его, ЕМНИП, по-умолчанию нет.
Re: Переменная в eeprom по определенному адресу
Добавлено: Пт ноя 29, 2013 12:24:12
eess9
Поиграть с линкером я как раз не против. Только никогда этого не делал. Почитал пару статеек в инете, чего то прояснилось, но явно не все.
Мне надо создать отдельную секцию в секции .eeprom. Правильно?
Что я для этого должен сделать: записать туда, куда показано на прикрепленном рисунке примерно следующее
, где 0xXXXX - где адрес первого байта eeprom моего контроллера.
И объявить переменную примерно так:
Код: Выделить всё
uint8_t __attribute__((section(".MySection"))) Peremennaya = 0;
К ней я уже могу обращаться стандартными функциями из eeprom.h
Я все правильно понял?
Re: Переменная в eeprom по определенному адресу
Добавлено: Пт ноя 29, 2013 15:01:31
a_skr
Работаю в WinAVR с makefile, но смысл тот же.
Это укажет на то, что 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
Но в этом не уверен.
Re: Переменная в eeprom по определенному адресу
Добавлено: Пт ноя 29, 2013 15:42:50
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"
что делать с этим я не знаю.
Re: Переменная в eeprom по определенному адресу
Добавлено: Пт ноя 29, 2013 19:56:28
YS
eess9, я бы не стал ковырять конфиг линкера. ИМХО оно того не стоит - больно долго все это утрясать. Тем более, что, как показывает практика, не стоит ковырять без нужды то, что генерируется автоматически...
А чем Вам не нравится вариант со структурой? Все просто, логично и совершенно стандартно.
Re: Переменная в eeprom по определенному адресу
Добавлено: Вт дек 03, 2013 11:52:32
eess9
Да, так и сделаю, просто контроллер ATXmega128A3U. У него в 2 килобайтах eeprom хранится 4 массива uint8_t по 100 значений в каждом, 4 массива uint16_t по 100 значений в каждом и еще массив переменной структуры 15 штук по байт этак 15 в каждом. Поэтому почти все 2 килобайта заполнены. И именно поэтому не хотелось все это ворошить, т.к. уж очень много всего. Все массивы могут меняться во время работы (в смысле не константы), поэтому как я не извращался, выпихнуть их во флеш ну нет никакой возможности, т.к. их надо изменять.
Re: Переменная в eeprom по определенному адресу
Добавлено: Вт дек 03, 2013 18:53:01
YS
И именно поэтому не хотелось все это ворошить
Так а особо ворошить не придется. Просто объявления убираем под структуру, а потом автозаменой меняем все обращения по старым именам переменных на "имя_структуры.старое_имя_переменной".
Re: Переменная в eeprom по определенному адресу
Добавлено: Вт дек 03, 2013 21:09:01
vitalik_1984
YS писал(а):а потом автозаменой меняем все обращения по старым именам переменных на "имя_структуры.старое_имя_переменной".
В пятой студии для этого достаточно будет правым кликом выбрать меню переименовать переменную

Или горячая клавиша shift+alt+R И все , остальное студия сама сделает...
Re: Переменная в eeprom по определенному адресу
Добавлено: Ср дек 04, 2013 11:14:37
eess9
Спасибо, так и сделал.