--- name: cubemx-min-prj description: Create an STM32CubeMX minimum project (CMake/VS Code ready) matching STM32F407ZGTx clocks and debug setup. Use when generating a new CubeMX-based STM32 project or updating this workflow; confirm the locally installed CubeMX version before creating or editing any `.ioc` so the project stays openable on the user's machine. metadata: author: bowei-local version: "1.5" compatibility: Requires STM32CubeMX at C:/Program Files/STMicroelectronics/STM32Cube/STM32CubeMX/STM32CubeMX.exe and STM32CubeCLT available for VS Code debug. --- # STM32CubeMX Project Creator Teach Claude to create a new STM32CubeMX project for `STM32F407ZGTx`, output a CMake build for VS Code, and prep debug tasks. The generated project must preserve the required `USART2` behavior exactly, including DMA-based idle reception and the supporting user-code hooks in `usart.c`, `main.c`, and `syscalls.c`. The skill must be self-contained. Do not inspect, copy from, diff against, or otherwise rely on other user projects as templates or references when generating a new project. ## Preconditions - Confirm CubeMX exists at `C:/Program Files/STMicroelectronics/STM32Cube/STM32CubeMX/STM32CubeMX.exe`; otherwise stop and report. - Confirm the installed CubeMX version before generating or editing the project. If the local version cannot be determined, stop and report instead of guessing. - REQUIRED VERSION LOCK: local STM32CubeMX must be exactly `6.11.1`. If the detected version is not exactly `6.11.1`, stop immediately and report an error; do not proceed. Note: `6.11.1-*` is equal to `6.11.1`. - Ensure written `.ioc` metadata is `MxCube.Version=6.11.1` for this skill. - Use only the installed CubeMX, its bundled databases, and the requested project directory as inputs. Do not use another workspace or existing STM32 project as a reference. - Have an output directory where the new project folder will be created. - Ask the user for the project name. - VS Code STM32 extensions are available (CMake Tools, Cortex-Debug, STM32 VS Code Extension). ## Strict IOC acceptance gates - The generated `.ioc` must match this skill's required configuration exactly (MCU, clock tree, RCC/NVIC/DMA/GPIO/USART2 settings, and pin map). No partial match is acceptable. - Re-check the final `.ioc` against the required values before finishing; if any field differs, treat as failure and fix/regenerate. - For `USART2` compatibility, do not hand-write `WordLength/Parity/StopBits` enum lines in `.ioc`. Keep `USART2.IPParameters` minimal (`VirtualMode,BaudRate,Mode,OverSampling`) and let CubeMX resolve 8N1 defaults during load/generation. - Opening the `.ioc` must not show `Not a valid ioc file` or required-field incompatibility errors. - If any IOC gate fails, stop, fix in IOC, regenerate, and re-validate before any further edits. ## MCU + clock configuration - MCU: `STM32F407ZGTx`, package `LQFP144`. - Clock source: HSE crystal = `25_000_000 Hz` on `PH0/PH1`. - PLL: source HSE, `PLLM=25`, `PLLN=168`, `PLLP=2`, `PLLQ=4`. - Resulting clocks: `SYSCLK=84 MHz`, `HCLK=84 MHz`, `APB1=42 MHz`, `APB2=84 MHz`, `I2S=96 MHz`, `MCO2=84 MHz`, `Systick=1 ms`. - Ensure RCC: `SYSCLK source = PLLCLK`, `LSI = 32000`, and keep the divider values listed here. ## Generation targets - Toolchain/IDE: CMake (Ninja or Make). Enable `CMAKE_EXPORT_COMPILE_COMMANDS`. - Languages: C + ASM, C standard C11. - Linker script: device-generated `STM32F407ZGTx_FLASH.ld`. - Peripherals to enable by default: RCC, SYS, NVIC, GPIO, DMA, USART2. - GPIO baseline: - SWD: `PA13` = `SYS_JTMS-SWDIO`, `PA14` = `SYS_JTCK-SWCLK` - Oscillators: `PH0/PH1` for HSE - USART pins: `PD5` = `USART2_TX`, `PD6` = `USART2_RX` - Remove all other GPIO assignments unless the user explicitly asks for them - NVIC baseline: - `NVIC_PRIORITYGROUP_4` - System handlers enabled as generated by CubeMX - `SysTick_IRQn` enabled with priority `15` - Enable `DMA1_Stream5_IRQn` and `DMA1_Stream6_IRQn` - DMA baseline: - `USART2_RX`: `DMA1_Stream5`, `DMA_CHANNEL_4`, `DMA_PERIPH_TO_MEMORY`, `DMA_NORMAL`, byte alignment, memory increment enabled, peripheral increment disabled, priority low, FIFO disabled - `USART2_TX`: `DMA1_Stream6`, `DMA_CHANNEL_4`, `DMA_MEMORY_TO_PERIPH`, `DMA_NORMAL`, byte alignment, memory increment enabled, peripheral increment disabled, priority low, FIFO disabled - USART2 baseline: - Virtual mode: `VM_ASYNC` - Parameters in generated init: `115200`, `8N1`, `TX_RX`, `UART_HWCONTROL_NONE`, `UART_OVERSAMPLING_16` - `HAL_UART_MspInit()` must configure `PD5/PD6` as `GPIO_AF7_USART2` and link both DMA handles with `__HAL_LINKDMA` - `stm32f4xx_it.c` must keep `DMA1_Stream5_IRQHandler()` and `DMA1_Stream6_IRQHandler()` calling `HAL_DMA_IRQHandler(&hdma_usart2_rx)` and `HAL_DMA_IRQHandler(&hdma_usart2_tx)` - Do not add other peripherals unless the user explicitly requests them. ## USART2 runtime behavior - `printf` redirection pattern: - Keep `syscalls.c` with `extern int __io_putchar(int ch) __attribute__((weak));` - Do not implement `__io_putchar()` in `syscalls.c` - Re-define `int __io_putchar(int ch)` in `Core/Src/usart.c` - Implementation must call `HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 1000);` and return `ch` - DMA receive flow: - In `main.c`, after `MX_GPIO_Init();`, `MX_DMA_Init();`, and `MX_USART2_UART_Init();`, call `HAL_UARTEx_ReceiveToIdle_DMA(&huart2, receiveBuf50, sizeof(receiveBuf50));` - Implement `HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)` in user code, not the legacy `HAL_UART_RxCpltCallback()` - In that callback, when `huart->Instance == USART2`, terminate the buffer safely, process the received command, then immediately re-arm `HAL_UARTEx_ReceiveToIdle_DMA(&huart2, receiveBuf50, sizeof(receiveBuf50));` - Ensure the generated project includes all symbols used by this flow: - `UART_HandleTypeDef huart2` - `DMA_HandleTypeDef hdma_usart2_rx` - `DMA_HandleTypeDef hdma_usart2_tx` - a receive buffer such as `uint8_t receiveBuf50[50]` ## VS Code integration (mirror reference patterns) Create `.vscode/` with: - `settings.json`: - `"cmake.configurePreset": "Debug"` - `"cmake.buildPreset": "Debug"` - `"STM32VSCodeExtension.cubeCLT.path": "C:/ST/STM32CubeCLT_1.19.0"` (or user path) - `c_cpp_properties.json`: `configurationProvider` = `ms-vscode.cmake-tools` - `tasks.json`: include - A fixed `CMake: configure` task that runs `cmake --preset Debug` - A fixed default build task that runs `cmake --build --preset Debug` - A fixed clean rebuild task that runs `cmake --build --preset Debug --clean-first` - Mark the fixed build task as the default build group so VS Code `Ctrl+Shift+B` works immediately - Flash task: `STM32_Programmer_CLI --connect port=swd --download ${workspaceFolder}/build/Debug/.elf -hardRst -rst --start` - Aggregate "Build + Flash" task depending on rebuild + flash - Avoid depending on `${command:cmake.activeBuildPresetName}`, `${command:cmake.activeConfigurePresetName}`, or `${command:cmake.launchTargetPath}` for the default build path, because `Ctrl+Shift+B` may fail before CMake Tools initializes those values - `launch.json`: Cortex-Debug launch + attach configs: - `servertype: stlink`, `device: STM32F407ZGTx`, `interface: swd` - `executable: ${workspaceFolder}/build/Debug/.elf` - `svdFile: ${config:STM32VSCodeExtension.cubeCLT.path}/STMicroelectronics_CMSIS_SVD/STM32F407.svd` - `serverpath`/`stlinkPath`: `${config:STM32VSCodeExtension.cubeCLT.path}/STLink-gdb-server/bin/ST-LINK_gdbserver` - `armToolchainPath`: `${config:STM32VSCodeExtension.cubeCLT.path}/GNU-tools-for-STM32/bin` - `gdbPath`: `${config:STM32VSCodeExtension.cubeCLT.path}/GNU-tools-for-STM32/bin/arm-none-eabi-gdb` - `preLaunchTask`: `CMake: clean rebuild` (for launch config) ## CMake scaffolding (root) - `CMakeLists.txt`: include toolchain `cmake/gcc-arm-none-eabi.cmake`, set `CMAKE_C_STANDARD 11`, enable C & ASM, create executable `${CMAKE_PROJECT_NAME}`, `add_subdirectory(cmake/stm32cubemx)`, add user sources, link `stm32cubemx`. - `CMakePresets.json`: generator Ninja, binary dir `build/${presetName}`, presets Debug/RelWithDebInfo/Release/MinSizeRel inheriting default. - `cmake/gcc-arm-none-eabi.cmake`: set `TOOLCHAIN_PREFIX=arm-none-eabi-`, compilers, target flags `-mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard`, link script `STM32F407ZGTx_FLASH.ld`, typical link flags with gc-sections and map file. - `cmake/stm32cubemx/CMakeLists.txt`: interface lib with `USE_HAL_DRIVER`, `STM32F407xx`, includes for `Core/Inc` and `Drivers`, and CubeMX-generated sources for the minimal setup (at minimum `main.c`, `gpio.c`, `dma.c`, `usart.c`, `stm32f4xx_it.c`, `stm32f4xx_hal_msp.c`, `system_stm32f4xx.c`, `startup_stm32f407xx.s`, and required HAL driver files). Keep it aligned with CubeMX output; regenerate if peripherals differ. ## Execution steps 1) Verify CubeMX binary exists; if missing, stop. 2) Detect and record the installed CubeMX version before doing any `.ioc` work. Use that exact version when validating compatibility and when writing `MxCube.Version` / related metadata. - Hard stop unless the detected version is exactly `6.11.1`. 3) Do not handcraft a full STM32 project when CubeMX generation is available locally. Generate with the installed CubeMX first, then patch only the required user sections and build files. 4) Do not inspect or copy from any other project on disk. This skill must work independently from CubeMX metadata, generated output, and the instructions in this file only. 5) Ask user for project name and target directory. 6) Create project folder and open CubeMX: - Set MCU to STM32F407ZGTx (LQFP144). - Configure RCC: HSE 25 MHz on `PH0/PH1`, `PLLM=25`, `PLLN=168`, `PLLP=2`, `PLLQ=4`, `SYSCLK` from PLL. - Enable required peripherals for the default template: SYS, RCC, NVIC, GPIO, DMA, USART2. - Configure only these GPIO entries by default: `PH0`, `PH1`, `PA13`, `PA14`, `PD5`, `PD6`. - Configure `USART2` as asynchronous on `PD5/PD6`. - Configure DMA requests exactly as specified here: `USART2_RX -> DMA1_Stream5`, `USART2_TX -> DMA1_Stream6`. - Set `NVIC_PRIORITYGROUP_4`, keep `SysTick_IRQn` at priority `15`, and enable both DMA stream IRQs. - Project Manager -> Toolchain/IDE: CMake; set project name and path. - Code Generator: Generate peripheral initialization as "HAL", keep user sections. - Generate code. 7) Validate the generated output before patching: - Confirm `main.c` exists and `SystemClock_Config()` uses `HSE`, `PLL_ON`, `PLLM=25`, `PLLN=168`, `PLLP=RCC_PLLP_DIV2`, `PLLQ=4`, `SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK`, `AHB = DIV1`, `APB1 = DIV2`, `APB2 = DIV1`. - Confirm the generated project includes `USART2`, `DMA1_Stream5`, `DMA1_Stream6`, and `USART2_IRQn`. - Confirm the generated `.ioc` does not report required-field incompatibilities for RCC, DMA, SYS, GPIO, or USART2. - Confirm `.ioc` loads without `Not a valid ioc file`. - Confirm `.ioc` does not contain hand-written `USART2.WordLength`, `USART2.Parity`, `USART2.StopBits` lines and `USART2.IPParameters` remains `VirtualMode,BaudRate,Mode,OverSampling` before generation. - If CubeMX output falls back to `HSI`, `PLL_NONE`, missing DMA streams, or missing USART2 init, treat generation as failed and fix generation inputs before patching. 8) Patch the generated sources to preserve the required `USART2` runtime behavior: - In `Core/Src/usart.c`, add `__io_putchar()` in user code and keep it bound to `HAL_UART_Transmit(&huart2, ...)`. - In `Core/Src/syscalls.c`, leave `__io_putchar()` as a weak external declaration only. - In `Core/Src/main.c`, declare a receive buffer, call `HAL_UARTEx_ReceiveToIdle_DMA(&huart2, receiveBuf50, sizeof(receiveBuf50));` during initialization, and implement `HAL_UARTEx_RxEventCallback()` to process and re-arm reception. - In `Core/Src/stm32f4xx_it.c`, keep both DMA IRQ handlers for `USART2`. - This step is the only allowed direct source-code modification step. 9) Normalize the generated layout to the required root structure if CubeMX emits a different but equivalent layout: - Required end state is root `Core/Inc`, `Core/Src`, `Drivers`, `cmake`, `.vscode`, linker script, startup file, and root `.ioc`. - If CubeMX emits `Inc/` and `Src/` at the root, move them to `Core/Inc` and `Core/Src` before patching build files. 10) Add/adjust the CMake scaffolding files (root CMakeLists, presets, toolchain, stm32cubemx CMakeLists) to match the templates above if CubeMX did not emit them. 11) Add `.vscode` files as above; set `executable` paths to the chosen project name. 12) Validate VS Code build behavior: - Confirm the default VS Code build task maps to `cmake --build --preset Debug`. - Confirm build tasks do not rely on unresolved CMake Tools command substitutions for the default build path. - If needed, prefer fixed `Debug` preset names and fixed `${workspaceFolder}/build/Debug/.elf` paths over dynamic commands. 13) Before finishing, re-check the generated `.ioc` header and confirm its CubeMX version metadata still matches the local installation. Fix it if it drifted. - For this skill, it must be exactly `MxCube.Version=6.11.1`. 14) Enforce no-manual-edit rule: - Except for `USART2 runtime behavior` source edits in step 8, do not directly modify generated source code to fix config mismatches. - All non-runtime configuration fixes must be made in `.ioc`, then regenerated from CubeMX. 15) Run `cmake --preset Debug` then `cmake --build --preset Debug` to verify build; ensure `${workspaceFolder}/build/Debug/.elf` exists. 16) Verify VS Code `Ctrl+Shift+B` can invoke the generated default build task without manual preset reselection. 17) For flashing, run VS Code task "Build + Flash" or `STM32_Programmer_CLI --connect port=swd --download build/Debug/.elf -hardRst -rst --start`. 18) For debugging, launch "Build & Debug Microcontroller - ST-Link" in VS Code (Cortex-Debug). ## Notes & guardrails - Prefer using commands listed in `Reference commands` whenever possible. If a listed command cannot be used, use an equivalent command and briefly state why. - Keep `SKILL.md` concise; move verbose reference to separate files if added. - If user chooses another MCU, re-derive clocks accordingly instead of using the above constants. - Version policy for this skill is strict: only `6.11.1` is allowed. Any other detected version is a hard error. - Do not continue from an invalid CubeMX load that logs missing required RCC, DMA, SYS, GPIO, or USART fields. Fix the `.ioc` / generation inputs first. - For `USART2`, avoid hardcoding enum text values in `.ioc` for `WordLength/Parity/StopBits`; rely on CubeMX defaults and generated init checks instead. - Do not finish if IOC cannot be opened cleanly by CubeMX. - Do not continue patching if generated `main.c` shows `HSI` or `PLL_NONE` instead of the required `HSE + PLL` clock tree. - This skill must remain independent. Do not read another STM32 project to discover valid `.ioc` keys, clock parameters, or file layouts. - Prefer deterministic VS Code tasks. Do not assume VS Code `Ctrl+Shift+B` will work if the tasks depend on unresolved extension-provided command variables. - Do not refer to the VS Code build shortcut as `Ctrl+B`; in standard VS Code usage the build shortcut is `Ctrl+Shift+B`. - For the default build path, prefer fixed `Debug` preset tasks over dynamic `${command:...}` substitutions unless those substitutions are explicitly verified in the current workspace. - Unless the user asks for more peripherals, remove any auto-enabled middleware or peripheral blocks beyond DMA, GPIO, NVIC, RCC, SYS, and USART2 from both the CubeMX configuration and generated build files. - When stripping peripherals from a copied `.ioc`, also remove their dependent pins, DMA requests, NVIC entries, generated source files, and middleware references so the result stays internally consistent. - For GPIO specifically, keep only these default pins: `PH0`, `PH1`, `PA13`, `PA14`, `PD5`, `PD6`. - Do not replace the required `HAL_UARTEx_ReceiveToIdle_DMA()` + `HAL_UARTEx_RxEventCallback()` flow with polling, interrupt-only receive, or `HAL_UART_Receive_DMA()`. - Do not move `__io_putchar()` into `syscalls.c`; keep the actual implementation in `usart.c` so `printf` stays coupled to `USART2`. - Except for the explicit `USART2 runtime behavior` edits, do not directly edit generated C sources for configuration purposes; enforce configuration via IOC + regenerate. ## Reference commands Use these commands as operational references for this skill. Adapt `` / paths as needed. 1) Check CubeMX binary and version ```powershell $mx='C:/Program Files/STMicroelectronics/STM32Cube/STM32CubeMX/STM32CubeMX.exe' Test-Path $mx (Get-Item $mx).VersionInfo ``` 2) Set CubeMX CLI runtime (required by later commands) ```powershell $java='C:/Program Files/STMicroelectronics/STM32Cube/STM32CubeMX/jre/bin/java.exe' $jar='C:/Program Files/STMicroelectronics/STM32Cube/STM32CubeMX/STM32CubeMX.exe' ``` 3) Probe CLI command capabilities (optional, useful when syntax differs by install) ```powershell @' help project config set get generate exit '@ | Set-Content -Encoding ascii .mx_probe_cmd.txt & $java -jar $jar -q .mx_probe_cmd.txt ``` 4) Create a brand new project + IOC (empty workspace case) ```powershell @' load STM32F407ZGTx project name project toolchain CMake generate code . config saveas .ioc exit '@ | Set-Content -Encoding ascii .mx_create_cmd.txt & $java -jar $jar -q .mx_create_cmd.txt ``` 5) Configure existing IOC then regenerate code (already-created IOC case) ```powershell @' config load .ioc generate code . exit '@ | Set-Content -Encoding ascii .mx_cmd.txt & $java -jar $jar -q .mx_cmd.txt ``` 6) Apply minimum required pin/peripheral modes before regeneration ```powershell @' config load .ioc set mode RCC HSE-External-Oscillator set mode SYS Serial_Wire set mode USART2 Asynchronous set pin PH0 RCC_OSC_IN set pin PH1 RCC_OSC_OUT set pin PA13 SYS_JTMS-SWDIO set pin PA14 SYS_JTCK-SWCLK set pin PD5 USART2_TX set pin PD6 USART2_RX config save generate code . exit '@ | Set-Content -Encoding ascii .mx_set_basic_cmd.txt & $java -jar $jar -q .mx_set_basic_cmd.txt ``` 7) Apply RCC clock parameters required by this skill, then regenerate ```powershell @' config load .ioc set ip parameters RCC OscillatorType RCC_OSCILLATORTYPE_HSE set ip parameters RCC OscillatorTypeHSE RCC_OSCILLATORTYPE_HSE set ip parameters RCC HSEState RCC_HSE_ON set ip parameters RCC HSEStateARG RCC_HSE_ON set ip parameters RCC HSEUsed 1 set ip parameters RCC PLLState RCC_PLL_ON set ip parameters RCC PLLStateARG RCC_PLL_ON set ip parameters RCC PLLUsed 1 set ip parameters RCC PLLUsedForSys 1 set ip parameters RCC PLLSource RCC_PLLSOURCE_HSE set ip parameters RCC PLLSourceARG RCC_PLLSOURCE_HSE set ip parameters RCC PLLSourceVirtual RCC_PLLSOURCE_HSE set ip parameters RCC PLLM 25 set ip parameters RCC PLLN 168 set ip parameters RCC PLLP PLLP_DIV2 set ip parameters RCC PLLQ 4 set ip parameters RCC SYSCLKSource RCC_SYSCLKSOURCE_PLLCLK set ip parameters RCC SYSCLKSourceARG RCC_SYSCLKSOURCE_PLLCLK set ip parameters RCC AHBCLKDivider RCC_SYSCLK_DIV1 set ip parameters RCC AHBCLKDividerARG RCC_SYSCLK_DIV1 set ip parameters RCC APB1CLKDivider RCC_HCLK_DIV2 set ip parameters RCC APB1CLKDividerARG RCC_HCLK_DIV2 set ip parameters RCC APB2CLKDivider RCC_HCLK_DIV1 set ip parameters RCC APB2CLKDividerARG RCC_HCLK_DIV1 set ip parameters RCC FLatency FLASH_LATENCY_2 set ip parameters RCC HCLKFreq_Value 84000000 set ip parameters RCC AHBFreq_Value 84000000 set ip parameters RCC APB1Freq_Value 42000000 set ip parameters RCC APB2Freq_Value 84000000 set ip parameters RCC APB1TimFreq_Value 84000000 set ip parameters RCC APB2TimFreq_Value 84000000 set ip parameters RCC SYSCLKFreq_VALUE 84000000 set ip parameters RCC CortexFreq_Value 84000000 set ip parameters RCC FCLKCortexFreq_Value 84000000 set ip parameters RCC PLLCLKFreq_Value 84000000 set ip parameters RCC PLLQCLKFreq_Value 42000000 set ip parameters RCC VCOInputFreq_Value 1000000 set ip parameters RCC VCOOutputFreq_Value 168000000 set ip parameters RCC HSE_VALUE 25000000 set ip parameters RCC LSI_VALUE 32000 set ip parameters USART2 VirtualMode VM_ASYNC set ip parameters USART2 BaudRate 115200 set ip parameters USART2 Mode MODE_TX_RX set ip parameters USART2 OverSampling UART_OVERSAMPLING_16 config save generate code . exit '@ | Set-Content -Encoding ascii .mx_clock_uart_cmd.txt & $java -jar $jar -q .mx_clock_uart_cmd.txt ``` 7b) Apply DMA baseline using IOC `Dma.*` keys (CubeMX CLI does not accept `USART2_RxDMA/USART2_TxDMA` as valid `set ip parameters`) ```powershell $ioc='.ioc' $lines=Get-Content $ioc # Remove invalid/legacy USART2 DMA keys and existing Dma section before rewriting $lines=$lines | Where-Object { $_ -notmatch '^USART2\.USART2_RxDMA=' -and $_ -notmatch '^USART2\.USART2_TxDMA=' -and $_ -notmatch '^Dma\.' } # Keep USART2 IP parameters minimal per skill gate $lines=$lines | ForEach-Object { if($_ -match '^USART2\.IPParameters='){ 'USART2.IPParameters=VirtualMode,BaudRate,Mode,OverSampling' } elseif($_ -match '^USART2\.BaudRate='){ 'USART2.BaudRate=115200' } elseif($_ -match '^USART2\.Mode='){ 'USART2.Mode=MODE_TX_RX' } elseif($_ -match '^USART2\.OverSampling='){ 'USART2.OverSampling=UART_OVERSAMPLING_16' } elseif($_ -match '^USART2\.VirtualMode='){ 'USART2.VirtualMode=VM_ASYNC' } else { $_ } } # Ensure required USART2 fields exist if(-not ($lines -match '^USART2\.BaudRate=')){ $lines += 'USART2.BaudRate=115200' } if(-not ($lines -match '^USART2\.IPParameters=')){ $lines += 'USART2.IPParameters=VirtualMode,BaudRate,Mode,OverSampling' } if(-not ($lines -match '^USART2\.Mode=')){ $lines += 'USART2.Mode=MODE_TX_RX' } if(-not ($lines -match '^USART2\.OverSampling=')){ $lines += 'USART2.OverSampling=UART_OVERSAMPLING_16' } if(-not ($lines -match '^USART2\.VirtualMode=')){ $lines += 'USART2.VirtualMode=VM_ASYNC' } # DMA request block for USART2 RX/TX $dma=@( 'Dma.Request0=USART2_RX', 'Dma.Request1=USART2_TX', 'Dma.RequestsNb=2', 'Dma.USART2_RX.0.Direction=DMA_PERIPH_TO_MEMORY', 'Dma.USART2_RX.0.FIFOMode=DMA_FIFOMODE_DISABLE', 'Dma.USART2_RX.0.Instance=DMA1_Stream5', 'Dma.USART2_RX.0.MemDataAlignment=DMA_MDATAALIGN_BYTE', 'Dma.USART2_RX.0.MemInc=DMA_MINC_ENABLE', 'Dma.USART2_RX.0.Mode=DMA_NORMAL', 'Dma.USART2_RX.0.PeriphDataAlignment=DMA_PDATAALIGN_BYTE', 'Dma.USART2_RX.0.PeriphInc=DMA_PINC_DISABLE', 'Dma.USART2_RX.0.Priority=DMA_PRIORITY_LOW', 'Dma.USART2_RX.0.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode', 'Dma.USART2_TX.1.Direction=DMA_MEMORY_TO_PERIPH', 'Dma.USART2_TX.1.FIFOMode=DMA_FIFOMODE_DISABLE', 'Dma.USART2_TX.1.Instance=DMA1_Stream6', 'Dma.USART2_TX.1.MemDataAlignment=DMA_MDATAALIGN_BYTE', 'Dma.USART2_TX.1.MemInc=DMA_MINC_ENABLE', 'Dma.USART2_TX.1.Mode=DMA_NORMAL', 'Dma.USART2_TX.1.PeriphDataAlignment=DMA_PDATAALIGN_BYTE', 'Dma.USART2_TX.1.PeriphInc=DMA_PINC_DISABLE', 'Dma.USART2_TX.1.Priority=DMA_PRIORITY_LOW', 'Dma.USART2_TX.1.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode' ) # Place DMA block near top for readability $out=@() $inserted=$false foreach($l in $lines){ $out+=$l if(-not $inserted -and $l -eq 'CAD.provider='){ $out+=$dma $inserted=$true } } if(-not $inserted){ $out=$dma + $lines } if(-not ($out -match '^NVIC\.DMA1_Stream5_IRQn=')){ $out += 'NVIC.DMA1_Stream5_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:true' } if(-not ($out -match '^NVIC\.DMA1_Stream6_IRQn=')){ $out += 'NVIC.DMA1_Stream6_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:true' } $out | Set-Content -Encoding ascii $ioc @' config load .ioc generate code . exit '@ | Set-Content -Encoding ascii .mx_dma_fix_cmd.txt & $java -jar $jar -q .mx_dma_fix_cmd.txt ``` 8) Validate IOC can be loaded cleanly ```powershell @' config load .ioc exit '@ | Set-Content -Encoding ascii .mx_validate_cmd.txt & $java -jar $jar -q .mx_validate_cmd.txt ``` 9) Inspect workspace and key files ```powershell Get-ChildItem -Recurse -Force Get-Content -Raw .ioc rg -n "" . ``` 10) Verify generated clock/USART code quickly ```powershell rg -n "OscillatorType|HSEState|PLLState|PLLM|PLLN|PLLP|PLLQ|SYSCLKSource|APB1CLKDivider|APB2CLKDivider|FLASH_LATENCY" Src/main.c rg -n "huart2.Init.BaudRate|huart2.Init.Mode|huart2.Init.OverSampling" Src/main.c ``` 11) Configure and build with CMake ```powershell cmake --preset Debug cmake --build --preset Debug ``` 12) VS Code default build task target (Ctrl+Shift+B) ```powershell cmake --build --preset Debug ```