Pull to refresh

Comments 25

Прошивка для чего ?

Прошивка MBR нужна того лишь для того, чтобы запустить другую прошивку, которая прописана где-то по другому адресу в физической памяти микроконтроллера.

Это загрузчик.

А если MBR потребует вывода статуса в UART CLI, как это уместить в данный размер памяти? Или как понять, что процесс многоступенчатой загрузки проходит успешно?

 как понять, что процесс многоступенчатой загрузки проходит успешно?

На каждом этапе выставлять на наборе из N GPIO бинарные коды.
Процесс контролировать логическим анализатором.

Проинитить уарт и выплевывать в него байты этапов загрузки начиная с 0x30, не забывая проверять окончание передачи предыдущего байта

А что за код был, который 25 кбайт занял? Тот, что на основе HAL. Там какие флаги применялись?

А что за код был, который 25 кбайт занял?

Вот эта сборка
https://github.com/aabzel/trunk/tree/main/source/projects/jz_f407vet6_mbr_gcc_m

Там какие флаги применялись?

Компилятору были переданы ключи

-c -MD -MD
-ffreestanding -ffunction-sections -fdata-sections -fno-common -fno-printf-return-value -Werror=shadow -fshort-enums -fomit-frame-pointer -Werror=return-local-addr -Werror=implicit-function-declaration -Wno-nonnull-compare -Wall -fdce -fdse -Werror=address-of-packed-member -Werror=missing-field-initializers -Werror=unused-but-set-variable -Werror=unused-variable -g3 -Wall -ffunction-sections -fdata-sections -fshort-enums -fomit-frame-pointer -fno-move-loop-invariants -fdce -fdse -fmax-errors=70 -fmessage-length=0 -fsigned-char -fno-common -fstack-usage -fzero-initialized-in-bss -finline-small-functions -finline-functions -g3 -Werror=all -Werror=extra -Werror=clobbered -Werror=empty-body -Werror=missing-parameter-type -Werror=missing-field-initializers -Werror=old-style-declaration -Werror=override-init -Werror=strict-overflow=1 -Werror=type-limits -Werror=uninitialized -Werror=unused-but-set-parameter -Werror=pointer-to-int-cast -Werror=int-to-pointer-cast -Werror=switch-default -Werror=init-self -Werror=logical-not-parentheses -Werror=memset-transposed-args -Werror=misleading-indentation -Werror=parentheses -Werror=return-type -Werror=sign-compare -Werror=sequence-point -Werror=uninitialized -Werror=unused-function -Werror=unused-variable -Werror=sizeof-pointer-memaccess -Werror=strict-aliasing -Werror=switch -Werror=tautological-compare -Werror=trigraphs -Werror=array-bounds=1 -Werror=address -Werror=bool-compare -Werror=char-subscripts -Werror=comment -Werror=duplicated-cond -Werror=enum-compare -Werror=logical-op -Werror=return-local-addr -Werror=implicit-function-declaration -Werror=div-by-zero -Werror=duplicated-cond -Werror=enum-compare -Werror=empty-body -Werror=unused-but-set-variable -Werror=logical-op -Werror=implicit-int -Werror=incompatible-pointer-types -Werror=maybe-uninitialized -Werror=missing-parameter-type -Werror=overflow -Werror=pointer-sign -Werror=shift-count-overflow -Werror=unused-but-set-variable -Werror=incompatible-pointer-types -Werror=missing-parameter-type -Werror=old-style-declaration -Werror=pointer-sign -Werror=shift-count-overflow -Werror=shift-negative-value -Werror=missing-braces -Werror=unused-but-set-variable -Werror=unused-function -Werror=unused-value -Werror=pointer-arith -Werror=unused-but-set-variable -Werror=implicit-function-declaration -Werror=unused-but-set-variable -Werror=unused-variable -Werror=duplicate-decl-specifier -Werror=address-of-packed-member -Werror=sizeof-pointer-div -Werror=int-in-bool-context -Werror=bool-operation -Werror=memset-elt-size -Werror=multistatement-macros -Werror=ignored-qualifiers -Werror=float-equal -Werror=unused -Wno-nonnull-compare -Wno-stringop-truncation -Wno-format-truncation -Wno-restrict -Wno-format -Wno-redundant-decls -Wno-discarded-qualifiers -Wno-int-conversion -Wno-switch-bool -Wno-conversion -Wno-cpp -Wno-sign-compare -Wno-unused-parameter -Wno-implicit-fallthrough -Wno-restrict -Werror -mcpu=cortex-m4 -march=armv7e-m -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -O0 -std=c11 -MMD -MP -MF"build/system.d" -DHAS_ARM_GCC -Werror=all -Werror=extra -Werror=clobbered -Werror=empty-body -Werror=missing-parameter-type -Werror=missing-field-initializers -Werror=old-style-declaration -Werror=override-init -Werror=strict-overflow=1 -Werror=type-limits -Werror=uninitialized -Werror=unused-but-set-parameter -Werror=pointer-to-int-cast -Werror=int-to-pointer-cast -Werror=switch-default -Werror=init-self -Werror=logical-not-parentheses -Werror=memset-transposed-args -Werror=misleading-indentation -Werror=parentheses -Werror=return-type -Werror=sign-compare -Werror=sequence-point -Werror=uninitialized -Werror=unused-function -Werror=unused-variable -Werror=sizeof-pointer-memaccess -Werror=strict-aliasing -Werror=switch -Werror=tautological-compare -Werror=trigraphs -Werror=array-bounds=1 -Werror=address -Werror=bool-compare -Werror=char-subscripts -Werror=comment -Werror=duplicated-cond -Werror=enum-compare -Werror=logical-op -Werror=return-local-addr -Werror=implicit-function-declaration -Werror=div-by-zero -Werror=duplicated-cond -Werror=enum-compare -Werror=empty-body -Werror=unused-but-set-variable -Werror=logical-op -Werror=implicit-int -Werror=incompatible-pointer-types -Werror=maybe-uninitialized -Werror=missing-parameter-type -Werror=overflow -Werror=pointer-sign -Werror=shift-count-overflow -Werror=unused-but-set-variable -Werror=incompatible-pointer-types -Werror=missing-parameter-type -Werror=old-style-declaration -Werror=pointer-sign -Werror=shift-count-overflow -Werror=shift-negative-value -Werror=missing-braces -Werror=unused-but-set-variable -Werror=unused-function -Werror=unused-value -Werror=pointer-arith -Werror=unused-but-set-variable -Werror=implicit-function-declaration -Werror=unused-but-set-variable -Werror=unused-variable -Werror=duplicate-decl-specifier -Werror=address-of-packed-member -Werror=sizeof-pointer-div -Werror=int-in-bool-context -Werror=bool-operation -Werror=memset-elt-size -Werror=multistatement-macros -Werror=ignored-qualifiers -Werror=float-equal -Werror=unused -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-implicit-fallthrough -Wno-stringop-truncation -Wno-format-truncation -Wno-restrict -Wno-format -Wno-cpp -Wno-discarded-qualifiers

