Comments 25
Прошивка для чего ?
А если 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. начнется построение.
В логе сборки будут фигурировать абсолютные пути к каждому си файлу.
Я может быть не туда смотрю, но где там исходники?
Исходники вынесены "за скобки". То есть в папках на уровень выше.
Например, драйвер светодиода используется во всех проектах, поэтому он лежит в
https://github.com/aabzel/trunk/tree/main/source/control/led/led_mono
а не в папке с названием конкретного проекта
Репозиторий построен согласно вот этой методичке.
Что Должно Быть в Каждом FirmWare Pепозитории
https://habr.com/ru/articles/689542/
Я тут печалюсь, что загрузчик с возможностью обновления прошивки по Modbus меньше 2кБ не получается, а ИИ-шечка делает 2кБ кода, который не делает ничего? Есть надежда, что роботы пока людей не заменят.
Вы не правы. ИИ-шечка уже прекрасно заменяет людей, которые пишут 25 кБ кода, который не делает ничего.
А зачем загрузчику интерфейсы и протоколы? Сам бинарь приложение может успешно принять.
Загрузчику остаётся только прыгнуть в бинарь.
Не всегда и не везде нужен многоступенчатый загрузчик. Чаще всего достаточно возможности принять обновление прошивки по 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А я правильно понимаю, что в "наивной реализации HAL" присутствует mcal с целой горой всего на свете?
Это в репозитории много чего лежит.
А к конкретной сборке подключается только то, что выбирается переменными окружения в GNU Make скриптах.
Полный состав реально задействованных исходников можно увидеть в логе сборки компилятора.
После сборки образуется файл-отчет build_log.txt , который и рассказывает, что из чего собиралось.
Самый маленький загрузчик (MBR 324 байта)