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

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


Участник
*

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



Добрый день.

Имеется:
Некий контроллер STM32F4XX (применительно к задаче не важно какой именно)
IDE Keil uVision
Программатор J-Link (мне кажется он тут ни к чему, но всеже)
Некоторая программа.
Некоторый набор двоичных данных.

Сосбтвенно что я хочу:
Я использую встроенную нанду для хранения настроек и хочу чтобы при программировании контроллера в него сразу, вместе с программой, зашивались настройки по-умолчанию. (читать и писать программа умеет, но надо чтобы вместо стандартных 0xff в нужной области памяти "изначально" были какие-то определенные значения)
Я предполагаю что мне надо как-то получить на выходе из программы такой hex, чтобы после программирования им контроллера, помимо собственно программы, в жестко заданной области памяти, был тот самый "набор двоичных данных".

Есть мысли как это сделать?

Сообщение отредактировал RiseOfDeath - Oct 19 2015, 13:02
Go to the top of the page
 
+Quote Post
2 страниц V   1 2 >  
Start new topic
Ответов (1 - 22)
RadiatoR
сообщение Oct 19 2015, 13:08
Сообщение #2


Местный
***

Группа: Свой
Сообщений: 270
Регистрация: 8-08-15
Из: Москва
Пользователь №: 87 901



Если взглянуть на стартап.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

Поправьте если есть более простые варики

Сообщение отредактировал ЯadiatoR - Oct 19 2015, 13:09
Go to the top of the page
 
+Quote Post
zltigo
сообщение Oct 19 2015, 13:13
Сообщение #3


Гуру
******

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



QUOTE (ЯadiatoR @ Oct 19 2015, 16:08) *
Поправьте если есть более простые варики

квалификатор __at


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
scifi
сообщение Oct 19 2015, 13:24
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(RiseOfDeath @ Oct 19 2015, 16:00) *
Я использую встроенную нанду для хранения настроек и хочу чтобы при программировании контроллера в него сразу, вместе с программой, зашивались настройки по-умолчанию. (читать и писать программа умеет, но надо чтобы вместо стандартных 0xff в нужной области памяти "изначально" были какие-то определенные значения)

Очень может быть, что проще и практичнее будет, если прошивка сама при первом запуске зашьёт туда то, что нужно.
Go to the top of the page
 
+Quote Post
RadiatoR
сообщение Oct 19 2015, 13:24
Сообщение #5


Местный
***

Группа: Свой
Сообщений: 270
Регистрация: 8-08-15
Из: Москва
Пользователь №: 87 901



загуглил, проверил:
int var __at(0x80001000) = 20;
не компилит.
ps так заработало:
int variable1 __attribute__((at(0x8000))) = 10;

Сообщение отредактировал ЯadiatoR - Oct 19 2015, 13:27
Go to the top of the page
 
+Quote Post
RiseOfDeath
сообщение Oct 19 2015, 13:25
Сообщение #6


Участник
*

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



А как им пользоваться?
Go to the top of the page
 
+Quote Post
zltigo
сообщение Oct 19 2015, 13:32
Сообщение #7


Гуру
******

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



QUOTE (ЯadiatoR @ Oct 19 2015, 16:24) *
загуглил, проверил:
int var __at(0x80001000) = 20;
не компилит.
ps так заработало:
int variable1 __attribute__((at(0x8000))) = 10;

квалификатор const для flash забыли


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
RiseOfDeath
сообщение Oct 19 2015, 13:37
Сообщение #8


Участник
*

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



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



Быть может вы и правы. Сложно сказать.
Go to the top of the page
 
+Quote Post
smalcom
сообщение Oct 19 2015, 13:38
Сообщение #9


Профессионал
*****

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



я обычно по-умолчанию не зашиваю, т.к. программа сам должна знать, что там у неё надо сделать. а при запуске проверяю контрольную сумму: не совпала - сохраняем настройки по-умолчанию.
Go to the top of the page
 
+Quote Post
RadiatoR
сообщение Oct 19 2015, 13:47
Сообщение #10


Местный
***

Группа: Свой
Сообщений: 270
Регистрация: 8-08-15
Из: Москва
Пользователь №: 87 901



Цитата(zltigo @ Oct 19 2015, 16:32) *
квалификатор const для flash забыли

а где его писать? да и нужно ли? у меня скомпилилось, парвда я не проверял на деле
Go to the top of the page
 
+Quote Post
zltigo
сообщение Oct 19 2015, 13:55
Сообщение #11


Гуру
******

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



QUOTE (ЯadiatoR @ Oct 19 2015, 16:47) *
а где его писать?

Дивный вопрос. Как Вам, удалось ни разу не воспользоваться ни одним из квалификаторов?
Квалификаторы указываются рядом с типом переменной.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
RadiatoR
сообщение Oct 19 2015, 13:56
Сообщение #12


Местный
***

Группа: Свой
Сообщений: 270
Регистрация: 8-08-15
Из: Москва
Пользователь №: 87 901



Цитата(zltigo @ Oct 19 2015, 16:55) *
Дивный вопрос. Как Вам, удалось ни разу не воспользоваться ни одним из квалификаторов?
Квалификаторы указываются рядом с типом переменной.