Такие ключи были у компоновщика
-specs=nosys.specs -Xlinker --gc-sections -Xlinker --nmagic -Wl,–gc-sections -Xlinker --print-memory-usage -mcpu=cortex-m4 -march=armv7e-m -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -T C:/projects/release/trunk/source/microcontroller/stm32f407ve/gcc_arm_mbr.ld -L C:/projects/release/trunk/source/microcontroller/stm32f407ve -lm -t -Wl,–cref -Wl,–gc-sections -Wl,-Map=build/jz_f407vet6_mbr_gcc_m.map --verbose

Я может быть не туда смотрю, но где там исходники?

Надо запустить скрипт build_from_make.bat. начнется построение.

В логе сборки будут фигурировать абсолютные пути к каждому си файлу.

Зачем-то откуда-то там ещё файл .cproject

.cproject - это ж просто настройка текстового редактора eclipse.
Не более того.

Я может быть не туда смотрю, но где там исходники?

Исходники вынесены "за скобки". То есть в папках на уровень выше.

Например, драйвер светодиода используется во всех проектах, поэтому он лежит в
https://github.com/aabzel/trunk/tree/main/source/control/led/led_mono
а не в папке с названием конкретного проекта

Репозиторий построен согласно вот этой методичке.

Что Должно Быть в Каждом FirmWare Pепозитории
https://habr.com/ru/articles/689542/

Я тут печалюсь, что загрузчик с возможностью обновления прошивки по Modbus меньше 2кБ не получается, а ИИ-шечка делает 2кБ кода, который не делает ничего? Есть надежда, что роботы пока людей не заменят.

Вы не правы. ИИ-шечка уже прекрасно заменяет людей, которые пишут 25 кБ кода, который не делает ничего.

Это stm Hal написанный индусами раздувает бинарь.

А зачем загрузчику интерфейсы и протоколы? Сам бинарь приложение может успешно принять.

Загрузчику остаётся только прыгнуть в бинарь.

Не всегда и не везде нужен многоступенчатый загрузчик. Чаще всего достаточно возможности принять обновление прошивки по UART или CAN, и прыгнуть в основной код. Это всё великолепие можно вместить в первые 2 страницы флеша, а иногда и в одну.

Это же не большой arm процессор, где один загрузчик инициализирует ОЗУ, другой некоторую периферию, третий там в безопасную среду прыгает (или не прыгает), и только потом где-то там вдалеке есть ядро Linux.

Микроконтроллер в большинстве случаев работает вообще без загрузчиков, вот он пошел в адрес 0, который смаплен на какой-то адрес флеша (0x08000000), а там указатель стека и за ним reset handler, и дальше уже всё понятно. А если мы идём к многоступенчатой схеме, то нужно понимать, зачем мы это делаем?

В вашем случае я думаю, что хочется оставить первые небольшие страницы под nvram (что написано в таблице), а вторичный загрузчик работает с каким-то сложным интерфейсом типа ethernet, и не поместится в маленькую страницу флеша. Вот и строится Saturn V с множеством ступеней.

Главное чтобы не получился Спейс Шаттл, который весит в два раза больше, чем везёт на себе, и стоит многократно дороже, чем другие аналоги

