|
Прошивка Flash и EEPROM одним файлом hex или elf |
|
|
|
May 25 2015, 05:26
|
Участник

Группа: Участник
Сообщений: 32
Регистрация: 3-09-11
Из: Минск
Пользователь №: 66 982

|
Здравствуйте! У меня такая вот ситуация. Подключаю библиотеку eeprom.h. Инициализирую переменную в eeprom памяти строчкой uint8_t var EEMEM = 15; . После сборки создается файл с расширением eep который заливается в МК отдельно. Интересен такой вопрос можно ли прошить flash и eeprom память avr используя только один файл hex или elf? Как это сделать: что добавить, что убрать? От библиотеки eeprom.h не хотелось бы отказываться (хорошая библиотека, удобная)
Сообщение отредактировал Twin_by - May 25 2015, 09:41
|
|
|
|
|
May 25 2015, 13:54
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(Twin_by @ May 25 2015, 08:26)  Неправильно вы вопрос ставите. Всё зависит от того, какой утилитой вы пользуетесь для программирования (прошивки) микроконтроллера. Смотрите доку на утилиту в части поддерживаемых ей форматов входных файлов и делайте выводы... Одно могу сказать точно, что форматы с одним линейным адресным пространством вряд ли могут быть использованы для программирования сразу двух независимых типов памяти AVR ввиду их наложения.
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
May 25 2015, 14:50
|
Участник

Группа: Участник
Сообщений: 32
Регистрация: 3-09-11
Из: Минск
Пользователь №: 66 982

|
Цитата(demiurg_spb @ May 25 2015, 16:54)  Неправильно вы вопрос ставите. Всё зависит от того, какой утилитой вы пользуетесь для программирования (прошивки) микроконтроллера. Смотрите доку на утилиту в части поддерживаемых ей форматов входных файлов и делайте выводы... Одно могу сказать точно, что форматы с одним линейным адресным пространством вряд ли могут быть использованы для программирования сразу двух независимых типов памяти AVR ввиду их наложения. прошиваю я через Atmel Studio 6.2. В закладке Memories (Menu -> Tools -> Device Programming) указываю путь для elf файла и отдельно путь для eep файла. Встала задача для прошивки МК использовать только один файл (hex или elf). На форуме я видел что то похожее http://electronix.ru/forum/index.php?showt...73&hl=EEMEM . Там нужно что делать через линкеры, объектные файлы и тд. Но т.к у меня опыта еще маловато я не совсем понимаю о чем конкретно идет речь
|
|
|
|
|
May 26 2015, 04:44
|
Участник

Группа: Участник
Сообщений: 32
Регистрация: 3-09-11
Из: Минск
Пользователь №: 66 982

|
Цитата(alexeyv @ May 26 2015, 06:51)  2. По поводу работы с EEPROM. В начале программы определяется чиста ли EEPROM. Если чиста - то вызывается функция начальной инициализации. Далее - обычная работа программы. Таким образом не надо создавать отдельного файла для прошивки EEPROM - код программы сам ее инициализирует при первом запуске программы. Т.е вы предлагаете после начала функции main проверять пуста ли EEPROM. Если Да, то инициализировать переменную uint8_t var EEMEM = 15; Правильно я понимаю??? Вот сейчас попробовал инициализировать переменную после начала функции main. И как то безрезультатно, не дает мне этого сделать. Позволяет инициализировать только перед функцией main где инициализируются глобальные переменные.
Сообщение отредактировал Twin_by - May 26 2015, 05:16
|
|
|
|
|
May 26 2015, 07:00
|
Группа: Новичок
Сообщений: 8
Регистрация: 9-04-14
Пользователь №: 81 295

