|
Как в "незанятой" области FLASH-памяти контроллера сделать определенные значение |
|
|
|
Oct 19 2015, 13:00
|
Участник

Группа: Участник
Сообщений: 48
Регистрация: 2-10-13
Пользователь №: 78 579

|
Добрый день.
Имеется: Некий контроллер STM32F4XX (применительно к задаче не важно какой именно) IDE Keil uVision Программатор J-Link (мне кажется он тут ни к чему, но всеже) Некоторая программа. Некоторый набор двоичных данных.
Сосбтвенно что я хочу: Я использую встроенную нанду для хранения настроек и хочу чтобы при программировании контроллера в него сразу, вместе с программой, зашивались настройки по-умолчанию. (читать и писать программа умеет, но надо чтобы вместо стандартных 0xff в нужной области памяти "изначально" были какие-то определенные значения) Я предполагаю что мне надо как-то получить на выходе из программы такой hex, чтобы после программирования им контроллера, помимо собственно программы, в жестко заданной области памяти, был тот самый "набор двоичных данных".
Есть мысли как это сделать?
Сообщение отредактировал RiseOfDeath - Oct 19 2015, 13:02
|
|
|
|
2 страниц
1 2 >
|
 |
Ответов
(1 - 22)
|
Oct 19 2015, 13:25
|
Участник

Группа: Участник
Сообщений: 48
Регистрация: 2-10-13
Пользователь №: 78 579

|
Цитата(ЯadiatoR @ Oct 19 2015, 16:08)  Если взглянуть на стартап.s то можно увидеть записи типа: Stack_Size EQU 0x00000400
AREA STACK, NOINIT, READWRITE, ALIGN=3 Stack_Mem SPACE Stack_Size
Здесь в качестве STACK идет указатель на область стэка и далее выделяется его размер, равный 0x400 После этого командой DCD можно записать значения в ячейки памяти, так же как это делается с векторной таблицей:
__Vectors . . . DCD NMI_Handler ; NMI Handler DCD HardFault_Handler ; Hard Fault Handler DCD 0 ; Reserved DCD 0 ; Reserved
Поправьте если есть более простые варики Т.е. типа такого вот: Код Stack_Size EQU 0x00000400
AREA STACK, NOINIT, READWRITE, ALIGN=3 Stack_Mem SPACE Stack_Size __initial_sp
EQU 0x0x080E0000 DCD 0xDE DCD 0xAD DCD 0xBE DCD 0xEF Цитата(zltigo @ Oct 19 2015, 16:13)  квалификатор __at А как им пользоваться?
|
|
|
|
|
Oct 19 2015, 13:37
|
Участник

Группа: Участник
Сообщений: 48
Регистрация: 2-10-13
Пользователь №: 78 579

|
Цитата(scifi @ Oct 19 2015, 16:24)  Очень может быть, что проще и практичнее будет, если прошивка сама при первом запуске зашьёт туда то, что нужно. Быть может вы и правы. Сложно сказать.
|
|
|
|
|
Oct 19 2015, 13:38
|

Профессионал
    
Группа: Свой
Сообщений: 1 292
Регистрация: 26-06-07
Пользователь №: 28 718

|
в скрипт линковщика добавляете свою секцию Цитата __exidx_end = .;
.flash_var : ALIGN (1024) /* очень важно не прогадать с выравниванием, а то будете затирать программу */ { *(.flash_var*) . = ALIGN (1024); *(.flash_var_end*) } > ROM
__etext = .; затем задаёте в какой секции располагается нужкая переменная(структура) Код static uint8_t __attribute__ ((section(".flash_var"))) mConfigDataFlashArray[sizeof(SConfigData_Internal)]; я обычно по-умолчанию не зашиваю, т.к. программа сам должна знать, что там у неё надо сделать. а при запуске проверяю контрольную сумму: не совпала - сохраняем настройки по-умолчанию.
|
|
|
|
|
Oct 21 2015, 08:42
|
Участник

Группа: Участник
Сообщений: 48
Регистрация: 2-10-13
Пользователь №: 78 579

|
Благодарю всех за помощь. Я решил, что лучше буду при запуске проверять в той памяти некий magik number и орентируясь на его отсутствие писать туда дефолтные настройких. Мне кажется это и проще и будет более очевидно для другогоразработчика, если ему придется иметь с моей прогой дело.
|
|
|
|
|
Oct 21 2015, 10:23
|
Частый гость
 
Группа: Участник
Сообщений: 181
Регистрация: 26-11-10
Пользователь №: 61 198

|
Цитата(RiseOfDeath @ Oct 19 2015, 15:00)  Я предполагаю что мне надо как-то получить на выходе из программы такой hex, чтобы после программирования им контроллера, помимо собственно программы, в жестко заданной области памяти, был тот самый "набор двоичных данных".
Есть мысли как это сделать? Лично я в подобной ситуации поступил весьма тупо в лоб. Потребуется STSW-LINK004STM32 ST-LINK utility1. Заливаем .hex с кодом (без пользовательских настроек). 2. Настраиваем прибор, сохраняем настройки. 3. Читаем флеш полностью (вместе с настройками). 4. Сохраняем новый .hex
|
|
|
|
|
Oct 23 2015, 11:35
|
Участник

