|
|
  |
STM32 flash, помогите разобраться |
|
|
|
Jul 1 2014, 10:22
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(ViKo @ Jul 1 2014, 14:18)  Как бы тогда перекинуть функцию записи в ОЗУ, и выполнить? Вот так, к примеру: Код static const uint16_t jump2fw[] = { 0xF850, 0xDB04, /* LDR.W SP, [R0], #4 */ 0x6800, /* LDR.W R0, [R0] */ 0x4700, /* BX R0 */ }; ... ((void (*)(int*))(1 + (int)jump2fw))(&fw_start); Самый переносимый способ. Функцию можно сделать очень компактной, так что особого напряга быть не должно.
|
|
|
|
|
Jul 1 2014, 11:06
|

Знающий
   
Группа: Участник
Сообщений: 974
Регистрация: 4-04-08
Из: далека
Пользователь №: 36 467

|
Цитата(ViKo @ Jul 1 2014, 06:18)  Как бы тогда перекинуть функцию записи в ОЗУ, и выполнить? Или пользоватся встроенным бутлоадером, или сделать свой. Основную программу разместить по другому аддрессу. Тогда и внешняя РАМ не надо
--------------------
Верить нельзя никому, даже себе. Мне - можно.
|
|
|
|
|
Jul 1 2014, 11:07
|

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

|
Цитата(scifi @ Jul 1 2014, 13:22)  Самый переносимый способ. Функцию можно сделать очень компактной, так что особого напряга быть не должно. Но не самый "прямой". Код __attribute__(("section"(".ramfunc"))) void somefunc() { ......
}
*.ld: ...... .data : { . = ALIGN(4); _sdata = .; /* start of .data label */ *(.ramfunc) *(.ramfunc.*) *(.data) *(.data.*) . = ALIGN(4); _edata = .; /* end of .data label */ } > RAM AT > TEXT _sidata = LOADADDR(.data); /* start of initialized data label */ И все. Тело функции будет скопировано перед запуском main() заодно с инициализированными данными (как и ваше, кстати), но обращаться к ней можно напрямую - линкер при обращении к этой функции будет подставлять правильный адрес в ОЗУ, и не нужно писать эту функцию в машинных кодах. Для других компиляторов можно сделать аналогично. Но сколько работаю с разными Cortex, пока что ни разу функция в ОЗУ не потребовалась.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jul 1 2014, 11:15
|

Знающий
   
Группа: Участник
Сообщений: 974
Регистрация: 4-04-08
Из: далека
Пользователь №: 36 467

|
Цитата(ViKo @ Jul 1 2014, 07:13)  Да, можно разместить "прошивальщик" в конце flash, например. И не трогать этот сектор никогда. Нет, прошивальщик должен всегда стартовать по нулевому аддрессу, с рестарта. Иначе смысл теряется. А вот программа может быть где угодно
--------------------
Верить нельзя никому, даже себе. Мне - можно.
|
|
|
|
|
Jul 1 2014, 11:25
|

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

|
Цитата(ViKo @ Jul 1 2014, 14:18)  По нулевому адресу расположена таблица startup. Таблица векторов прошивальщика. Приложение со своей собственной таблицей может располагаться где угодно. При старте запускается прошивальщик, он проверяет целостность приложения, переключает VTOR на вектора приложения (для Cortex-M0 копирует вектора приложения в ОЗУ и делает ремап), грузит указатель стека из векторов приложения и передает управление на вектор Reset приложения. Приложение может отсутствовать вообще (или быть испорченным, недозаписанным), в этом случае прошивальщик весело мигая светодиодом ожидает новую прошивку для приложения, записывает ее и делает рестарт. После рестарта прошивальщик проверяет целостность... (далее читать с начала).
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jul 1 2014, 11:34
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(Сергей Борщ @ Jul 1 2014, 14:25)  При старте запускается прошивальщик, он проверяет целостность приложения, переключает VTOR на вектора приложения (для Cortex-M0 копирует вектора приложения в ОЗУ и делает ремап), грузит указатель стека из векторов приложения и передает управление на вектор Reset приложения. А если приложение целое, но хочу зашить новую прошивку? Чем подтолкнуть? А целостность как определить - CRC посчитать? А размеры кода откуда узнать, хранить во flash, рядом с CRC? В конце flash сектора большие, по 128 KB (речь идет про STM32F20x). Значит, загрузчик надо расположить в начальных секторах, или в OTP (страшно!).
|
|
|
|
|
Jul 1 2014, 11:48
|

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