Писал загрузчик для stm24f407.

В первую страницу флеша (16кб), уложил полновесную прошивку, которая могла обновлять основную прошивку с USB mass storage (fat 16/32 only)...

Вот ссылка - https://github.com/andreili/USB-Keyboard/tree/master/fw_boot

Сам проект давно заброшен и не доведён до ума - он давно потерял смысл.

По размеру загрузчика:

1) Делать его меньше размера страницы флеша нет смысла - стирание идёт минимально страницами.

2) Если там не нужны прерывания, то почти вся таблица прерываний идёт под нож - прилично экономит размер. Главное - запретить прерывания сразу на старте и не забыть оставить системные прерывания, они не маскируются.

3) Да, большую часть драйверов и прочего придётся писать самому - код из HAL от ST-Micro далеко не оптимальный и есть память как браузер Хром...

Вот вы пользуютесь LLM чтобы нагенерить текмт в статью, но можно же вычитать, чтобы одно и то же не повторялось по несколько раз.

Сори, наболело уже.

Можно уменьшить размер прошивки, если отключить использование стандартной библиотеки C, убрав bl __libc_init_array из startup_stm32f407xx.S и раскомментировав LDFLAGS += -nostdlib в Makefile. Также ещё можно убрать неиспользуемые вектора прерываний из таблицы, например, все external. Суммарно размер прошивки сократится до ~350 байт.

Благодарю Вас, Владимир, за отличную подсказку!
В самом деле, с этими двумя улучшениями бинарь загрузчика стал 324 байта.


rm -f main.o system_stm32f4xx.o startup_stm32f407xx.o jz_f407vet6_mbr_light_gcc_m.elf jz_f407vet6_mbr_light_gcc_m.bin jz_f407vet6_mbr_light_gcc_m.hex jz_f407vet6_mbr_light_gcc_m.map
arm-none-eabi-gcc -mcpu=cortex-m4  -mthumb  -mfpu=fpv4-sp-d16  -mfloat-abi=softfp -Os -ffunction-sections -fdata-sections  -nostdlib  -nostartfiles -fno-builtin  -ffreestanding  -fno-exceptions  -fno-rtti -Wl,-gc-sections -Wl,-s -DSTM32F407xx  -DUSE_STDPERIPH_DRIVER -c main.c -o main.o
cc1.exe: warning: command-line option '-fno-rtti' is valid for C++/D/ObjC++ but not for C
arm-none-eabi-gcc -mcpu=cortex-m4  -mthumb  -mfpu=fpv4-sp-d16  -mfloat-abi=softfp -Os -ffunction-sections -fdata-sections  -nostdlib  -nostartfiles -fno-builtin  -ffreestanding  -fno-exceptions  -fno-rtti -Wl,-gc-sections -Wl,-s -DSTM32F407xx  -DUSE_STDPERIPH_DRIVER -c system_stm32f4xx.c -o system_stm32f4xx.o
cc1.exe: warning: command-line option '-fno-rtti' is valid for C++/D/ObjC++ but not for C
arm-none-eabi-gcc    -c -o startup_stm32f407xx.o startup_stm32f407xx.S
arm-none-eabi-gcc -nostdlib  -mcpu=cortex-m4  -mthumb  -mfpu=fpv4-sp-d16  -mfloat-abi=softfp -T gcc_arm_mbr.ld -Wl,--print-memory-usage  -Wl,--gc-sections -Wl,--cref  -Wl,-Map=jz_f407vet6_mbr_light_gcc_m.map main.o system_stm32f4xx.o startup_stm32f407xx.o -o jz_f407vet6_mbr_light_gcc_m.elf
Memory region         Used Size  Region Size  %age Used
             RAM:       16392 B       128 KB     12.51%
          CCMRAM:          0 GB        64 KB      0.00%
           FLASH:         324 B         3 KB     10.55%
arm-none-eabi-size jz_f407vet6_mbr_light_gcc_m.elf
   text	   data	    bss	    dec	    hex	filename
    324	      0	  16392	  16716	   414c	jz_f407vet6_mbr_light_gcc_m.elf
arm-none-eabi-objcopy -O binary jz_f407vet6_mbr_light_gcc_m.elf jz_f407vet6_mbr_light_gcc_m.bin
arm-none-eabi-objcopy -O ihex jz_f407vet6_mbr_light_gcc_m.elf jz_f407vet6_mbr_light_gcc_m.hex

Ещё можно выкинуть кучу и уменьшить стек - их зануление идёт в начальной стадии работы фирмвари. По логу выше - целых 16Кб оперативы зануляет, это дохрена для фирмвари, которая этим не пользуется всё равно...

А я правильно понимаю, что в "наивной реализации HAL" присутствует mcal с целой горой всего на свете?

Это в репозитории много чего лежит.
А к конкретной сборке подключается только то, что выбирается переменными окружения в GNU Make скриптах.

Полный состав реально задействованных исходников можно увидеть в логе сборки компилятора.

После сборки образуется файл-отчет build_log.txt , который и рассказывает, что из чего собиралось.

Sign up to leave a comment.

Articles