ой =) вы про это. Я даже не сразу понял о чем идет речь, а const как-то вообще пропустил сквозь текст.
Go to the top of the page
 
+Quote Post
RiseOfDeath
сообщение Oct 21 2015, 08:42
Сообщение #13


Участник
*

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



Благодарю всех за помощь. Я решил, что лучше буду при запуске проверять в той памяти некий magik number и орентируясь на его отсутствие писать туда дефолтные настройких. Мне кажется это и проще и будет более очевидно для другогоразработчика, если ему придется иметь с моей прогой дело.
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Oct 21 2015, 09:12
Сообщение #14


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



Хорошим тоном является проверять
1. пустоту сектора - обычно есть прям такая команда ну или просто смотреть что там FFFFF
2. контрольную сумму настроек, что если вы их изменяли, а вам дернули питание и настройки на половину не верны

3. В особых случаях добавляют признак актуальности, то есть делают 2-3 копии настроек,в начале и конце стоит номер, если он в начале и конце совпадает - значит блок настроек полный, а по номеру определяют последние актуальные. Это позволяет если у вас во время изменения настройки померли, иметь рабочий прошлый вариант. Ну или загрузить прошлые настройки если надо
Go to the top of the page
 
+Quote Post
stas00n
сообщение Oct 21 2015, 10:23
Сообщение #15


Частый гость
**

Группа: Участник
Сообщений: 181
Регистрация: 26-11-10
Пользователь №: 61 198



Цитата(RiseOfDeath @ Oct 19 2015, 15:00) *
Я предполагаю что мне надо как-то получить на выходе из программы такой hex, чтобы после программирования им контроллера, помимо собственно программы, в жестко заданной области памяти, был тот самый "набор двоичных данных".

Есть мысли как это сделать?


Лично я в подобной ситуации поступил весьма тупо в лоб. Потребуется STSW-LINK004STM32 ST-LINK utility
1. Заливаем .hex с кодом (без пользовательских настроек).
2. Настраиваем прибор, сохраняем настройки.
3. Читаем флеш полностью (вместе с настройками).
4. Сохраняем новый .hex
Go to the top of the page
 
+Quote Post
RiseOfDeath
сообщение Oct 23 2015, 11:35
Сообщение #16


Участник
*

Группа: Участник
Сообщений: 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 utility
1. Заливаем .hex с кодом (без пользовательских настроек).
2. Настраиваем прибор, сохраняем настройки.
3. Читаем флеш полностью (вместе с настройками).
4. Сохраняем новый .hex


Тут слишком много "лишних" действий, как мне кажется. Хотя ваш способ имеет право на существование.

Сообщение отредактировал RiseOfDeath - Oct 23 2015, 11:36
Go to the top of the page
 
+Quote Post
Sanya_kv
сообщение Oct 27 2015, 05:34
Сообщение #17


Частый гость
**

Группа: Свой
Сообщений: 185
Регистрация: 25-02-09
Из: Россия
Пользователь №: 45 369



В Keil пользуюсь данным способом:
const char имя_переменной_типа_char [32] __attribute__((at(0x20000))) = { "Определяем её значение" };
0x20000 - адрес, где она будет располагаться.
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Oct 27 2015, 14:20
Сообщение #18


Знающий
****

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


Гуру
******

Группа: Свой
Сообщений: 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;

Иначе компилятор не догадается, что эта переменная может меняться.
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Oct 27 2015, 15:15
Сообщение #20


Знающий
****

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


Гуру
******

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



QUOTE (KnightIgor @ Oct 27 2015, 18:15) *
Мне просто интересно, а в чем разница в результирующем коде?

Разница или будет, или нет. Если не будет, то как-бы "все хорошо", если будет, то будут глюки. Даже если сейчас "все хорошо", то при изменении исходника все может поменяться. Если Вам глюки НЕ нужны, то объясняйте компилятору все максимально четко используя volatile, если нет абсолютной уверенности в том, что содержимое конфигурации не будет меняться, например, без перезагрузки программы.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Oct 27 2015, 18:21
Сообщение #22


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Да и перезагрузка не спасет. gcc очень хорошо умеет подставлять значения констант из константных переменных (и даже из полей структур) прямо в код. И сколько потом ни перегружай программу, некторые части ее могут продолжать рабоать с теми значениями, которые были в момент компиляции. Мы ведь хотели быструю и маленькую программу? Компилятор пошел нам навстречу.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Oct 28 2015, 10:12
Сообщение #23


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(Сергей Борщ @ Oct 27 2015, 19:21) *
Да и перезагрузка не спасет. gcc очень хорошо умеет подставлять значения констант из константных переменных (и даже из полей структур) прямо в код.

Подтверждаю. И не только gcc, но и armcc KEIL. Ушло, когда такие изменяемые конфигурационные константы собрались в одну кучу в секции. Видимо, поэтому я не стал заморачиваться с volatile, поскольку свод в секцию (в одну область памяти только с данными, которую можно переписывать) изменяемых констант - крутая фразочка вышла cool.gif - с помощью присвоения атрибутов просто неизбежен и необходим при решении поставленно задачи и пресёк одновременно 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
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 22nd July 2025 - 21:12
Рейтинг@Mail.ru


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