|
Тут наверное имеется в виду что-то типа Код //_e_data_ok магическая константа #define DATA_OK 0x5A
volatile __no_init __eeprom uchar EEMEM; volatile __no_init __eeprom uchar _e_data_ok;
void main(void) {
if (_e_data_ok != DATA_OK) { EEMEM = 15; _e_data_ok = DATA_OK; }
while(1) { .... }
} А вообще, если это ответсвенная переменная, не помешало бы "накрыть" это все какойнить crc и уже по целостности crc судить о валидности данных в EEPROM. Вот вам идеи для творчества. Удобно использовать объединения, тогда к блоку данных можно обращаться как к масиву байт при, например чтении его из памяти, подсчете crc и т.п. но при этом иметь структурированные данные для нормальной читаемости программы. CODE struct sEEPROMSet { ... uchar msgAllEnd2DurationSec; // длительность "пииик" x100мс uint devSetFlags; //uint crc16; - не участвует в стркуктуре для экономии ОЗУ но есть во флеш };
union { uchar byte[sizeof(sEEPROMSet)]; sEEPROMSet; } block;
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++ //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++
uint crc16update(uchar inData, uint inCrc) { uchar i;
// считаем crc inCrc ^= inData;
for (i = 0; i < 8; i++) { if (inCrc & 1) { inCrc >>= 1; inCrc ^= 0x1021; } else { inCrc >>= 1; } } return inCrc; }
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++ //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++
bool GetMemBlock(ulong start, uint dataSize, uchar * data) { uchar tmpData; uint s, memCrc, crc = 0xFFFF;
//Led2On();
// записываем комманду непрерывного чтения memStart(); SPIRW(0x03); // непрерывное чтение memSetAdr(start);
for(s = 0; s < dataSize; s++) { // читаем байт из флешки tmpData = SPIRW(0); // записываем по указателю и увеличиваем указатель data[s] = tmpData; // считаем crc crc = crc16update(tmpData, crc); }
// читаем значение CRC16 memCrc = SPIRW(0); memCrc |= (SPIRW(0) << 8);
memStop();
//Led2Off();
// проверяем if (crc == memCrc) { return true; } else { return false; } }
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++ //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++
bool LoadSettings(uchar modeNum) { union { uchar byte[sizeof(sWorkModeSetBlock)]; sWorkModeSetBlock; } block;
// читаем таблицу размещения настроек режимов if (!GetMemBlock((ulong)WORK_MODE_TABLE_START_ADR, (uint)sizeof(sWorkModeSetBlock), block.byte)) { // ошибка при чтении блока, аварийный выход LCD_send(0x0E,'r',0xFF,0x00,0xFF,0xFF,0xFF,0xFF,0,0); return false; }
// блок считался без ошибок, выбираем настройки режима
// заполняем рабочую структуру настроек
//копируем тип режима workData.soundMode = block.modeSet[modeNum].soundMode;
// копируем настройки обязательного звука 1 msgBeep1Adr = block.msgAllEnd1Adr; // адресс начала звука "пик-пик" во флешке msgBeep1DurationSempl = block.msgAllEnd1DurationSempl; // длительность "пик-пик" в семплах msgBeep1DurationSec = block.msgAllEnd1DurationSec; // длительность "пик-пик" x100мс
Сообщение отредактировал IgorKossak - May 26 2015, 13:04
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!
|
|
|
|
|
May 26 2015, 08:05
|
Местный
  
Группа: Участник
Сообщений: 298
Регистрация: 26-01-09
Из: Пермь
Пользователь №: 43 940

|
Выбираешь один из неиспользуемых адресов в EEPROM и сравниваешь его с 0xFF - если совпало, пишешь туда что-то не равное 0xFF и инициализируешь все остальные переменные, хранящиеся в EEPROM. Например: Код #define EE_ADR_FLAG ((void*)0x10) unsigned char val = eeprom_read_byte(EE_ADR_FLAG); if(val == 0xFF) { // инициализируем другие переменные // ................ eeprom_write_byte(EE_ADR1,DEF_ADR1); eeprom_write_byte(EE_ADR2,DEF_ADR2); // ................ // изменяем флажок - все записано eeprom_write_byte(EE_ADR_FLAG,0xAA); }
// дальше считываем из EEPROM в рабочие переменные в оперативной памяти val1 = eeprom_read_byte(EE_ADR1); val2 = eeprom_read_byte(EE_ADR2);
Сообщение отредактировал alexeyv - May 26 2015, 08:17
|
|
|
|
|
May 28 2015, 11:09
|
Участник

Группа: Участник
Сообщений: 32
Регистрация: 3-09-11
Из: Минск
Пользователь №: 66 982

|
Цитата(alexeyv @ May 26 2015, 11:05)  Например: Код #define EE_ADR_FLAG ((void*)0x10) unsigned char val = eeprom_read_byte(EE_ADR_FLAG); if(val == 0xFF) { // инициализируем другие переменные // ................ eeprom_write_byte(EE_ADR1,DEF_ADR1); eeprom_write_byte(EE_ADR2,DEF_ADR2); // ................ // изменяем флажок - все записано eeprom_write_byte(EE_ADR_FLAG,0xAA); }
// дальше считываем из EEPROM в рабочие переменные в оперативной памяти val1 = eeprom_read_byte(EE_ADR1); val2 = eeprom_read_byte(EE_ADR2); Если я правильно понял ваш код, то вы в нем сами присваиваете адрес ячейки в eeprom где будет хранится значение переменной? Т.е использовать директиву EEMEM (для автоматического присвоения адреса) не получится
|
|
|
|
|
May 29 2015, 02:19
|
Местный
  
Группа: Участник
Сообщений: 298
Регистрация: 26-01-09
Из: Пермь
Пользователь №: 43 940

|
Цитата Если я правильно понял ваш код, то вы в нем сами присваиваете адрес ячейки в eeprom где будет хранится значение переменной? Т.е использовать директиву EEMEM (для автоматического присвоения адреса) не получится Почему же, получится! можете использовать и EEMEM Код unsigned char eeprom_var1 EEMEM; ...... eeprom_write_byte(eeprom_var1,DEFAUT_VALUE); ..... val1 = eeprom_read_byte(eeprom_var1); Просто я уже привык определять адреса таким образом. При отладке знаешь где посмотреть переменную, не надо лазить по map-файлам. Да и раньше у Atmel'a был один косячок с EEPROM - при расположении переменных по каким-то адресам в EEPROM МК входил в ступор (его победили, но привычка осталась)
|
|
|
|
|
May 29 2015, 08:07
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(alexeyv @ May 29 2015, 05:19)  Код val1 = eeprom_read_byte(eeprom_var1); 1. Во всех ваших примерах надо добавить &eeprom_var1... 2. Лет 10 как никаких проблем с EEPROM нет, да и те, что были, вами лично надуманы. Единственное, что было это: http://www.nongnu.org/avr-libc/user-manual...prom_corruption А привычка у вас плохая осталась - компилятор не проверяет типизацию при обращении к данным. Возникает дополнительный шанс совершить ошибку. 3. Вообще с eeprom правильно работать следующим образом: Через typedef определяете структуру, содержащую все данные из EEPROM: Код typedef struct { uint8_t __dummy; // don't use zero address uint8_t var1; float var2; ... } eeprom_data_t; Задаёте значения своим переменным: Код EEMEM eeprom_data_t eeprom = { .var1 = 33U, .var2 = 333.0f }; Работаете с ними: Код extern EEMEM eeprom_data_t eeprom; uint8_t x = eeprom_read_byte(&eeprom.var1); ... eeprom_update_byte(&eeprom.var1, x);
float f = eeprom_read_float(&eeprom.var2); ... eeprom_update_float(&eeprom.var2, f); В таком случае вы дополнительно обеспечиваете гарантию неизменности задуманной вами очерёдности данных в EEPROM, независимо от версий и причуд компилятора (хорошо бы, конечно, использовать ещё и атрибут __packed, но для вводного курса этого и так достаточно). Также, благодаря update вместо write вы упрощаете пользовательское приложение и подливаете срок службы EEPROM. Урок окончен)))
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
May 29 2015, 08:47
|
Группа: Новичок
Сообщений: 8
Регистрация: 9-04-14
Пользователь №: 81 295

|
Цитата(demiurg_spb @ May 29 2015, 11:07)  Задаёте значения своим переменным: Код EEMEM eeprom_data_t eeprom = { .var1 = 33U, .var2 = 333.0f } Урок окончен))) А в какой момент и как это происходит?
|
|
|
|
|
May 29 2015, 09:09
|
Участник

Группа: Участник
Сообщений: 32
Регистрация: 3-09-11
Из: Минск
Пользователь №: 66 982

|
Цитата(demiurg_spb @ May 29 2015, 11:52)  После сборки проекта вы получаете секцию с ЕЕПРОМ переменными в elf файле, после чего имеется возможность экспортировать эту секцию в eeprom-hex файл, а данные секции .text и иже с ним в flash-hex файл. Потом программатором зашиваете эти оба файла в микроконтроллер. Т.е все равно нужно использовать два файла для прошивки eeprom и flash?
Сообщение отредактировал Twin_by - May 29 2015, 09:09
|
|
|
|
|
May 31 2015, 11:31
|
Местный
  
Группа: Свой
Сообщений: 475
Регистрация: 14-04-05
Из: Москва
Пользователь №: 4 140

|
Цитата(zltigo @ May 29 2015, 12:10)  Все. И никаких инициализаций EEPROM при программировании по причине нахренненужности. Аналогично всегда делаю. Можно, конечно, придумать случай когда нет места для кода инициализации EEPROM, но мне такого не встречалось. И если мало переменных в EEPROM, то предпочитаю вместо сигнатуры сами данные на корректность проверять.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|