Перейти к содержанию
    

Прошивка Flash и EEPROM одним файлом hex или elf

Здравствуйте!

У меня такая вот ситуация. Подключаю библиотеку eeprom.h. Инициализирую переменную в eeprom памяти строчкой uint8_t var EEMEM = 15; . После сборки создается файл с расширением eep который заливается в МК отдельно. Интересен такой вопрос можно ли прошить flash и eeprom память avr используя только один файл hex или elf? Как это сделать: что добавить, что убрать? От библиотеки eeprom.h не хотелось бы отказываться (хорошая библиотека, удобная)

Изменено пользователем Twin_by

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Неправильно вы вопрос ставите.

Всё зависит от того, какой утилитой вы пользуетесь для программирования (прошивки) микроконтроллера.

Смотрите доку на утилиту в части поддерживаемых ей форматов входных файлов и делайте выводы...

Одно могу сказать точно, что форматы с одним линейным адресным пространством

вряд ли могут быть использованы для программирования сразу двух независимых типов памяти AVR ввиду их наложения.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Неправильно вы вопрос ставите.

Всё зависит от того, какой утилитой вы пользуетесь для программирования (прошивки) микроконтроллера.

Смотрите доку на утилиту в части поддерживаемых ей форматов входных файлов и делайте выводы...

Одно могу сказать точно, что форматы с одним линейным адресным пространством

вряд ли могут быть использованы для программирования сразу двух независимых типов памяти AVR ввиду их наложения.

 

прошиваю я через Atmel Studio 6.2. В закладке Memories (Menu -> Tools -> Device Programming) указываю путь для elf файла и отдельно путь для eep файла. Встала задача для прошивки МК использовать только один файл (hex или elf). На форуме я видел что то похожее http://electronix.ru/forum/index.php?showt...73&hl=EEMEM . Там нужно что делать через линкеры, объектные файлы и тд. Но т.к у меня опыта еще маловато я не совсем понимаю о чем конкретно идет речь

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1. На производстве используют программатор ASISP и ПО к нему. В нем можно создать проект в котором указывается файл для FLASH, файл для EEPROM, настройки FUSE/LOCK бит, проверку всего после прошивки и кое что еще по мелочи (типа запись счетчика в EEPROM - серийный номер платы). Этот проект настраивается один раз и сохраняется. Далее наладчику/настройщику остается нажать кнопку "Автопрограммирование" один раз для каждой платы.

 

2. По поводу работы с EEPROM. В начале программы определяется чиста ли EEPROM. Если чиста - то вызывается функция начальной инициализации. Далее - обычная работа программы. Таким образом не надо создавать отдельного файла для прошивки EEPROM - код программы сам ее инициализирует при первом запуске программы.

 

P.S. ASISP можно подключить в ввиде тулза к Atmel Studio и для программирования надо будет нажимать одну кнопку из Atmel Studio.

Изменено пользователем alexeyv

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2. По поводу работы с EEPROM. В начале программы определяется чиста ли EEPROM. Если чиста - то вызывается функция начальной инициализации. Далее - обычная работа программы. Таким образом не надо создавать отдельного файла для прошивки EEPROM - код программы сам ее инициализирует при первом запуске программы.

 

Т.е вы предлагаете после начала функции main проверять пуста ли EEPROM. Если Да, то инициализировать переменную uint8_t var EEMEM = 15; Правильно я понимаю???

 

Вот сейчас попробовал инициализировать переменную после начала функции main. И как то безрезультатно, не дает мне этого сделать. Позволяет инициализировать только перед функцией main где инициализируются глобальные переменные.

Изменено пользователем Twin_by

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Тут наверное имеется в виду что-то типа

 

//_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 и т.п. но при этом иметь структурированные данные для нормальной читаемости программы.

 

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
[codebox] для длинного кода, [code] - для короткого!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Выбираешь один из неиспользуемых адресов в 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Например:

#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 (для автоматического присвоения адреса) не получится

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если я правильно понял ваш код, то вы в нем сами присваиваете адрес ячейки в 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 МК входил в ступор (его победили, но привычка осталась)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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.

Урок окончен)))

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Задаёте значения своим переменным:

EEMEM eeprom_data_t eeprom =
{
    .var1 = 33U,
    .var2 = 333.0f
}

 

Урок окончен)))

 

А в какой момент и как это происходит?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А в какой момент и как это происходит?
После сборки проекта вы получаете секцию с ЕЕПРОМ переменными в elf файле, после чего имеется возможность экспортировать эту секцию в eeprom-hex файл, а данные секции .text и иже с ним в flash-hex файл.

Потом программатором зашиваете эти оба файла в микроконтроллер.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

После сборки проекта вы получаете секцию с ЕЕПРОМ переменными в elf файле, после чего имеется возможность экспортировать эту секцию в eeprom-hex файл, а данные секции .text и иже с ним в flash-hex файл.

Потом программатором зашиваете эти оба файла в микроконтроллер.

 

Т.е все равно нужно использовать два файла для прошивки eeprom и flash?

Изменено пользователем Twin_by

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1) Все данные ЕЕPROМ в структуру, это святое и не обсуждаемо.

2) Такм-же в структуре сигнатура размером в несколько байт.

3) При запуске проверка сигнатуры, если ее нет, то инициализация данных значениями по умолчанию и пофиг, это первый запуск или содержимое слетело. Сигнатуру можно менять и при изменениии версии софта требующей других начальных установок или расширения данных. Такой поход к делу позволяет так-же не заморчиваться содержимым EEPROМ и при внутрисхемном программировании.

 

Все. И никаких инициализаций EEPROM при программировании по причине нахренненужности.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Все. И никаких инициализаций EEPROM при программировании по причине нахренненужности.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...