Группа: Участник
Сообщений: 48
Регистрация: 2-10-13
Пользователь №: 78 579

|
Цитата(Golikov A. @ Oct 21 2015, 12:12)  Хорошим тоном является проверять 1. пустоту сектора - обычно есть прям такая команда ну или просто смотреть что там FFFFF 2. контрольную сумму настроек, что если вы их изменяли, а вам дернули питание и настройки на половину не верны
3. В особых случаях добавляют признак актуальности, то есть делают 2-3 копии настроек,в начале и конце стоит номер, если он в начале и конце совпадает - значит блок настроек полный, а по номеру определяют последние актуальные. Это позволяет если у вас во время изменения настройки померли, иметь рабочий прошлый вариант. Ну или загрузить прошлые настройки если надо Спасибо за совет, хотя проверка валидности и актуальности настроек, это отдельный вопрос. Цитата(stas00n @ Oct 21 2015, 13:23)  Лично я в подобной ситуации поступил весьма тупо в лоб. Потребуется STSW-LINK004STM32 ST-LINK utility1. Заливаем .hex с кодом (без пользовательских настроек). 2. Настраиваем прибор, сохраняем настройки. 3. Читаем флеш полностью (вместе с настройками). 4. Сохраняем новый .hex Тут слишком много "лишних" действий, как мне кажется. Хотя ваш способ имеет право на существование.
Сообщение отредактировал RiseOfDeath - Oct 23 2015, 11:36
|
|
|
|
|
Oct 27 2015, 14:20
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(RiseOfDeath @ Oct 19 2015, 14:00)  Сосбтвенно что я хочу: Я использую встроенную нанду для хранения настроек и хочу чтобы при программировании контроллера в него сразу, вместе с программой, зашивались настройки по-умолчанию. (читать и писать программа умеет, но надо чтобы вместо стандартных 0xff в нужной области памяти "изначально" были какие-то определенные значения) Я предполагаю что мне надо как-то получить на выходе из программы такой hex, чтобы после программирования им контроллера, помимо собственно программы, в жестко заданной области памяти, был тот самый "набор двоичных данных". Мне кажется, Вашу задачу надо переформулировать так: в программе имеются константы настройки, которые необходимо менять в процессе работы. Эти константы есть часть кода, поэтому говорить о хранении настроек в области "свободной" памяти, как бы вне программы, неверно, т.к. настройки есть часть программного кода в рамках занимаемой памяти. В принципе, все достаточно просто: 1. Настройка - это есть константа во флэше, объявленная в рамках исходного кода, например: Код const float MyCoeff = 5.5; Очевидно, что 5.5 - это значение по-умолчанию, которое и будет " грузиться" во флэш вместе с программой во время записи/обновления кода. Вот Вам и зашивка настроек по-умолчанию. Также очевидно, что использование настройки в коде есть ни что иное как просто использование имени константы в выражениях. 2. Т.к. предполагается менять значение константы, ее нельзя смешивать с исполняемым кодом, а надо разместить где-то отдельно, чтобы безболезненно переписывать флэш и не завалить код. Это проистекает из принципа работы флэша с постраничными стираниями/записью. Для этого константу для начала надо поместить в известную секцию: Код const float MyCoeff __attribute__((section("MYSETTINGS"), used)) = 5.5; Так нужно поступить со всеми подобными константами-настройками. Компоновщик соберет затем все такие константы в одну секцию. 3. Теперь надо поработать ручками и модифицировать файл скаттера (скрипта компоновщика). Например, Код ; ************************************************************* ; *** Scatter-Loading Description File generated by uVision *** ; ************************************************************* ; ; Assume 64Flash ; LR_IROM1 0x08000000 0x00010000 { ; load region size_region ER_IROM1 0x08000000 0x00010000 {; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) } RW_IRAM1 0x20000000 0x00002000 {; RW data .ANY (+RW +ZI) } } ; ; In-flash rewritable params, size 1K, must be 1K aligned (page size of used CPU) ; LR_IROM3 (0x08000000 + (0x00010000-0x400)) 0x400 ; load region size_region { ER_IROM3 (0x08000000 + (0x00010000-0x400)) 0x400 ; load address = execution address { *(MYSETTINGS) } } Здесь дано указание компоновщику создать загружаемый регион LR_IROM3 размером в 1К (это размер страницы в STM32F051), а в нем - подрегион ER_IROM3, в котором и соберутся все настройки. Использована последняя страница флэша. Если посмотреть карту памяти готовой программы, можно разместить страницу настроек и непосредственно (но выровненно на страницу!) за "основным" кодом, указав нужные адреса, но лично мне последняя страница нравится больше. 4. Для модификации значений из кода программы надо, очевидно, прочитать всю страницу в буфер, модифицировать значение настройки в буфере по смещению и записать страницу назад по месту. Смещение будет ((int)&MyCoeff)%0x400. Базовый адрес всей страницы можно вычислить из любой настройки в странице как ((int)&MyCoeff)/0x400*0x400. Это все, конечно, при условии, что все настройки помещаются в одну страницу. Для объемных настроек, пересекающих границы страниц (структуры), нужны соответствующие многостраничные алгоритмы записи во флэш. Или можно выровнять все настройки так, чтобы они никогда не пересекали страницу. Есть еще интересная возможность у компоновщика генерировать константы, доступные в программе. Например, базовый адрес региона можно получить как (void *)&Load$$LR$$LR_IROM3$$Base, а длину региона как (int)&Load$$LR$$LR_IROM3$$Length. 5. Если на образ ELF "натравить" утилиту fromelf.exe как Код fromelf.exe --i32 myproject.axf --output myproject.hex то будет создан ПОДКАТАЛОГ myproject.hex, в котором появятся два файла с именами ER_IROM1 и ER_IROM3 и без расширений. На самом деле это *.HEX файлы. В файле ER_IROM3 собраны все настройки. 6. Внешняя программа, которая хочет модифицировать такой файл, должна, конечно, знать, по какому смещению какая переменная находится. Это нетривиальная задача, особенно по мере развития программы, версий, и т.п. Можно предложить путь дескрипторов или меток. Например, метки всегда четырехбуквенные: Код const char myLabel __attribute__((section("MYSETTINGS"), used)) = "MYCO"; const float MyCoeff __attribute__((section("MYSETTINGS"), used)) = 5.5; Внешняя программа может найти строку MYCO и знать, что после нее идет MyCoeff.
Сообщение отредактировал KnightIgor - Oct 27 2015, 14:27
|
|
|
|
|
Oct 27 2015, 14:33
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(KnightIgor @ Oct 27 2015, 17:20)  1. Настройка - это есть константа во флэше, объявленная в рамках исходного кода, например: Код const float MyCoeff = 5.5; Очевидно, что 5.5 - это значение по-умолчанию, которое и будет " грузиться" во флэш вместе с программой во время записи/обновления кода. Вот Вам и зашивка настроек по-умолчанию. Также очевидно, что использование настройки в коде есть ни что иное как просто использование имени константы в выражениях. Тогда уж так: Код const volatile float MyCoeff = 5.5; Иначе компилятор не догадается, что эта переменная может меняться.
|
|
|
|
|
Oct 27 2015, 15:15
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(scifi @ Oct 27 2015, 15:33)  Тогда уж так: Код const volatile float MyCoeff = 5.5; Иначе компилятор не догадается, что эта переменная может меняться. Когда и если значение поменяется, компилятор будет уже далеко-далеко. P.S. Мне просто интересно, а в чем разница в результирующем коде?
Сообщение отредактировал KnightIgor - Oct 27 2015, 15:18
|
|
|
|
|
Oct 27 2015, 17:48
|

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

