реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> Прошивка Flash и EEPROM одним файлом hex или elf
Twin_by
сообщение May 25 2015, 05:26
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 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
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение May 25 2015, 13:54
Сообщение #2


неотягощённый злом
******

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



Цитата(Twin_by @ May 25 2015, 08:26) *

Неправильно вы вопрос ставите.
Всё зависит от того, какой утилитой вы пользуетесь для программирования (прошивки) микроконтроллера.
Смотрите доку на утилиту в части поддерживаемых ей форматов входных файлов и делайте выводы...
Одно могу сказать точно, что форматы с одним линейным адресным пространством
вряд ли могут быть использованы для программирования сразу двух независимых типов памяти AVR ввиду их наложения.


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
Twin_by
сообщение May 25 2015, 14:50
Сообщение #3


Участник
*

Группа: Участник
Сообщений: 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 . Там нужно что делать через линкеры, объектные файлы и тд. Но т.к у меня опыта еще маловато я не совсем понимаю о чем конкретно идет речь
Go to the top of the page
 
+Quote Post
alexeyv
сообщение May 26 2015, 03:51
Сообщение #4


Местный
***

Группа: Участник
Сообщений: 298
Регистрация: 26-01-09
Из: Пермь
Пользователь №: 43 940



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

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

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

Сообщение отредактировал alexeyv - May 26 2015, 03:53
Go to the top of the page
 
+Quote Post
Twin_by
сообщение May 26 2015, 04:44
Сообщение #5


Участник
*

Группа: Участник
Сообщений: 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
Go to the top of the page
 
+Quote Post
qwerty1023
сообщение May 26 2015, 07:00
Сообщение #6





Группа: Новичок
Сообщений: 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] - для короткого!
Go to the top of the page
 
+Quote Post
alexeyv
сообщение May 26 2015, 08:05
Сообщение #7


Местный
***

Группа: Участник
Сообщений: 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
Go to the top of the page
 
+Quote Post
Twin_by
сообщение May 28 2015, 11:09
Сообщение #8


Участник
*

Группа: Участник
Сообщений: 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 (для автоматического присвоения адреса) не получится
Go to the top of the page
 
+Quote Post
alexeyv
сообщение May 29 2015, 02:19
Сообщение #9


Местный
***

Группа: Участник
Сообщений: 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 МК входил в ступор (его победили, но привычка осталась)
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение May 29 2015, 08:07
Сообщение #10


неотягощённый злом
******

Группа: Свой
Сообщений: 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.
Урок окончен)))


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
qwerty1023
сообщение May 29 2015, 08:47
Сообщение #11





Группа: Новичок
Сообщений: 8
Регистрация: 9-04-14
Пользователь №: 81 295



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


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


А в какой момент и как это происходит?
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение May 29 2015, 08:52
Сообщение #12


неотягощённый злом
******

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



Цитата(qwerty1023 @ May 29 2015, 11:47) *
А в какой момент и как это происходит?
После сборки проекта вы получаете секцию с ЕЕПРОМ переменными в elf файле, после чего имеется возможность экспортировать эту секцию в eeprom-hex файл, а данные секции .text и иже с ним в flash-hex файл.
Потом программатором зашиваете эти оба файла в микроконтроллер.


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
Twin_by
сообщение May 29 2015, 09:09
Сообщение #13


Участник
*

Группа: Участник
Сообщений: 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
Go to the top of the page
 
+Quote Post
zltigo
сообщение May 29 2015, 09:10
Сообщение #14


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



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

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


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
VladislavS
сообщение May 31 2015, 11:31
Сообщение #15


Местный
***

Группа: Свой
Сообщений: 475
Регистрация: 14-04-05
Из: Москва
Пользователь №: 4 140



Цитата(zltigo @ May 29 2015, 12:10) *
Все. И никаких инициализаций EEPROM при программировании по причине нахренненужности.

Аналогично всегда делаю. Можно, конечно, придумать случай когда нет места для кода инициализации EEPROM, но мне такого не встречалось. И если мало переменных в EEPROM, то предпочитаю вместо сигнатуры сами данные на корректность проверять.
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 14th July 2025 - 04:58
Рейтинг@Mail.ru


Страница сгенерированна за 0.01519 секунд с 7
ELECTRONIX ©2004-2016