|
Цитата(ViKo @ Jul 1 2014, 14:34)  А если приложение целое, но хочу зашить новую прошивку? Чем подтолкнуть? Я делаю программный сброс из приложения. А загрузчик после обновления делает сброс по собаке. При старте загрузчика проверяю источник сброса и если он программный - ухожу на обновление, если нет - проверяю целостность и запускаю приложение. Цитата(ViKo @ Jul 1 2014, 14:34)  А целостность как определить - CRC посчитать? Да, тем более что у STM32 есть и аппаратный расчет CRC и DMA. Цитата(ViKo @ Jul 1 2014, 14:34)  А размеры кода откуда узнать, хранить во flash, рядом с CRC? Я размер храню сразу после области векторов приложения. У меня его туда линкет прописывает: Код .text : { _image_start = .; KEEP(*(.isr_vector))
LONG((_image_end - _image_start) / 4); /* application size, in 4-byte words */ .................... } > TEXT
.data : { . = ALIGN(4); _sdata = .; /* start of .data label */ *(.ramfunc) *(.ramfunc.*) *(.data) *(.data.*) . = ALIGN(4); _edata = .; /* end of .data label */ } > RAM AT > TEXT _sidata = LOADADDR(.data); /* start of initialized data label */
.crc : { . = . + 4; /* reserve space for CRC */ _image_end = .; } > TEXT Цитата(ViKo @ Jul 1 2014, 14:34)  Значит, загрузчик надо расположить в начальных секторах, или в OTP (страшно!). Разумеется в начальных секторах. Чтобы всегда, после заливки чего угодно он всегда стартовал первым и имел возможность залить другое приложения. Я предусматриваю одну из свободных ног для принудительного запуска загрузчика - если залито приложение, которое хотя и целое, но тем не менее нерабочее, то сняв питание, закоротив эту ногу и подав питание снова, я из кирпича получаю готовое к обновлению устройство.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jul 1 2014, 12:22
|

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

|
Цитата(ViKo @ Jul 1 2014, 15:15)  В секторе 0 расположить загрузчик, основную программу начать с сектора 1. Именно. Цитата(ViKo @ Jul 1 2014, 15:15)  А таблицей векторов нельзя ли одной обойтись? Запретить все прерывания при загрузке, и шабаш? Не вижу смысла. Вектора приложения все равно каким-то образом должны попасть на свое место - или через VTOR или через ремап. При этом содержимое векторов загрузчика никакой роли уже не имеет. Никаких плюсов от неиспользования прерываний в загрузчике нет.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jul 1 2014, 13:16
|
Профессионал
    
Группа: Свой
Сообщений: 1 404
Регистрация: 11-03-11
Из: Минск, Беларусь
Пользователь №: 63 539

|
Цитата(Сергей Борщ @ Jul 1 2014, 14:48)  Я предусматриваю одну из свободных ног для принудительного запуска загрузчика - если залито приложение, которое хотя и целое, но тем не менее нерабочее, то сняв питание, закоротив эту ногу и подав питание снова, я из кирпича получаю готовое к обновлению устройство. И вчём смысл такого решения, если всё равно необходимо будет разобрать всё устройство (что порой бывает не просто), чтобы добраться до платы с процессором. Там уже что ножку коротить, что программатор подключить, особой разницы нету.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|