|
QUOTE (KnightIgor @ Oct 27 2015, 18:15)  Мне просто интересно, а в чем разница в результирующем коде? Разница или будет, или нет. Если не будет, то как-бы "все хорошо", если будет, то будут глюки. Даже если сейчас "все хорошо", то при изменении исходника все может поменяться. Если Вам глюки НЕ нужны, то объясняйте компилятору все максимально четко используя volatile, если нет абсолютной уверенности в том, что содержимое конфигурации не будет меняться, например, без перезагрузки программы.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Oct 28 2015, 10:12
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(Сергей Борщ @ Oct 27 2015, 19:21)  Да и перезагрузка не спасет. gcc очень хорошо умеет подставлять значения констант из константных переменных (и даже из полей структур) прямо в код. Подтверждаю. И не только gcc, но и armcc KEIL. Ушло, когда такие изменяемые конфигурационные константы собрались в одну кучу в секции. Видимо, поэтому я не стал заморачиваться с volatile, поскольку свод в секцию (в одну область памяти только с данными, которую можно переписывать) изменяемых констант - крутая фразочка вышла  - с помощью присвоения атрибутов просто неизбежен и необходим при решении поставленно задачи и пресёк одновременно inline-стремление компилятора. Убедил меня scifi, что для строгости, ясности и безопасности стОит объявлять volatile. ПЫ.СЫ.: 1. Для теста добавил для одной такой "переменной константы" в проекте volatile. Собрал. Загрузил. Вылетел в hard fault из инициализации еще перед main. 2. Есть атрибут __attribute__((noinline)), который предотвращает использование значения константной переменной непосредственно как операнд инструкции ("прямо в коде" в терминах Сергей Борщ). Мой макрос, который размещает константные настройки, выглядит так: Код #define ATS(s) __attribute__((section(s), noinline, used)) Так что "забъю" я пока на volatile.
Сообщение отредактировал KnightIgor - Oct 28 2015, 15:55
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|