Twin_by 0 25 мая, 2015 Опубликовано 25 мая, 2015 (изменено) · Жалоба Здравствуйте! У меня такая вот ситуация. Подключаю библиотеку eeprom.h. Инициализирую переменную в eeprom памяти строчкой uint8_t var EEMEM = 15; . После сборки создается файл с расширением eep который заливается в МК отдельно. Интересен такой вопрос можно ли прошить flash и eeprom память avr используя только один файл hex или elf? Как это сделать: что добавить, что убрать? От библиотеки eeprom.h не хотелось бы отказываться (хорошая библиотека, удобная) Изменено 25 мая, 2015 пользователем Twin_by Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 25 мая, 2015 Опубликовано 25 мая, 2015 · Жалоба Неправильно вы вопрос ставите. Всё зависит от того, какой утилитой вы пользуетесь для программирования (прошивки) микроконтроллера. Смотрите доку на утилиту в части поддерживаемых ей форматов входных файлов и делайте выводы... Одно могу сказать точно, что форматы с одним линейным адресным пространством вряд ли могут быть использованы для программирования сразу двух независимых типов памяти AVR ввиду их наложения. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Twin_by 0 25 мая, 2015 Опубликовано 25 мая, 2015 · Жалоба Неправильно вы вопрос ставите. Всё зависит от того, какой утилитой вы пользуетесь для программирования (прошивки) микроконтроллера. Смотрите доку на утилиту в части поддерживаемых ей форматов входных файлов и делайте выводы... Одно могу сказать точно, что форматы с одним линейным адресным пространством вряд ли могут быть использованы для программирования сразу двух независимых типов памяти AVR ввиду их наложения. прошиваю я через Atmel Studio 6.2. В закладке Memories (Menu -> Tools -> Device Programming) указываю путь для elf файла и отдельно путь для eep файла. Встала задача для прошивки МК использовать только один файл (hex или elf). На форуме я видел что то похожее http://electronix.ru/forum/index.php?showt...73&hl=EEMEM . Там нужно что делать через линкеры, объектные файлы и тд. Но т.к у меня опыта еще маловато я не совсем понимаю о чем конкретно идет речь Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alexeyv 0 26 мая, 2015 Опубликовано 26 мая, 2015 (изменено) · Жалоба 1. На производстве используют программатор ASISP и ПО к нему. В нем можно создать проект в котором указывается файл для FLASH, файл для EEPROM, настройки FUSE/LOCK бит, проверку всего после прошивки и кое что еще по мелочи (типа запись счетчика в EEPROM - серийный номер платы). Этот проект настраивается один раз и сохраняется. Далее наладчику/настройщику остается нажать кнопку "Автопрограммирование" один раз для каждой платы. 2. По поводу работы с EEPROM. В начале программы определяется чиста ли EEPROM. Если чиста - то вызывается функция начальной инициализации. Далее - обычная работа программы. Таким образом не надо создавать отдельного файла для прошивки EEPROM - код программы сам ее инициализирует при первом запуске программы. P.S. ASISP можно подключить в ввиде тулза к Atmel Studio и для программирования надо будет нажимать одну кнопку из Atmel Studio. Изменено 26 мая, 2015 пользователем alexeyv Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Twin_by 0 26 мая, 2015 Опубликовано 26 мая, 2015 (изменено) · Жалоба 2. По поводу работы с EEPROM. В начале программы определяется чиста ли EEPROM. Если чиста - то вызывается функция начальной инициализации. Далее - обычная работа программы. Таким образом не надо создавать отдельного файла для прошивки EEPROM - код программы сам ее инициализирует при первом запуске программы. Т.е вы предлагаете после начала функции main проверять пуста ли EEPROM. Если Да, то инициализировать переменную uint8_t var EEMEM = 15; Правильно я понимаю??? Вот сейчас попробовал инициализировать переменную после начала функции main. И как то безрезультатно, не дает мне этого сделать. Позволяет инициализировать только перед функцией main где инициализируются глобальные переменные. Изменено 26 мая, 2015 пользователем Twin_by Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
qwerty1023 0 26 мая, 2015 Опубликовано 26 мая, 2015 (изменено) · Жалоба Тут наверное имеется в виду что-то типа //_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мс Изменено 26 мая, 2015 пользователем IgorKossak [codebox] для длинного кода, [code] - для короткого! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alexeyv 0 26 мая, 2015 Опубликовано 26 мая, 2015 (изменено) · Жалоба Выбираешь один из неиспользуемых адресов в 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); Изменено 26 мая, 2015 пользователем alexeyv Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Twin_by 0 28 мая, 2015 Опубликовано 28 мая, 2015 · Жалоба Например: #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 (для автоматического присвоения адреса) не получится Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alexeyv 0 29 мая, 2015 Опубликовано 29 мая, 2015 · Жалоба Если я правильно понял ваш код, то вы в нем сами присваиваете адрес ячейки в 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 МК входил в ступор (его победили, но привычка осталась) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 29 мая, 2015 Опубликовано 29 мая, 2015 · Жалоба 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. Урок окончен))) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
qwerty1023 0 29 мая, 2015 Опубликовано 29 мая, 2015 · Жалоба Задаёте значения своим переменным: EEMEM eeprom_data_t eeprom = { .var1 = 33U, .var2 = 333.0f } Урок окончен))) А в какой момент и как это происходит? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 29 мая, 2015 Опубликовано 29 мая, 2015 · Жалоба А в какой момент и как это происходит?После сборки проекта вы получаете секцию с ЕЕПРОМ переменными в elf файле, после чего имеется возможность экспортировать эту секцию в eeprom-hex файл, а данные секции .text и иже с ним в flash-hex файл. Потом программатором зашиваете эти оба файла в микроконтроллер. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Twin_by 0 29 мая, 2015 Опубликовано 29 мая, 2015 (изменено) · Жалоба После сборки проекта вы получаете секцию с ЕЕПРОМ переменными в elf файле, после чего имеется возможность экспортировать эту секцию в eeprom-hex файл, а данные секции .text и иже с ним в flash-hex файл. Потом программатором зашиваете эти оба файла в микроконтроллер. Т.е все равно нужно использовать два файла для прошивки eeprom и flash? Изменено 29 мая, 2015 пользователем Twin_by Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 0 29 мая, 2015 Опубликовано 29 мая, 2015 · Жалоба 1) Все данные ЕЕPROМ в структуру, это святое и не обсуждаемо. 2) Такм-же в структуре сигнатура размером в несколько байт. 3) При запуске проверка сигнатуры, если ее нет, то инициализация данных значениями по умолчанию и пофиг, это первый запуск или содержимое слетело. Сигнатуру можно менять и при изменениии версии софта требующей других начальных установок или расширения данных. Такой поход к делу позволяет так-же не заморчиваться содержимым EEPROМ и при внутрисхемном программировании. Все. И никаких инициализаций EEPROM при программировании по причине нахренненужности. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VladislavS 29 31 мая, 2015 Опубликовано 31 мая, 2015 · Жалоба Все. И никаких инициализаций EEPROM при программировании по причине нахренненужности. Аналогично всегда делаю. Можно, конечно, придумать случай когда нет места для кода инициализации EEPROM, но мне такого не встречалось. И если мало переменных в EEPROM, то предпочитаю вместо сигнатуры сами данные на корректность проверять. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться