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

tathagata

Участник
  • Постов

    8
  • Зарегистрирован

  • Посещение

Репутация

0 Обычный

Посетители профиля

Блок последних пользователей отключён и не показывается другим пользователям.

  1. Эксперименты показали, что ARMCLANG (6.18 в моем случае) правильно размещает массив на Flash. В то время как ARMCC (5.06), на котором и строился проект, имеет такой неприятный баг. Выбор компилятора в моем случае осложняется тем, что при использовании миландровских библиотек ARMCLANG при сборке выдает много странных ошибок, которые я отношу на совесть разработчиков пакета драйверов для Milandr. Для экспериментов собирать пришлось, в качестве устройства выбрав в обоих случаях стандартный ARMCM0P (ARM Cortex M0 plus). Если кто-то подскажет рабочее решение для увы устаревшего ARMCC v5.06, буду очень признателен.
  2. MDR32F1QI. Программа использует калибровочную таблицу переменной длины, под которую отводится страница памяти во Flash-области. В выделенной под таблицу секции памяти необходимо проинициализировать нулевыми значениями переменную — текущую длину таблицы, а так же сами данные. Соответствующий участок C-кода выглядит так: // Максимальное количество записей в таблице #define MAX_TABLE_SIZE 500 // Структура записи в таблице typedef struct { uint32_t value; uint32_t corr; } record_t; // Текущее количество записей в таблице const volatile size_t table_sz __attribute__((section(".table"))) = 0; // Массив стуктур const volatile record_t table[MAX_TABLE_SIZE] __attribute__((section(".table"))) = { {0, 0} }; Далее привожу соответствующий scatter-файл: LR_IROM1 0x00000000 0x00012000 { ; load region size_region ER_IROM1 0x00000000 0x00010000 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) } RW_IRAM1 0x20000000 0x00008000 { ; RW data .ANY (+RW +ZI) } RW_IRAM2 0x20100000 0x00004000 { mdr32f9qx_eeprom.o eeprom.o (+RO) .ANY (+RW +ZI) } } } LR_IROM2 0x00013000 0x00001000 { ; load region size_region ER_IROM2 0x00013000 0x00001000 { ; * (.table) } } Компилирую и собираю (ARMCC 5.06), после чего с помощью objdump смотрю выходной файл. И здесь начинается волшебство: Содержимое раздела ER_IROM2: 13000 01ff01ff 01ff01ff 01ff01ff 01ff01ff ................ 13010 01ff01ff 01ff01ff 01ff01ff 01ff01b3 ................ Далее, пытаюсь уменьшить длину массива в объявлении (MAX_TABLE_SIZE = 20). И, о чудо! Содержимое раздела ER_IROM2: 13000 00000000 00000000 00000000 00000000 ................ 13010 00000000 00000000 00000000 00000000 ................ 13020 00000000 00000000 00000000 00000000 ................ 13030 00000000 00000000 00000000 00000000 ................ 13040 00000000 00000000 00000000 00000000 ................ 13050 00000000 00000000 00000000 00000000 ................ 13060 00000000 00000000 00000000 00000000 ................ 13070 00000000 00000000 00000000 00000000 ................ 13080 00000000 00000000 00000000 00000000 ................ 13090 00000000 00000000 00000000 00000000 ................ 130a0 00000000 .... Опытным путем обнаружил, что максимальное работающее значение MAX_TABLE_SIZE равно 36. Тогда и переменная, отвечающая за текущую длину массива, и сам массив аккуратно в зануленном виде появляются в соответствующей секции. Иначе — мусор, подобный тому, что выше. Например, при MAX_TABLE_SIZE = 37 соответствующая секция выглядит так (вообще одно значение): Содержимое раздела ER_IROM2: 13000 01ff012d ...- Помогите разобраться с этим "волшебством". Сразу скажу, что при использовании GCC и ld никаких проблем не возникает. Массив и переменная в аккурат инициализируются в том количестве, какое задано. А вот с Keil у меня засада. Но необходимо делать код рабочим под оба компилятора. Есть, конечно, еще workaround: массив ведь можно заменить указателем относительно адреса переменной —- текущей его длины (что и было сделано в самом первоначальной версии), причем инициализация нулями его элементов необязательна — нулевая начальная длина (в соответствующей переменной) вполне достаточна для правильной работы программы. Но последующие считывание и запись в массив будут происходить тоже через смещения указателя относительно базового адреса переменной. Это, как мне кажется, не совсем удобно. Тем более, когда в GCC и ld все прекрасно работает. Посему в силу моего небольшого опыта прошу помочь разобраться с этой странной проблемой в Keil. Заранее спасибо за помощь.
  3. Первоначальная идея была в том, чтобы при прошивке инициализировать нужную страницу, заполнив ее нулями, а дальше по ходу работы программы эти данные могут быть изменены. В таком случае исключить эту страницу из скаттера нельзя, т. к. программа после запуска не знает о том, что она должна инициализировать эти данные. Для нее это просто сохраненные данные, которые она вычитывает из заданной страницы памяти. Вариант с CRC решает проблему принятия решения об инициализации данных уже со стороны программы (ну, и служит гарантией их целостности).
  4. Да, именно так я себе это и представил: с помощью CRC защищаю данные настроек, а также использую этот hack для их первоначальной инициализации. А в странице с ресурсом наработки "гашу" биты, не используя контрольные суммы.
  5. Что скажете о таком варианте? scatter.sct LR_IROM1 0x00000000 0x0001E000 { ; load region size_region ER_IROM1 0x00000000 0x0001E000 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) } RW_IRAM1 0x20000000 0x00008000 { ; RW data .ANY (+RW +ZI) } RW_IRAM2 0x20100000 0x00004000 { mdr32f9qx_eeprom.o RAMFunction.o (+RO) .ANY (+RW +ZI) } } LR_IROM2 0x0001E000 0x00002000 { ; отключаем LR_IROM2, если перепрошивка не должна затрагивать данные ER_IROM2 0x0001E000 0x00002000 { ; начало страницы инициализируется переменными из файла, остальное — 0xFF data_init.o (+RO) } } data_init.c const uint32_t data_array[3] __attribute__((used)) = {0x0, 0x0, 0x0}; data_init.h #ifndef DATA_INIT_H #define DATA_INIT_H extern const uint32_t data_init[3]; #endif // DATA_INIT_H Полностью согласен, что так идеологически правильнее. Кстати, это решило бы мою проблему с необходимостью инициализации нулями настроек при первой прошивке, поскольку 0xFFFFFF, считанные для всех переменных настроек не соответствовали бы CRC, так же равному 0xFFFFFF и тем самым запускали бы процесс принудительной инициализации значениями по-умолчанию (например, нулями в моем случае). Отличная мысль с CRC! Спасибо. В таком случае мой скаттер мог бы иметь такой вид: LR_IROM1 0x00000000 0x0001E000 { ; load region size_region ER_IROM1 0x00000000 0x0001E000 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) } RW_IRAM1 0x20000000 0x00008000 { ; RW data .ANY (+RW +ZI) } RW_IRAM2 0x20100000 0x00004000 { mdr32f9qx_eeprom.o RAMFunction.o (+RO) .ANY (+RW +ZI) } } LR_IROM2 0x0001E000 0x00002000 { ; отключаем LR_IROM2, если перепрошивка не должна затрагивать данные ER_IROM2 0x0001E000 0x00002000 { } } Поправьте меня, если я неправ.
  6. Для хранения настроек как раз и не рассматривается необходимости использования контрольной суммы — полагаемся на корректную работу флеша) Вопрос в том, как правильно в скаттере прописать эти две области по заданным адресам, одна из которых (вся страница) будет инициализирована нулями, а вторая (тоже размером в страницу) — единичками. Со второй понятно, что полное стирание памяти перед прошивкой заполняет не инициализируемые другим способом ячейки памяти единицами. Кстати, порядок страниц принципиальной роли не играет (можно 0x1F000 — для счетчика, а 0x1E000 — для настроек, а можно и наоборот). Этот момент обсуждается. Разумеется, что правильно было бы отделить мух от котлет. Но тогда придется работать двумя скаттерами (один — для первоначальной прошивки с инициализацией областей хранения данных, а другой — для дальнейших возможных перепрошивок (с сохранением этих самых значений). Я правильно понял? Сейчас интересно хоть какое-то решение.
  7. На этом и основан наш алгоритм подсчета ресурса — я же выше указывал. Эту страницу достаточно просто стереть (заполнить единицами), а потом "гасить" очередные единички, не стирая всю страницу (т. е. без перезаписи). Так что в этом наши с вами подходы схожи.
  8. МК — MDR32F1QI. Необходимо в EEPROM особым образом подготовить две области: Страница (0x1F000) для счетчика ресурсов. При разметке должна быть инициализирована единицами, что в принципе уже делает Erase Full Chip. Страница (0x1E000) для хранения нескольких настроек. При разметке должна быть инициализирована нулями. Счетчик ресурсов работает по принципу ежеминутного обнуления очередного бита выделенной страницы — для этого и необходимо ее инициализировать единицами. Доступ к значениям настроек сейчас сделан так: #define ADDR_SETTINGS 0x0001E000 int32_t dat1_ __attribute__((at(ADDR_SETTINGS))); int32_t dat2_ __attribute__((at(ADDR_SETTINGS + 4))); uint32_t dat3_ __attribute__((at(ADDR_SETTINGS + 8))); // Переменые, хранящие эти значение в ходе работы программы. int32_t dat1; int32_t dat2; uint32_t dat3; // Считываение значений переменных из EEPROM при старте программы. void read_settings() { dat1 = dat1_; dat2 = dat2_; dat1 = dat3_; } // Запись измененных значений переменных в EEPROM void update_settings() { __disable_irq(); EEPROM_ErasePage(ADDR_SETTINGS, EEPROM_Main_Bank_Select); EEPROM_ProgramWord(&dat1_, EEPROM_Main_Bank_Select, dat1); EEPROM_ProgramWord(&dat2_, EEPROM_Main_Bank_Select, dat2); EEPROM_ProgramWord(&dat3_, EEPROM_Main_Bank_Select, dat3); // Или записать можно и так, наверное: // EEPROM_ProgramWord(ADDR_SETTINGS, EEPROM_Main_Bank_Select, dat1); // EEPROM_ProgramWord(ADDR_SETTINGS + 4, EEPROM_Main_Bank_Select, dat2); // EEPROM_ProgramWord(ADDR_SETTINGS + 8, EEPROM_Main_Bank_Select, dat3); __enable_irq(); } Ну, а с записью счетчика наработки все аналогично. С той лишь разницей, что при загрузке вычитывается последнее ненулевое слово из соответствующей страницы и по вычесленному адресу пишется измененное значение. Вопрос в том, как в скаттере описать эти две страницы в EEPROM. Сразу скажу, что при перепрошивке МК нет необходимости сохранять старые настройки и наработку (подобная ситуация часто поднимается в обсуждениях) — нужно лишь их нужным образом инициализировать (нулями и единицами соответственно). Сейчас скаттер имеет такой вид: ; ************************************************************* ; *** Scatter-Loading Description File generated by uVision *** ; ************************************************************* LR_IROM1 0x00000000 0x00020000 { ; load region size_region ER_IROM1 0x00000000 0x00020000 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) } RW_IRAM1 0x20000000 0x00008000 { ; RW data .ANY (+RW +ZI) } RW_IRAM2 0x20100000 0x00004000 { mdr32f9qx_eeprom.o RAMFunction.o (+RO) .ANY (+RW +ZI) } } Подскажите, как его изменить, чтобы указанные страницы при прошивке были инициализированы правильным образом? А также интересует мнение, правильно ли я выбрал подход к доступу к настройкам. Они меняются крайне редко. А при первом запуске (после прошивки) должны вычитываться нулевые значения. При включении устройства EEPROM сразу переводится в программный режим.
×
×
  • Создать...