From 5ac85b90f5e68d26b59e29fc5a6c19e4c2a87b6d Mon Sep 17 00:00:00 2001 From: Ezra Maccabee Date: Fri, 6 Mar 2026 16:14:37 +0300 Subject: [PATCH] # 4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Сборка bare-metal проекта в режиме Debug --- .clangd | 24 +++- .devcontainer/devcontainer.json | 5 +- .gitignore | 1 - .vscode/launch.json | 38 ++++++ .vscode/tasks.json | 213 ++++++++++++++++++++++++++++++ bsp/BOOT_FLAGS.md | 175 ++++++++++++++++++++++++ bsp/CMakeLists.txt | 6 +- cmake/toolchain_arm.cmake | 24 ++-- firmware/test/CMakeLists.txt | 20 +-- firmware/test/main.c | 2 +- lib/SEGGER/wrapper/CMakeLists.txt | 12 -- 11 files changed, 478 insertions(+), 42 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 .vscode/tasks.json create mode 100644 bsp/BOOT_FLAGS.md diff --git a/.clangd b/.clangd index fc6c9ca..a731f80 100644 --- a/.clangd +++ b/.clangd @@ -23,9 +23,9 @@ Diagnostics: --- -# Полностью отключаем clang-tidy для Core (генерированный STM32CubeMX код) +# SDK NXP: сгенерированный/вендорный код — tidy полностью отключён If: - PathMatch: "Core/.*\\.(c|h)" + PathMatch: "sdk/.*\\.(c|h)" Diagnostics: ClangTidy: Remove: @@ -33,7 +33,27 @@ Diagnostics: UnusedIncludes: None --- +# Сторонние библиотеки (SEGGER RTT и др.) — tidy полностью отключён +If: + PathMatch: "lib/.*\\.(c|h)" +Diagnostics: + ClangTidy: + Remove: + - "*" + UnusedIncludes: None +--- +# BSP board: сгенерированный Config Tools код — tidy полностью отключён +If: + PathMatch: "bsp/board/(board|pin_mux|clock_config)\\.(c|h)" +Diagnostics: + ClangTidy: + Remove: + - "*" + UnusedIncludes: None + +--- +# Глобальные настройки Index: Background: Build Diagnostics: diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index e3db4d1..87d9b7e 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,11 +1,11 @@ { - "name": "STM32 Dev", + "name": "MIMXRT1052 TFT Project", "build": { "dockerfile": "Dockerfile" }, "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind", "workspaceFolder": "/workspace", - // "postCreateCommand": "cmake --preset host-debug && cmake --preset Debug && cp build/Debug/compile_commands.json /workspace/compile_commands.json", + "postCreateCommand": "cmake --preset host-debug && cmake --preset Debug", "customizations": { "vscode": { "extensions": [ @@ -42,7 +42,6 @@ "*.h": "c", "*.c": "c" }, - "stm32.chip": "STM32F407VE", // clangd "clangd.path": "clangd", "clangd.arguments": [ diff --git a/.gitignore b/.gitignore index 2f4a6d2..1102fc6 100644 --- a/.gitignore +++ b/.gitignore @@ -60,7 +60,6 @@ Testing/ # Файлы настройки среды разработки .project -.vscode/ compile_commands.json .cache/ .DS_Store diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..46dd49a --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,38 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "preLaunchTask": "CopyExecutableDebug", + "type": "probe-rs-debug", + "request": "launch", + "name": "Local STM32F4 via probe-rs", + "cwd": "${workspaceFolder}", + "connectUnderReset": false, + "server": "127.0.0.1:50000", + "chip": "STM32F407VE", + "speed": 4000, + "wireProtocol": "Swd", + "flashingConfig": { + "flashingEnabled": true, + "haltAfterReset": true, + "formatOptions": {} + }, + "coreConfigs": [ + { + "coreIndex": 0, + "programBinary": "/tmp/firmware.elf", + "svdFile": "${workspaceFolder}/STM32F407.svd", + "rttEnabled": true, + "rttChannelFormats": [ + { + "channelNumber": 0, + "dataFormat": "String", + "showTimestamps": true + } + ] + } + ], + "consoleLogLevel": "Console" + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..79cf828 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,213 @@ +{ + "version": "2.0.0", + "tasks": [ + // Очистка директории с артефактами сборки + { + "label": "Clean", + "group": "build", + "type": "shell", + "command": "rm -rf build*", + "windows": { + "command": "rm build* -Recurse -Force" + }, + "options": { + "statusbar": { + "color": "#ff8b8b", + "label": "$(clear-all) CleanBuildDir", + "detail": "Clean ALL" + } + } + }, + // Сборка и запуск тестов на хосте в режиме Debug + { + "label": "Configure Host Debug tests", + "group": "build", + "hide": true, + "type": "shell", + "command": "cmake", + "args": [ + "--preset", + "host-debug" + ], + "options": { + "cwd": "${workspaceFolder}" + } + }, + { + "label": "Build Host Debug tests", + "group": "build", + "hide": true, + "type": "shell", + "command": "cmake", + "args": [ + "--build", + "--preset", + "host-debug-build" + ], + "options": { + "cwd": "${workspaceFolder}" + }, + "dependsOn": "Configure Host Debug tests" + }, + { + "label": "🧪 Host Build & Test All", + "type": "shell", + "command": "ctest", + "args": [ + "--preset", + "host-debug-test" + ], + "options": { + "cwd": "${workspaceFolder}", + "statusbar": { + "color": "#c800ff", + "label": "$(test-view-icon) Host Test Debug", + "detail": "Perform all the host tests" + } + }, + "group": "test", + "dependsOrder": "sequence", + "dependsOn": [ + "Build Host Debug tests" + ] + }, + // Сборка и запуск тестов на хосте в режиме Release + { + "label": "Configure Host Release tests", + "group": "build", + "hide": true, + "type": "shell", + "command": "cmake", + "args": [ + "--preset", + "host-release" + ], + "options": { + "cwd": "${workspaceFolder}" + }, + }, + { + "label": "Build Host Release tests", + "group": "build", + "hide": true, + "type": "shell", + "command": "cmake", + "args": [ + "--build", + "--preset", + "host-release-build" + ], + "dependsOn": "Configure Host Release tests" + }, + { + "label": "🧪 Host Release Tests", + "type": "shell", + "command": "ctest", + "args": [ + "--preset", + "host-release-test" + ], + "options": { + "cwd": "${workspaceFolder}", + "statusbar": { + "color": "#c800ff", + "label": "$(test-view-icon) Host Test Release", + "detail": "Perform all the host tests" + } + }, + "group": "test", + "dependsOrder": "sequence", + "dependsOn": [ + "Build Host Release tests" + ], + }, + // Подготовка сборки в контейнере с пресетом Debug + { + "label": "Docker: Configure (Debug)", + "type": "shell", + "hide": true, + "command": "cmake", + "args": [ + "--preset", + "Debug" + ], + "options": { + "cwd": "${workspaceFolder}" + }, + "group": "build", + "problemMatcher": [] + }, + // Сборка проекта в контейнере Debug + { + "label": "Docker: Build (Debug)", + "type": "shell", + "hide": false, + "command": "cmake", + "args": [ + "--build", + "--preset", + "Debug" + ], + "options": { + "cwd": "${workspaceFolder}", + "statusbar": { + "color": "#ff8bd4", + "label": "$(debug-console-view-icon) Target: Build (Debug)", + "detail": "do Debug build" + } + }, + "group": "build", + "dependsOn": "Docker: Configure (Debug)", + }, + // Подготовка сборки в контейнере с пресетом Release + { + "label": "Docker: Configure (Release)", + "type": "shell", + "hide": true, + "command": "cmake", + "args": [ + "--preset", + "Release" + ], + "options": { + "cwd": "${workspaceFolder}" + }, + "group": "build", + "problemMatcher": [] + }, + // Сборка проекта в контейнере Release + { + "label": "Docker: Build (Release)", + "type": "shell", + "hide": false, + "command": "cmake", + "args": [ + "--build", + "--preset", + "Release" + ], + "options": { + "cwd": "${workspaceFolder}", + "statusbar": { + "color": "#03b3ff", + "label": "$(pass-filled) Target: Build (Release)", + "detail": "do Release build" + } + }, + "group": "build", + "dependsOn": "Docker: Configure (Release)", + }, + ], + "inputs": [ + { + "id": "buildType", + "type": "pickString", + "description": "Тип сборки", + "options": [ + "Debug", + "Release", + ], + "default": "Debug" + } + ], +} \ No newline at end of file diff --git a/bsp/BOOT_FLAGS.md b/bsp/BOOT_FLAGS.md new file mode 100644 index 0000000..f6cb6b7 --- /dev/null +++ b/bsp/BOOT_FLAGS.md @@ -0,0 +1,175 @@ +# Boot-дефайны IMXRT1052 + +## Процесс загрузки + +При старте BootROM читает QSPI Flash через FlexSPI и ищет специальные структуры +по фиксированным смещениям от начала Flash (`0x60000000`): + +```bash +0x60000000 FDCB — FlexSPI NOR Configuration Block (512 bytes) +0x60000400 IVT — Image Vector Table +0x60000420 Boot Data +0x60000430 DCD — Device Configuration Data (опционально) +``` + +После разбора структур BootROM передаёт управление на точку входа прошивки. + +--- + +### `XIP_EXTERNAL_FLASH=1` + +Код исполняется напрямую из QSPI Flash через XIP (Execute-In-Place) без +копирования в RAM. FlexSPI отображает Flash в адресное пространство начиная с +`0x60000000`. Стартап и SDK знают что копирование кода из Flash в RAM не +требуется. + +### `XIP_BOOT_HEADER_ENABLE=1` + +Включает генерацию FDCB и IVT в начале Flash-образа. Без этих структур BootROM +не сможет найти прошивку и передать ей управление — устройство не загрузится. + +### `XIP_BOOT_HEADER_DCD_ENABLE=1` + +Включает DCD внутри boot header. DCD — список команд для BootROM (запись +регистров, ожидание флагов), которые выполняются **до** передачи управления +прошивке. Используется для ранней инициализации SDRAM, чтобы линкер мог +размещать данные в SDRAM с самого старта. + +> Если SDRAM инициализируется вручную в `main()` — DCD можно отключить, +> убрав этот дефайн. + +### `SKIP_SYSCLK_INIT` + +Запрещает `SystemInit()` (вызывается из стартапа до `main()`) настраивать +системные часы. Конфигурация тактирования полностью делегируется +`BOARD_BootClockRUN()` из `clock_config.c`. Без этого флага часы +инициализировались бы дважды, что может привести к нестабильной работе на +этапе старта. + +--- + +## Сценарии размещения кода + +### Справка: внутренняя RAM IMXRT1052 + +IMXRT1052 имеет три региона внутренней RAM: + +| Регион | Адрес | Размер | Назначение | +|--------|--------------|--------|------------------------------------------------------| +| ITCM | `0x00000000` | 512 KB | Tightly Coupled Instruction Memory — код, ISR | +| DTCM | `0x20000000` | 512 KB | Tightly Coupled Data Memory — стек, критичные данные | +| OCRAM | `0x20200000` | 512 KB | On-Chip RAM — общего назначения, доступна DMA | + +**ITCM** — лучший выбор для исполнения кода из RAM. Подключена напрямую к ядру +по выделенной шине, работает без wait states и без кэша. Даёт максимальную +детерминированность — критично для ISR и time-critical кода. + +OCRAM подключена через системную шину и кэш — выше латентность, но доступна +периферии и DMA. + +--- + +### Сценарий 1: хранение и исполнение из Flash (XIP) + +Код хранится в QSPI Flash и исполняется напрямую оттуда через FlexSPI. +Копирования не происходит. Простейший вариант — минимум настроек. + +**Применение:** большинство приложений где производительность не критична, +быстрый старт разработки. + +```cmake +target_compile_definitions(bsp_board PUBLIC + XIP_EXTERNAL_FLASH=1 # исполнение прямо из Flash + XIP_BOOT_HEADER_ENABLE=1 # FDCB + IVT в начале образа + XIP_BOOT_HEADER_DCD_ENABLE=1 # DCD для инициализации SDRAM если нужна + SKIP_SYSCLK_INIT +) +``` + +Линкерный скрипт: `MIMXRT1052xxxxx_flexspi_nor.ld` + +```bash +Flash (XIP): 0x60000000 — код и константы +DTCM: 0x20000000 — стек, .data, .bss +``` + +**Ограничения:** FlexSPI шина делится между исполнением кода и доступом к данным +Flash. При интенсивной работе с Flash (запись, чтение данных) производительность +кода падает. + +--- + +### Сценарий 2: хранение во Flash, исполнение из внутренней RAM (ITCM) + +Код хранится в QSPI Flash, при старте стартап копирует секцию `.text` в ITCM. +BootROM загружает стартап из Flash, стартап копирует остальной код и передаёт +управление. + +**Применение:** ISR с жёсткими временными требованиями, алгоритмы управления, +участки кода где нужна детерминированная латентность. + +```cmake +target_compile_definitions(bsp_board PUBLIC + # XIP_EXTERNAL_FLASH не определяем — код копируется в ITCM + XIP_BOOT_HEADER_ENABLE=1 # FDCB + IVT нужны — BootROM всё равно грузит из Flash + XIP_BOOT_HEADER_DCD_ENABLE=1 # DCD нужен если SDRAM используется под данные + SKIP_SYSCLK_INIT +) +``` + +Линкерный скрипт: `MIMXRT1052xxxxx_flexspi_nor_txt_itcm.ld` (или кастомный) + +```bash +Flash: 0x60000000 — хранение образа +ITCM (LMA→VMA): 0x00000000 — исполнение кода +DTCM: 0x20000000 — стек, .data, .bss +``` + +**Ограничения:** ITCM всего 512 KB — весь исполняемый код должен в него +поместиться. Время старта увеличивается на время копирования из Flash. + +--- + +### Сценарий 3: хранение во Flash, исполнение из SDRAM + +Код хранится в QSPI Flash, при старте копируется в SDRAM (32 MB, `0x80000000`). +SDRAM **должна быть инициализирована до копирования** — через DCD BootROM. + +**Применение:** большие приложения которые не помещаются во внутреннюю RAM и +слишком медленно работают из Flash — например, UI с графикой, обработка +изображений. + +```cmake +target_compile_definitions(bsp_board PUBLIC + # XIP_EXTERNAL_FLASH не определяем — код копируется в SDRAM + XIP_BOOT_HEADER_ENABLE=1 + XIP_BOOT_HEADER_DCD_ENABLE=1 # обязательно — DCD инициализирует SDRAM до старта + SKIP_SYSCLK_INIT +) +``` + +Линкерный скрипт: кастомный с регионом SDRAM + +```bash +Flash: 0x60000000 — хранение образа +SDRAM (LMA→VMA): 0x80000000 — исполнение кода (32 MB) +DTCM: 0x20000000 — стек, критичные данные +ITCM: 0x00000000 — ISR и time-critical функции +``` + +Для ISR и критичного кода используй атрибут `__attribute__((section(".itcm")))` +чтобы разместить их в ITCM отдельно от основного кода в SDRAM. + +**Ограничения:** SDRAM работает через SEMC с несколькими wait states — медленнее +ITCM. DCD усложняет конфигурацию — при смене частоты тактирования SEMC параметры +DCD нужно пересчитывать. + +--- + +### Сводная таблица + +| Сценарий | `XIP_EXTERNAL_FLASH` | `XIP_BOOT_HEADER_ENABLE` | `XIP_BOOT_HEADER_DCD_ENABLE` | `SKIP_SYSCLK_INIT` | +|---------------------|----------------------|--------------------------|------------------------------|--------------------| +| XIP из Flash | `1` | `1` | `1` (если SDRAM нужна) | да | +| Копирование в ITCM | не определять | `1` | `1` (если SDRAM нужна) | да | +| Копирование в SDRAM | не определять | `1` | `1` (обязательно) | да | \ No newline at end of file diff --git a/bsp/CMakeLists.txt b/bsp/CMakeLists.txt index 43cb841..e402674 100644 --- a/bsp/CMakeLists.txt +++ b/bsp/CMakeLists.txt @@ -5,9 +5,9 @@ endif() # ----------------------------------------------------------------------------- # bsp_board — стартап, сгенерированные файлы Config Tools, инициализация платы # ----------------------------------------------------------------------------- -add_library( - bsp_board STATIC board/board.c board/pin_mux.c board/clock_config.c - board/syscalls.c board/startup/startup_MIMXRT1052.S) + +add_library(bsp_board STATIC board/board.c board/pin_mux.c board/clock_config.c + board/startup/startup_MIMXRT1052.S) target_include_directories(bsp_board PUBLIC board) diff --git a/cmake/toolchain_arm.cmake b/cmake/toolchain_arm.cmake index 5b4c9d2..c13a4b1 100644 --- a/cmake/toolchain_arm.cmake +++ b/cmake/toolchain_arm.cmake @@ -76,8 +76,17 @@ set(CMAKE_SIZE # ----------------------------------------------------------------------------- # Флаги процессора — MIMXRT1052 (Cortex-M7, FPv5-D16, hard-float ABI) # ----------------------------------------------------------------------------- +# -mcpu=cortex-m7 — целевой процессор, включает оптимизации под эту +# архитектуру -mthumb — набор инструкций Thumb-2 (16/32-bit), +# меньший код при той же производительности -mfpu=fpv5-d16 — FPU: FPv5 с +# 16 парами 64-bit регистров, соответствует аппаратному FPU IMXRT1052 +# -mfloat-abi=hard — float/double передаются через FPU-регистры (быстрее чем +# softfp) -ffunction-sections — каждая функция в отдельной секции, позволяет +# --gc-sections удалять неиспользуемые -fdata-sections — аналогично, но для +# переменных -ffreestanding — не предполагать наличия ОС, main() не точка +# входа, встроенные замены stdlib отключены set(CPU_FLAGS - "-mcpu=cortex-m7 -mthumb -mfpu=fpv5-d16 -mfloat-abi=hard -ffunction-sections -fdata-sections" + "-mcpu=cortex-m7 -mthumb -mfpu=fpv5-d16 -mfloat-abi=hard -ffunction-sections -fdata-sections -ffreestanding" ) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CPU_FLAGS}" @@ -115,16 +124,9 @@ set(CMAKE_ASM_FLAGS_RELEASE # ----------------------------------------------------------------------------- # C runtime библиотека — newlib-nano (меньше размер, подходит для embedded) # ----------------------------------------------------------------------------- -# nano.specs — выбирает компактную версию newlib-nano (меньший размер printf, -# malloc и т.д.). Но не предоставляет реализацию системных вызовов. - -# nosys.specs — предоставляет именно заглушки syscalls. Без него newlib ожидает -# что ты сам реализуешь _sbrk, _write, _exit и т.д. — либо через semihosting, -# либо вручную. - -# --gc-sections — убирает неиспользуемые секции кода и данных. Работает в паре с -# -ffunction-sections -fdata-sections у компилятора (каждая функция в отдельной -# секции — линкер выбрасывает ненужные). +# --specs=nano.specs — использовать newlib-nano: облегчённая stdlib, +# меньший размер printf/malloc -Wl,--no-warn-rwx-segments — подавить +# предупреждение о RWX сегментах (ITCM/DTCM нормальны для MCU) set(CMAKE_EXE_LINKER_FLAGS_INIT "--specs=nano.specs -Wl,--no-warn-rwx-segments") # ----------------------------------------------------------------------------- diff --git a/firmware/test/CMakeLists.txt b/firmware/test/CMakeLists.txt index f7a40b1..bb8a9e1 100644 --- a/firmware/test/CMakeLists.txt +++ b/firmware/test/CMakeLists.txt @@ -1,7 +1,10 @@ # firmware/test/CMakeLists.txt Тестовая прошивка — входной контроль платы на # производстве -add_executable(firmware_test main.c) +add_executable(firmware_test) + +target_sources(firmware_test PRIVATE main.c + ${PROJECT_SOURCE_DIR}/bsp/board/syscalls.c) # ----------------------------------------------------------------------------- # Зависимости — только то что нужно для входного контроля bsp_board транзитивно @@ -23,16 +26,15 @@ target_link_libraries( # ----------------------------------------------------------------------------- # Linker script # ----------------------------------------------------------------------------- -# --gc-sections — убирает неиспользуемые секции кода и данных. Работает в паре с -# -ffunction-sections -fdata-sections у компилятора (каждая функция в отдельной -# секции — линкер выбрасывает ненужные). +# --gc-sections — удалять неиспользуемые секции (работает с +# -ffunction/data-sections) --print-memory-usage — выводить таблицу +# использования Flash/RAM после линковки -Map — генерировать +# map-файл для анализа размещения символов -T — линкерный +# скрипт с описанием карты памяти IMXRT1052 target_link_options( - firmware_test - PRIVATE - -T${PROJECT_SOURCE_DIR}/cmake/linker/MIMXRT1052xxxxx_flexspi_nor.ld - -Wl,--gc-sections + firmware_test PRIVATE -Wl,--gc-sections -Wl,--print-memory-usage -Wl,-Map=${CMAKE_BINARY_DIR}/firmware_test.map - -Wl,--print-memory-usage) + -T${PROJECT_SOURCE_DIR}/cmake/linker/MIMXRT1052xxxxx_flexspi_nor.ld) # ----------------------------------------------------------------------------- # Post-build: генерация .bin для прошивки через blhost diff --git a/firmware/test/main.c b/firmware/test/main.c index 0732849..7e2f1a8 100644 --- a/firmware/test/main.c +++ b/firmware/test/main.c @@ -6,8 +6,8 @@ * SPDX-License-Identifier: BSD-3-Clause */ +#include "SEGGER_RTT.h" #include "board.h" - /******************************************************************************* * Definitions ******************************************************************************/ diff --git a/lib/SEGGER/wrapper/CMakeLists.txt b/lib/SEGGER/wrapper/CMakeLists.txt index ef09ef7..7682692 100644 --- a/lib/SEGGER/wrapper/CMakeLists.txt +++ b/lib/SEGGER/wrapper/CMakeLists.txt @@ -7,18 +7,6 @@ set(RTT_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../RTT/RTT) set(RTT_SYSCALLS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../RTT/Syscalls) set(RTT_CONFIG_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../RTT/Config) -# Проверяем наличие субмодуля -if(NOT EXISTS "${RTT_SRC_DIR}/SEGGER_RTT.c") - message( - FATAL_ERROR - " -❌ SEGGER_RTT submodule не инициализирован! - -Запустите в корне проекта: - git submodule update --init ThirdParty/SEGGER/RTT - ") -endif() - # Создаём статическую библиотеку add_library(SeggerRTT STATIC)