diff --git a/BMSv4_pincfg/SKILL.md b/BMSv4_pincfg/SKILL.md new file mode 100644 index 0000000..06347a5 --- /dev/null +++ b/BMSv4_pincfg/SKILL.md @@ -0,0 +1,192 @@ +--- +name: BMSv4_pincfg +description: Modify an existing STM32CubeMX project for BMSv4 hardware pin and peripheral settings. Use when a CubeMX `.ioc` project already exists and BMSv4 SPI3, SPISW_nCSx / SPIADC_nCSx GPIO outputs, PWM outputs, CUR_poly ADC2 inputs, and specific ADC3 inputs must be configured, code regenerated, and the build re-verified. +metadata: + author: bowei-local + version: "2.1" +compatibility: Requires an existing STM32CubeMX project, local STM32CubeMX installation, and a working CMake build in the target workspace. +--- + +# BMSv4 Pin Configuration + +Apply the BMSv4 hardware pin/peripheral configuration to an existing STM32CubeMX project. Update the `.ioc`, regenerate code with the locally installed CubeMX, then verify the project still builds. + +This skill is for modifying an existing CubeMX project only. Do not create a new project when using this skill. + +## Preconditions +- Confirm the target workspace already contains a CubeMX `.ioc` file and generated STM32 project structure. +- Confirm CubeMX exists locally and detect the installed CubeMX version before editing `.ioc` metadata. +- Keep the existing project name, MCU, clock tree, toolchain, and user code sections unless the user explicitly asks to change them. +- Preserve `ProjectManager.KeepUserCode=true`. +- Treat the existing project as the baseline. Only change configuration items explicitly described in this skill or explicitly requested by the user. +- If the user asks to modify this skill itself, update only the skill file in that turn. Do not also modify any target STM32 project or `.ioc` unless the user separately asks to apply the updated skill. + +## Required BMSv4 configuration + +### SPI3 +- Enable `SPI3`. +- Configure `SPI3` as `Half-Duplex Master`. +- Use `PC10` as `SPI3_SCK`. +- Use `PC12` as `SPI3_MOSI`. +- Disable hardware NSS and use software NSS. +- Parameters: + - Frame format: `Motorola` + - Data size: `8 Bits` + - First bit: `MSB First` + - Prescaler: `2` + - CPOL: `Low` + - CPHA: `1 Edge` + - CRC calculation: `Disabled` + +### Battery switch decoder chip selects +Configure these pins as `GPIO_Output`, label them exactly as listed, and default them to inactive high unless the user explicitly requests another reset state: + +- `PE14` -> `SPISW_nCS1` +- `PE12` -> `SPISW_nCS2` +- `PE10` -> `SPISW_nCS3` +- `PE8` -> `SPISW_nCS4` +- `PG1` -> `SPISW_nCS5` +- `PF15` -> `SPISW_nCS6` + +### Battery voltage ADC decoder chip selects +Configure these pins as `GPIO_Output`, label them exactly as listed, and default them to inactive high unless the user explicitly requests another reset state: + +- `PE13` -> `SPIADC_nCS1` +- `PE11` -> `SPIADC_nCS2` +- `PE9` -> `SPIADC_nCS3` +- `PE7` -> `SPIADC_nCS4` +- `PG0` -> `SPIADC_nCS5` +- `PF14` -> `SPIADC_nCS6` + + + + +### Current-sense ADC inputs +Configure the following six pins as `ADC2` analog inputs and label them exactly as listed: + +- `PB1` -> `ADC2_IN9` -> `CUR_poly1` +- `PB0` -> `ADC2_IN8` -> `CUR_poly2` +- `PC5` -> `ADC2_IN15` -> `CUR_poly3` +- `PC4` -> `ADC2_IN14` -> `CUR_poly4` +- `PA7` -> `ADC2_IN7` -> `CUR_poly5` +- `PA6` -> `ADC2_IN6` -> `CUR_poly6` + +Requirements for these ADC inputs: +- Configure each listed pin as `Analog`. +- Use `No pull-up and no pull-down`. +- Apply the exact labels `CUR_poly1..6`. +- Use `ADC2` for all six channels. +- Preserve any existing ADC peripheral configuration unless the user explicitly asks to change sampling sequences, trigger sources, DMA, scan mode, or conversion timing. +- If the target project does not yet enable an ADC instance for these channels, add the minimum ADC configuration required for CubeMX to keep the pin-to-channel mapping valid, without altering unrelated peripherals. +- Do not stop at pin signal mapping plus regular channel/rank fields. Add whatever CubeMX metadata the installed version requires so the ADC GUI actually shows the channels as selected. + +Required `ADC2` parameters for these inputs: +- Clock Prescaler: `PCLK2 divided by 4` +- Resolution: `12 bits` +- Data Alignment: `Right alignment` +- Scan Conversion Mode: + - keep `Disabled` when only one `CUR_poly` channel is configured into the ADC2 regular group + - set `Enabled` when multiple `CUR_poly` channels are configured into the ADC2 regular group +- Continuous Conversion Mode: `Disabled` +- Discontinuous Conversion Mode: `Disabled` +- DMA Continuous Requests: `Disabled` +- End Of Conversion Selection: `EOC flag at the end of single channel conversion` +- Number Of Conversion: set this to the number of `CUR_poly` channels actually configured into the ADC2 regular group +- External Trigger Conversion Source: `Regular Conversion launched by software` +- External Trigger Conversion Edge: `None` +- Rank: + - when one `CUR_poly` channel is configured, use `Rank = 1` + - when multiple `CUR_poly` channels are configured, assign sequential regular ranks starting at `1` +- Injected Number Of Conversions: `0` +- Enable `ADC1, ADC2 and ADC3 global interrupts` in NVIC with preemption priority `0` and sub priority `0` + +### Additional ADC3 inputs +Configure the following two pins as analog `ADC3` inputs and label them exactly as listed: + +- `PA3` -> `ADC3_IN3` -> `lt3763_cur` +- `PF5` -> `ADC3_IN15` -> `ADC_VBAT_TMP` + +Requirements for these ADC inputs (BMSv31-style ADC3 workflow): +- Configure each listed pin as `Analog`. +- Use `No pull-up and no pull-down`. +- Apply the exact labels `lt3763_cur` and `ADC_VBAT_TMP`. +- Use `ADC3` for both channels. +- Preserve any existing `ADC3` configuration unless the user explicitly asks to change sampling sequences, trigger sources, DMA, scan mode, or conversion timing. +- If the target project does not yet enable an `ADC3` instance for these channels, add the minimum ADC configuration required for CubeMX to keep the pin-to-channel mapping valid, without altering unrelated peripherals. +- Keep pin mapping for both channels, but do not require both channels to be simultaneously configured in the ADC3 regular group. +- Treat `ADC3_IN15` specially on `STM32F407ZGTx`: `PF5 -> ADC3_IN15` is a valid ADC3-only pin mapping in the device database, and it must not be modeled using the same shared-signal metadata pattern as `ADC2_IN15` on `PC5`. +- Do not reuse `SH.ADCx_IN15` entries that belong to `ADC1/ADC2` when configuring `PF5 -> ADC3_IN15`. If the installed CubeMX version uses a different metadata representation for ADC3-only `IN15`, preserve or generate that exact representation instead of forcing it into the ADC1/ADC2 shared-signal format. +- ADC3 working mode must follow BMSv31 style: + - initialize ADC3 as single regular conversion (`Scan Conversion Mode = Disabled`, `Number Of Conversion = 1`, `Rank = 1`) + - keep `Continuous Conversion Mode = Disabled` + - keep `Discontinuous Conversion Mode = Disabled` + - keep `DMA Continuous Requests = Disabled` + - keep `End Of Conversion Selection = EOC flag at the end of single channel conversion` + - use software trigger (`External Trigger Conversion Source = Regular Conversion launched by software`, `External Trigger Conversion Edge = None`) + - do channel selection at runtime by reconfiguring `sConfig.Channel` before each conversion (e.g. switch between `ADC_CHANNEL_3` and `ADC_CHANNEL_15`) + +## Execution steps +1. Detect the local CubeMX version and confirm the project `.ioc` header is not stamped with a newer version than the installed tool. +2. Open the existing `.ioc` project. Do not replace it with a newly created project. +3. Compare the existing project configuration against the configuration explicitly listed in this skill. +4. Modify only the listed configuration items that differ: + - the `SPI3` mode and parameters listed above + - the twelve named GPIO output definitions listed above + - the six PWM pin assignments, timer channel mappings, timer base settings, and default duty-cycle settings listed above + - the six `CUR_poly` ADC input pin assignments, analog modes, labels, required ADC2 channel mappings, and ADC parameters listed above + - the two additional `ADC3` input pin assignments, analog modes, labels, and required ADC3 channel mappings listed above + - when configuring ADC inputs, also add the CubeMX shared-signal metadata required by the installed version so the ADC page shows the intended `INx` entries as selected + - when configuring `PF5 -> ADC3_IN15`, verify against the local device database that the mapping is ADC3-only and do not alias it to the `ADC1/ADC2 IN15` shared-signal entry used by `PC5` + - for ADC3, keep the two pin mappings but configure ADC3 peripheral as single-conversion runtime-switch mode (BMSv31 style), not fixed multi-channel scan sequence +5. Keep every other existing project configuration unchanged if it is not explicitly covered by this skill, including unrelated peripherals, clocks, middleware, pins, NVIC settings, DMA settings, and user code. +6. If any requested pin conflicts with an existing peripheral assignment, stop and report the conflict instead of silently remapping the hardware. +7. Regenerate code using the installed CubeMX while preserving user code sections. + - This is mandatory after any `.ioc` change. Do not skip regeneration. +8. Validate the generated result before finishing: + - `Core/Src/spi.c` contains `MX_SPI3_Init()` with `SPI_DIRECTION_1LINE`, master mode, prescaler `2`, `SPI_POLARITY_LOW`, `SPI_PHASE_1EDGE`, software NSS, and CRC disabled. + - `Core/Src/gpio.c` initializes the required `GPIOE`, `GPIOF`, and `GPIOG` chip-select pins as outputs. + - `Core/Inc/main.h` exports the requested pin names and ports. + - `Core/Src/tim.c` contains `MX_TIM1_Init()` and `MX_TIM3_Init()` with a `10 kHz` PWM base derived from the project timer clocks. + - The generated compare values default to `50%` duty cycle for `pwm_polyctl1..6`. + - The generated GPIO/pin metadata maps `PA9`, `PA8`, `PC9`, `PC8`, `PC7`, and `PC6` to the requested timer channels. + - The generated GPIO/pin metadata maps `PB1`, `PB0`, `PC5`, `PC4`, `PA7`, and `PA6` to `ADC2_IN9`, `ADC2_IN8`, `ADC2_IN15`, `ADC2_IN14`, `ADC2_IN7`, and `ADC2_IN6` with labels `CUR_poly1..6`. + - The generated GPIO/pin metadata maps `PA3` and `PF5` to `ADC3_IN3` and `ADC3_IN15` with labels `lt3763_cur` and `ADC_VBAT_TMP`. + - The generated ADC configuration matches the required `ADC2` settings: `PCLK2/4`, `12-bit`, right alignment, continuous disabled, discontinuous disabled, DMA continuous requests disabled, single-channel EOC, software trigger, trigger edge none, and injected conversions `0`. + - The ADC2 regular group explicitly includes the requested `CUR_poly` channels rather than only setting the pins to analog input mode. + - `Scan Conversion Mode`, `Number Of Conversion`, and the regular channel `Rank` values are adjusted to match the number of `CUR_poly` channels actually configured in ADC2. + - The `.ioc` contains the CubeMX shared ADC signal metadata needed for the locally installed version to render the requested ADC2 inputs as selected in the GUI, not just low-level regular channel fields. + - Re-open or re-load the `.ioc` with the installed CubeMX and confirm the ADC GUI shows the expected `ADC2` input selections instead of leaving the `INx` list unchecked. + - The `.ioc` contains the CubeMX shared ADC signal metadata needed for the locally installed version to render the requested ADC3 inputs as selected in the GUI, not just low-level pin signal fields. + - Re-open or re-load the `.ioc` with the installed CubeMX and confirm `PA3 -> ADC3_IN3` and `PF5 -> ADC3_IN15` pin mappings are preserved without pin-level conflict warnings. + - `Core/Src/adc.c` (or generated ADC3 init code) uses single regular conversion style for ADC3: scan disabled and number-of-conversion = 1. + - ADC3 channel usage follows runtime channel reconfiguration style instead of fixed two-channel scan sequence. + - `ADC3` `IN15` metadata must not overwrite or corrupt the existing `ADC2_IN15` representation used for `PC5`. + - The generated GPIO settings for the six ADC pins remain `Analog mode` with `No pull-up and no pull-down`. + - The generated GPIO settings for `PA3` and `PF5` remain `Analog mode` with `No pull-up and no pull-down`. + - The NVIC enables `ADC1, ADC2 and ADC3 global interrupts` with preemption priority `0` and sub priority `0`. + - If CubeMX generated or updated ADC init code, it does not silently remove unrelated existing ADC settings outside the channels required for `CUR_poly1..6`, `lt3763_cur`, and `ADC_VBAT_TMP`. + - The `.ioc` still opens in the locally installed CubeMX version. +9. Run `cmake --preset Debug`. +10. Run `cmake --build --preset Debug`. +11. Confirm the expected ELF exists under `build/Debug/`. +12. Treat the task as failed if code generation was not executed or if build is not successful. Do not report completion in that case. + +## Notes & guardrails +- Do not infer CubeMX compatibility from memory. Detect the installed version each time. +- Do not hand-edit generated C source first and then try to backfill the `.ioc`; the `.ioc` is the source of truth. +- Do not treat missing detail in this skill as permission to normalize or simplify the rest of the project. +- Do not remove or rewrite existing project configuration that is outside the explicit scope of this skill. +- Do not rename the GPIO labels. They must remain `SPISW_nCS1..6` and `SPIADC_nCS1..6`. +- Do not rename the ADC labels. They must remain `CUR_poly1..6`. +- Do not rename the additional ADC3 labels. They must remain `lt3763_cur` and `ADC_VBAT_TMP`. +- Do not guess PWM frequency parameters from screenshots alone. Derive PSC/ARR/CCR from the actual timer clock in the target project. +- Do not invent ADC parameters that are not explicitly shown or requested; keep unspecified ADC timing details at the generated or pre-existing values unless the user later constrains them. +- Do not leave ADC2 half-configured. It is not sufficient to set only pin analog mode and `ADC2_INx` signal mapping; the required regular ADC2 channels must also be present in the ADC2 configuration. +- Do not leave ADC3 half-configured. It is not sufficient to set only pin analog mode and `ADC3_INx` signal mapping; add the minimum ADC3 configuration and metadata needed for CubeMX to keep and display the requested channels. +- Do not force ADC3 into fixed multi-channel scan mode for these two channels when BMSv31-style behavior is requested. +- Do not assume `ADCx_IN15` metadata is interchangeable across ADC instances on this MCU family. `ADC2_IN15` on `PC5` and `ADC3_IN15` on `PF5` may require different `.ioc` representations. +- Do not add extra ADC channels, sampling logic, or conversion sequencing beyond what is needed to preserve the requested `CUR_poly1..6`, `lt3763_cur`, and `ADC_VBAT_TMP` pin mappings. +- For `_nCS` lines, prefer reset state high so external devices stay deselected after boot. +- If CubeMX generation removes or rewrites required user code outside the modified peripherals, stop and report before making manual source patches. +- If the project uses a non-`Debug` preset name, keep the workspace's existing preset strategy, but still verify a full configure + build path before finishing. +- Do not mark the task complete unless both conditions are met: CubeMX code generation completed successfully, and the project build completed successfully. diff --git a/BMSv4_pincfg/SKILL.md.bak b/BMSv4_pincfg/SKILL.md.bak new file mode 100644 index 0000000..f61a277 --- /dev/null +++ b/BMSv4_pincfg/SKILL.md.bak @@ -0,0 +1,213 @@ +--- +name: BMSv4_pincfg +description: Modify an existing STM32CubeMX project for BMSv4 hardware pin and peripheral settings. Use when a CubeMX `.ioc` project already exists and BMSv4 SPI3, SPISW_nCSx / SPIADC_nCSx GPIO outputs, PWM outputs, CUR_poly ADC2 inputs, and specific ADC3 inputs must be configured, code regenerated, and the build re-verified. +metadata: + author: bowei-local + version: "2.1" +compatibility: Requires an existing STM32CubeMX project, local STM32CubeMX installation, and a working CMake build in the target workspace. +--- + +# BMSv4 Pin Configuration + +Apply the BMSv4 hardware pin/peripheral configuration to an existing STM32CubeMX project. Update the `.ioc`, regenerate code with the locally installed CubeMX, then verify the project still builds. + +This skill is for modifying an existing CubeMX project only. Do not create a new project when using this skill. + +## Preconditions +- Confirm the target workspace already contains a CubeMX `.ioc` file and generated STM32 project structure. +- Confirm CubeMX exists locally and detect the installed CubeMX version before editing `.ioc` metadata. +- Keep the existing project name, MCU, clock tree, toolchain, and user code sections unless the user explicitly asks to change them. +- Preserve `ProjectManager.KeepUserCode=true`. +- Treat the existing project as the baseline. Only change configuration items explicitly described in this skill or explicitly requested by the user. +- If the user asks to modify this skill itself, update only the skill file in that turn. Do not also modify any target STM32 project or `.ioc` unless the user separately asks to apply the updated skill. + +## Required BMSv4 configuration + +### SPI3 +- Enable `SPI3`. +- Configure `SPI3` as `Half-Duplex Master`. +- Use `PC10` as `SPI3_SCK`. +- Use `PC12` as `SPI3_MOSI`. +- Disable hardware NSS and use software NSS. +- Parameters: + - Frame format: `Motorola` + - Data size: `8 Bits` + - First bit: `MSB First` + - Prescaler: `2` + - CPOL: `Low` + - CPHA: `1 Edge` + - CRC calculation: `Disabled` + +### Battery switch decoder chip selects +Configure these pins as `GPIO_Output`, label them exactly as listed, and default them to inactive high unless the user explicitly requests another reset state: + +- `PE14` -> `SPISW_nCS1` +- `PE12` -> `SPISW_nCS2` +- `PE10` -> `SPISW_nCS3` +- `PE8` -> `SPISW_nCS4` +- `PG1` -> `SPISW_nCS5` +- `PF15` -> `SPISW_nCS6` + +### Battery voltage ADC decoder chip selects +Configure these pins as `GPIO_Output`, label them exactly as listed, and default them to inactive high unless the user explicitly requests another reset state: + +- `PE13` -> `SPIADC_nCS1` +- `PE11` -> `SPIADC_nCS2` +- `PE9` -> `SPIADC_nCS3` +- `PE7` -> `SPIADC_nCS4` +- `PG0` -> `SPIADC_nCS5` +- `PF14` -> `SPIADC_nCS6` + +### PWM outputs +Configure the following pins as timer PWM outputs and label them exactly as listed: + +- `PA9` -> `TIM1_CH2` -> `pwm_polyctl1` +- `PA8` -> `TIM1_CH1` -> `pwm_polyctl2` +- `PC9` -> `TIM3_CH4` -> `pwm_polyctl3` +- `PC8` -> `TIM3_CH3` -> `pwm_polyctl4` +- `PC7` -> `TIM3_CH2` -> `pwm_polyctl5` +- `PC6` -> `TIM3_CH1` -> `pwm_polyctl6` + +Use PWM output mode with configurable duty cycle. Default duty cycle must be `50%`. + +Timer settings for both `TIM1` and `TIM3`: +- Clock source: `Internal Clock` +- PWM frequency: `10 kHz` +- Compute timer parameters from the existing project clocks instead of guessing +- For the standard `STM32F407ZGTx` clock tree used in this workspace, `TIM1` and `TIM3` both see an `84 MHz` timer clock, so use: + - Prescaler `PSC = 83` + - Counter Period `ARR = 99` + - Default Pulse `CCR = 50` +- Keep counter mode `Up` +- Keep clock division `No Division` +- Keep repetition counter `0` unless the selected timer requires a different default generated by CubeMX + +### Current-sense ADC inputs +Configure the following six pins as `ADC2` analog inputs and label them exactly as listed: + +- `PB1` -> `ADC2_IN9` -> `CUR_poly1` +- `PB0` -> `ADC2_IN8` -> `CUR_poly2` +- `PC5` -> `ADC2_IN15` -> `CUR_poly3` +- `PC4` -> `ADC2_IN14` -> `CUR_poly4` +- `PA7` -> `ADC2_IN7` -> `CUR_poly5` +- `PA6` -> `ADC2_IN6` -> `CUR_poly6` + +Requirements for these ADC inputs: +- Configure each listed pin as `Analog`. +- Use `No pull-up and no pull-down`. +- Apply the exact labels `CUR_poly1..6`. +- Use `ADC2` for all six channels. +- Preserve any existing ADC peripheral configuration unless the user explicitly asks to change sampling sequences, trigger sources, DMA, scan mode, or conversion timing. +- If the target project does not yet enable an ADC instance for these channels, add the minimum ADC configuration required for CubeMX to keep the pin-to-channel mapping valid, without altering unrelated peripherals. +- Do not stop at pin signal mapping plus regular channel/rank fields. Add whatever CubeMX metadata the installed version requires so the ADC GUI actually shows the channels as selected. + +Required `ADC2` parameters for these inputs: +- Clock Prescaler: `PCLK2 divided by 4` +- Resolution: `12 bits` +- Data Alignment: `Right alignment` +- Scan Conversion Mode: + - keep `Disabled` when only one `CUR_poly` channel is configured into the ADC2 regular group + - set `Enabled` when multiple `CUR_poly` channels are configured into the ADC2 regular group +- Continuous Conversion Mode: `Disabled` +- Discontinuous Conversion Mode: `Disabled` +- DMA Continuous Requests: `Disabled` +- End Of Conversion Selection: `EOC flag at the end of single channel conversion` +- Number Of Conversion: set this to the number of `CUR_poly` channels actually configured into the ADC2 regular group +- External Trigger Conversion Source: `Regular Conversion launched by software` +- External Trigger Conversion Edge: `None` +- Rank: + - when one `CUR_poly` channel is configured, use `Rank = 1` + - when multiple `CUR_poly` channels are configured, assign sequential regular ranks starting at `1` +- Injected Number Of Conversions: `0` +- Enable `ADC1, ADC2 and ADC3 global interrupts` in NVIC with preemption priority `0` and sub priority `0` + +### Additional ADC3 inputs +Configure the following two pins as analog `ADC3` inputs and label them exactly as listed: + +- `PA3` -> `ADC3_IN3` -> `lt3763_cur` +- `PF5` -> `ADC3_IN15` -> `ADC_VBAT_TMP` + +Requirements for these ADC inputs (BMSv31-style ADC3 workflow): +- Configure each listed pin as `Analog`. +- Use `No pull-up and no pull-down`. +- Apply the exact labels `lt3763_cur` and `ADC_VBAT_TMP`. +- Use `ADC3` for both channels. +- Preserve any existing `ADC3` configuration unless the user explicitly asks to change sampling sequences, trigger sources, DMA, scan mode, or conversion timing. +- If the target project does not yet enable an `ADC3` instance for these channels, add the minimum ADC configuration required for CubeMX to keep the pin-to-channel mapping valid, without altering unrelated peripherals. +- Keep pin mapping for both channels, but do not require both channels to be simultaneously configured in the ADC3 regular group. +- Treat `ADC3_IN15` specially on `STM32F407ZGTx`: `PF5 -> ADC3_IN15` is a valid ADC3-only pin mapping in the device database, and it must not be modeled using the same shared-signal metadata pattern as `ADC2_IN15` on `PC5`. +- Do not reuse `SH.ADCx_IN15` entries that belong to `ADC1/ADC2` when configuring `PF5 -> ADC3_IN15`. If the installed CubeMX version uses a different metadata representation for ADC3-only `IN15`, preserve or generate that exact representation instead of forcing it into the ADC1/ADC2 shared-signal format. +- ADC3 working mode must follow BMSv31 style: + - initialize ADC3 as single regular conversion (`Scan Conversion Mode = Disabled`, `Number Of Conversion = 1`, `Rank = 1`) + - keep `Continuous Conversion Mode = Disabled` + - keep `Discontinuous Conversion Mode = Disabled` + - keep `DMA Continuous Requests = Disabled` + - keep `End Of Conversion Selection = EOC flag at the end of single channel conversion` + - use software trigger (`External Trigger Conversion Source = Regular Conversion launched by software`, `External Trigger Conversion Edge = None`) + - do channel selection at runtime by reconfiguring `sConfig.Channel` before each conversion (e.g. switch between `ADC_CHANNEL_3` and `ADC_CHANNEL_15`) + +## Execution steps +1. Detect the local CubeMX version and confirm the project `.ioc` header is not stamped with a newer version than the installed tool. +2. Open the existing `.ioc` project. Do not replace it with a newly created project. +3. Compare the existing project configuration against the configuration explicitly listed in this skill. +4. Modify only the listed configuration items that differ: + - the `SPI3` mode and parameters listed above + - the twelve named GPIO output definitions listed above + - the six PWM pin assignments, timer channel mappings, timer base settings, and default duty-cycle settings listed above + - the six `CUR_poly` ADC input pin assignments, analog modes, labels, required ADC2 channel mappings, and ADC parameters listed above + - the two additional `ADC3` input pin assignments, analog modes, labels, and required ADC3 channel mappings listed above + - when configuring ADC inputs, also add the CubeMX shared-signal metadata required by the installed version so the ADC page shows the intended `INx` entries as selected + - when configuring `PF5 -> ADC3_IN15`, verify against the local device database that the mapping is ADC3-only and do not alias it to the `ADC1/ADC2 IN15` shared-signal entry used by `PC5` + - for ADC3, keep the two pin mappings but configure ADC3 peripheral as single-conversion runtime-switch mode (BMSv31 style), not fixed multi-channel scan sequence +5. Keep every other existing project configuration unchanged if it is not explicitly covered by this skill, including unrelated peripherals, clocks, middleware, pins, NVIC settings, DMA settings, and user code. +6. If any requested pin conflicts with an existing peripheral assignment, stop and report the conflict instead of silently remapping the hardware. +7. Regenerate code using the installed CubeMX while preserving user code sections. + - This is mandatory after any `.ioc` change. Do not skip regeneration. +8. Validate the generated result before finishing: + - `Core/Src/spi.c` contains `MX_SPI3_Init()` with `SPI_DIRECTION_1LINE`, master mode, prescaler `2`, `SPI_POLARITY_LOW`, `SPI_PHASE_1EDGE`, software NSS, and CRC disabled. + - `Core/Src/gpio.c` initializes the required `GPIOE`, `GPIOF`, and `GPIOG` chip-select pins as outputs. + - `Core/Inc/main.h` exports the requested pin names and ports. + - `Core/Src/tim.c` contains `MX_TIM1_Init()` and `MX_TIM3_Init()` with a `10 kHz` PWM base derived from the project timer clocks. + - The generated compare values default to `50%` duty cycle for `pwm_polyctl1..6`. + - The generated GPIO/pin metadata maps `PA9`, `PA8`, `PC9`, `PC8`, `PC7`, and `PC6` to the requested timer channels. + - The generated GPIO/pin metadata maps `PB1`, `PB0`, `PC5`, `PC4`, `PA7`, and `PA6` to `ADC2_IN9`, `ADC2_IN8`, `ADC2_IN15`, `ADC2_IN14`, `ADC2_IN7`, and `ADC2_IN6` with labels `CUR_poly1..6`. + - The generated GPIO/pin metadata maps `PA3` and `PF5` to `ADC3_IN3` and `ADC3_IN15` with labels `lt3763_cur` and `ADC_VBAT_TMP`. + - The generated ADC configuration matches the required `ADC2` settings: `PCLK2/4`, `12-bit`, right alignment, continuous disabled, discontinuous disabled, DMA continuous requests disabled, single-channel EOC, software trigger, trigger edge none, and injected conversions `0`. + - The ADC2 regular group explicitly includes the requested `CUR_poly` channels rather than only setting the pins to analog input mode. + - `Scan Conversion Mode`, `Number Of Conversion`, and the regular channel `Rank` values are adjusted to match the number of `CUR_poly` channels actually configured in ADC2. + - The `.ioc` contains the CubeMX shared ADC signal metadata needed for the locally installed version to render the requested ADC2 inputs as selected in the GUI, not just low-level regular channel fields. + - Re-open or re-load the `.ioc` with the installed CubeMX and confirm the ADC GUI shows the expected `ADC2` input selections instead of leaving the `INx` list unchecked. + - The `.ioc` contains the CubeMX shared ADC signal metadata needed for the locally installed version to render the requested ADC3 inputs as selected in the GUI, not just low-level pin signal fields. + - Re-open or re-load the `.ioc` with the installed CubeMX and confirm `PA3 -> ADC3_IN3` and `PF5 -> ADC3_IN15` pin mappings are preserved without pin-level conflict warnings. + - `Core/Src/adc.c` (or generated ADC3 init code) uses single regular conversion style for ADC3: scan disabled and number-of-conversion = 1. + - ADC3 channel usage follows runtime channel reconfiguration style instead of fixed two-channel scan sequence. + - `ADC3` `IN15` metadata must not overwrite or corrupt the existing `ADC2_IN15` representation used for `PC5`. + - The generated GPIO settings for the six ADC pins remain `Analog mode` with `No pull-up and no pull-down`. + - The generated GPIO settings for `PA3` and `PF5` remain `Analog mode` with `No pull-up and no pull-down`. + - The NVIC enables `ADC1, ADC2 and ADC3 global interrupts` with preemption priority `0` and sub priority `0`. + - If CubeMX generated or updated ADC init code, it does not silently remove unrelated existing ADC settings outside the channels required for `CUR_poly1..6`, `lt3763_cur`, and `ADC_VBAT_TMP`. + - The `.ioc` still opens in the locally installed CubeMX version. +9. Run `cmake --preset Debug`. +10. Run `cmake --build --preset Debug`. +11. Confirm the expected ELF exists under `build/Debug/`. +12. Treat the task as failed if code generation was not executed or if build is not successful. Do not report completion in that case. + +## Notes & guardrails +- Do not infer CubeMX compatibility from memory. Detect the installed version each time. +- Do not hand-edit generated C source first and then try to backfill the `.ioc`; the `.ioc` is the source of truth. +- Do not treat missing detail in this skill as permission to normalize or simplify the rest of the project. +- Do not remove or rewrite existing project configuration that is outside the explicit scope of this skill. +- Do not rename the GPIO labels. They must remain `SPISW_nCS1..6` and `SPIADC_nCS1..6`. +- Do not rename the ADC labels. They must remain `CUR_poly1..6`. +- Do not rename the additional ADC3 labels. They must remain `lt3763_cur` and `ADC_VBAT_TMP`. +- Do not guess PWM frequency parameters from screenshots alone. Derive PSC/ARR/CCR from the actual timer clock in the target project. +- Do not invent ADC parameters that are not explicitly shown or requested; keep unspecified ADC timing details at the generated or pre-existing values unless the user later constrains them. +- Do not leave ADC2 half-configured. It is not sufficient to set only pin analog mode and `ADC2_INx` signal mapping; the required regular ADC2 channels must also be present in the ADC2 configuration. +- Do not leave ADC3 half-configured. It is not sufficient to set only pin analog mode and `ADC3_INx` signal mapping; add the minimum ADC3 configuration and metadata needed for CubeMX to keep and display the requested channels. +- Do not force ADC3 into fixed multi-channel scan mode for these two channels when BMSv31-style behavior is requested. +- Do not assume `ADCx_IN15` metadata is interchangeable across ADC instances on this MCU family. `ADC2_IN15` on `PC5` and `ADC3_IN15` on `PF5` may require different `.ioc` representations. +- Do not add extra ADC channels, sampling logic, or conversion sequencing beyond what is needed to preserve the requested `CUR_poly1..6`, `lt3763_cur`, and `ADC_VBAT_TMP` pin mappings. +- For `_nCS` lines, prefer reset state high so external devices stay deselected after boot. +- If CubeMX generation removes or rewrites required user code outside the modified peripherals, stop and report before making manual source patches. +- If the project uses a non-`Debug` preset name, keep the workspace's existing preset strategy, but still verify a full configure + build path before finishing. +- Do not mark the task complete unless both conditions are met: CubeMX code generation completed successfully, and the project build completed successfully. diff --git a/cubemx-min-prj/BMSv4.ioc b/cubemx-min-prj/BMSv4.ioc new file mode 100644 index 0000000..da932d1 --- /dev/null +++ b/cubemx-min-prj/BMSv4.ioc @@ -0,0 +1,152 @@ +#MicroXplorer Configuration settings - do not modify +CAD.formats= +CAD.pinconfig= +CAD.provider= +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 +File.Version=6 +GPIO.groupedBy=Group By Peripherals +KeepUserPlacement=false +Mcu.CPN=STM32F407ZGT6 +Mcu.Family=STM32F4 +Mcu.IP0=DMA +Mcu.IP1=NVIC +Mcu.IP2=RCC +Mcu.IP3=SYS +Mcu.IP4=USART2 +Mcu.IPNb=5 +Mcu.Name=STM32F407Z(E-G)Tx +Mcu.Package=LQFP144 +Mcu.Pin0=PH0-OSC_IN +Mcu.Pin1=PH1-OSC_OUT +Mcu.Pin2=PA13 +Mcu.Pin3=PA14 +Mcu.Pin4=PD5 +Mcu.Pin5=PD6 +Mcu.PinsNb=6 +Mcu.ThirdPartyNb=0 +Mcu.UserConstants= +Mcu.UserName=STM32F407ZGTx +MxCube.Version=6.11.1 +MxDb.Version=DB.6.0.111 +NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.DMA1_Stream5_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:true +NVIC.DMA1_Stream6_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:true +NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.ForceEnableDMAVector=true +NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4 +NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:false\:true\:false +NVIC.USART2_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:true +NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +PA13.Mode=Serial_Wire +PA13.Signal=SYS_JTMS-SWDIO +PA14.Mode=Serial_Wire +PA14.Signal=SYS_JTCK-SWCLK +PD5.Mode=Asynchronous +PD5.Signal=USART2_TX +PD6.Mode=Asynchronous +PD6.Signal=USART2_RX +PH0-OSC_IN.Mode=HSE-External-Oscillator +PH0-OSC_IN.Signal=RCC_OSC_IN +PH1-OSC_OUT.Mode=HSE-External-Oscillator +PH1-OSC_OUT.Signal=RCC_OSC_OUT +PinOutPanel.RotationAngle=0 +ProjectManager.AskForMigrate=true +ProjectManager.BackupPrevious=false +ProjectManager.CompilerOptimize=6 +ProjectManager.ComputerToolchain=false +ProjectManager.CoupleFile=true +ProjectManager.CustomerFirmwarePackage= +ProjectManager.DefaultFWLocation=true +ProjectManager.DeletePrevious=true +ProjectManager.DeviceId=STM32F407ZGTx +ProjectManager.FirmwarePackage=STM32Cube FW_F4 V1.28.3 +ProjectManager.FreePins=false +ProjectManager.HalAssertFull=false +ProjectManager.HeapSize=0x200 +ProjectManager.KeepUserCode=true +ProjectManager.LastFirmware=true +ProjectManager.LibraryCopy=1 +ProjectManager.MainLocation=Core/Src +ProjectManager.NoMain=false +ProjectManager.PreviousToolchain= +ProjectManager.ProjectBuild=false +ProjectManager.ProjectFileName=BMSv4.ioc +ProjectManager.ProjectName=BMSv4 +ProjectManager.ProjectStructure= +ProjectManager.RegisterCallBack= +ProjectManager.StackSize=0x400 +ProjectManager.TargetToolchain=CMake +ProjectManager.ToolChainLocation= +ProjectManager.UAScriptAfterPath= +ProjectManager.UAScriptBeforePath= +ProjectManager.UnderRoot=false +ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_DMA_Init-DMA-false-HAL-true,4-MX_USART2_UART_Init-USART2-false-HAL-true +RCC.48MHZClocksFreq_Value=42000000 +RCC.AHBFreq_Value=84000000 +RCC.APB1CLKDivider=RCC_HCLK_DIV2 +RCC.APB1Freq_Value=42000000 +RCC.APB1TimFreq_Value=84000000 +RCC.APB2CLKDivider=RCC_HCLK_DIV1 +RCC.APB2Freq_Value=84000000 +RCC.APB2TimFreq_Value=84000000 +RCC.CortexFreq_Value=84000000 +RCC.EthernetFreq_Value=84000000 +RCC.FCLKCortexFreq_Value=84000000 +RCC.FCLKFreq_Value=84000000 +RCC.FamilyName=M +RCC.HCLKFreq_Value=84000000 +RCC.HSE_VALUE=25000000 +RCC.HSI_VALUE=16000000 +RCC.I2SClocksFreq_Value=96000000 +RCC.IPParameters=48MHZClocksFreq_Value,AHBFreq_Value,APB1CLKDivider,APB1Freq_Value,APB1TimFreq_Value,APB2CLKDivider,APB2Freq_Value,APB2TimFreq_Value,CortexFreq_Value,EthernetFreq_Value,FCLKCortexFreq_Value,FCLKFreq_Value,FamilyName,HCLKFreq_Value,HSE_VALUE,HSI_VALUE,I2SClocksFreq_Value,LSE_VALUE,LSI_VALUE,MCO2PinFreq_Value,PLLCLKFreq_Value,PLLM,PLLN,PLLP,PLLQ,PLLQCLKFreq_Value,PLLSourceVirtual,RTCFreq_Value,RTCHSEDivFreq_Value,SYSCLKFreq_VALUE,SYSCLKSource,VCOI2SOutputFreq_Value,VCOInputFreq_Value,VCOOutputFreq_Value,VcooutputI2S +RCC.LSE_VALUE=32768 +RCC.LSI_VALUE=32000 +RCC.MCO2PinFreq_Value=84000000 +RCC.PLLCLKFreq_Value=84000000 +RCC.PLLM=25 +RCC.PLLN=168 +RCC.PLLP=RCC_PLLP_DIV2 +RCC.PLLQ=4 +RCC.PLLQCLKFreq_Value=42000000 +RCC.PLLSourceVirtual=RCC_PLLSOURCE_HSE +RCC.RTCFreq_Value=32000 +RCC.RTCHSEDivFreq_Value=12500000 +RCC.SYSCLKFreq_VALUE=84000000 +RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK +RCC.VCOI2SOutputFreq_Value=192000000 +RCC.VCOInputFreq_Value=1000000 +RCC.VCOOutputFreq_Value=168000000 +RCC.VcooutputI2S=96000000 +USART2.BaudRate=115200 +USART2.IPParameters=VirtualMode,BaudRate,Mode,OverSampling +USART2.Mode=MODE_TX_RX +USART2.OverSampling=UART_OVERSAMPLING_16 +USART2.VirtualMode=VM_ASYNC +board=custom diff --git a/cubemx-min-prj/DEBUG_SETUP.md b/cubemx-min-prj/DEBUG_SETUP.md new file mode 100644 index 0000000..555ff74 --- /dev/null +++ b/cubemx-min-prj/DEBUG_SETUP.md @@ -0,0 +1,100 @@ +# VS Code Debug Setup + +Use this guide when the reproduction workspace must be flashable and debuggable in VS Code with ST-Link and Cortex-Debug. + +## Expected local prerequisites + +- `STM32CubeCLT` installed locally +- `marus25.cortex-debug` extension available in VS Code +- `STM32_Programmer_CLI` on `PATH` or otherwise discoverable by VS Code tasks + +## 1. `.vscode/settings.json` + +Keep the active CMake preset on `Debug` and point VS Code to the local CubeCLT root. + +```json +{ + "files.associations": { + "tcp_client.h": "c", + "lwip.h": "c", + "ethernetif.h": "c" + }, + "cmake.configurePreset": "Debug", + "cmake.buildPreset": "Debug", + "STM32VSCodeExtension.cubeCLT.path": "C:/ST/STM32CubeCLT_1.19.0" +} +``` + +## 2. `.vscode/tasks.json` + +Provide three tasks: + +- `CMake: clean rebuild` +- `CubeProg: Flash project (SWD)` +- `Build + Flash` + +Use `${command:cmake.launchTargetPath}` for the download path so the task follows the active target. + +## 3. `.vscode/launch.json` + +Create both launch and attach profiles with: + +- `type: "cortex-debug"` +- `servertype: "stlink"` +- `device: "STM32F407ZGTx"` +- `interface: "swd"` +- `runToEntryPoint: "main"` +- `serverArgs: ["-m", "0"]` + +Point `executable` at the reproduction ELF. For this skill's default example: + +```json +"executable": "${workspaceFolder}/build/Debug/BMSv4.elf" +``` + +Keep all tool paths derived from `STM32VSCodeExtension.cubeCLT.path`: + +- `serverpath` +- `stm32cubeprogrammer` +- `stlinkPath` +- `armToolchainPath` +- `gdbPath` +- `svdFile` + +## 4. `.vscode/c_cpp_properties.json` + +Use the CMake Tools provider instead of hardcoded include paths. + +```json +{ + "version": 4, + "configurations": [ + { + "name": "STM32", + "configurationProvider": "ms-vscode.cmake-tools", + "intelliSenseMode": "${default}" + } + ] +} +``` + +## 5. `.vscode/extensions.json` + +Recommend, at minimum: + +- `ms-vscode.cpptools-extension-pack` +- `ms-vscode.cmake-tools` +- `marus25.cortex-debug` +- `mcu-debug.debug-tracker-vscode` +- `mcu-debug.memory-view` +- `mcu-debug.peripheral-viewer` +- `mcu-debug.rtos-views` + +Add project-specific editor helpers only if they are already part of the source workflow. + +## 6. Final checks + +- `cmake --build --preset Debug` succeeds before debugging. +- VS Code resolves `${command:cmake.launchTargetPath}` to the expected ELF. +- ST-Link GDB server starts without path errors. +- Flash task uses the same ELF that the debug configuration launches. diff --git a/cubemx-min-prj/REPRODUCTION_GUIDE.md b/cubemx-min-prj/REPRODUCTION_GUIDE.md new file mode 100644 index 0000000..f55d81e --- /dev/null +++ b/cubemx-min-prj/REPRODUCTION_GUIDE.md @@ -0,0 +1,167 @@ +# STM32CubeMX Minimal Reproduction Guide + +Use this guide when the task is to recreate the known `BMSv4` minimal project for `STM32F407ZGTx` in a clean workspace and prove that the generated project still builds. + +## Scope + +- CubeMX version: `6.11.1` +- MCU: `STM32F407ZGTx` +- Project name: `BMSv4` +- Toolchain: `CMake` +- Output folder: default to `/reproduction` + +## 1. Verify tools + +Use explicit local paths for CubeMX and fail early if they do not exist. + +```powershell +$mxRoot = "C:/Program Files/STMicroelectronics/STM32Cube/STM32CubeMX" +$mxExe = Join-Path $mxRoot "STM32CubeMX.exe" +$javaExe = Join-Path $mxRoot "jre/bin/java.exe" + +$mxInfo = Get-Item $mxExe | Select-Object FullName,@{N="Version";E={$_.VersionInfo.ProductVersion}} +$mxInfo + +if ($mxInfo.Version -notmatch '^6\.11\.1(?:-.+)?$') { + throw "Unsupported STM32CubeMX version: $($mxInfo.Version). Required: 6.11.1 or 6.11.1-*" +} +``` + +If the version is not `6.11.1` or `6.11.1-*`, stop immediately. Do not create the project, patch the `.ioc`, or generate code. + +## 2. Create the base project + +Generate the initial `.ioc` from CubeMX CLI instead of copying an existing project. + +```powershell +$workspace = (Get-Location).Path +$projDir = Join-Path $workspace "reproduction" + +New-Item -ItemType Directory -Force -Path $projDir | Out-Null +Set-Location $projDir + +@' +load STM32F407ZGTx +project name BMSv4 +project toolchain CMake +project path __PROJECT_PATH__ +config saveas BMSv4.ioc +exit +'@.Replace("__PROJECT_PATH__", $projDir) | Set-Content -Encoding ascii .mx_init.txt + +& $javaExe -jar $mxExe -q .mx_init.txt +``` + +## 3. Patch `.ioc` metadata that CubeMX CLI does not encode reliably + +This reproduction needs precise clock, DMA, and NVIC entries. Apply them directly, then regenerate code. + +```powershell +$ioc = "BMSv4.ioc" +$content = Get-Content $ioc + +$fixes = @( + "RCC.EthernetFreq_Value=84000000", + "RCC.PLLP=RCC_PLLP_DIV2", + "Dma.Request0=USART2_RX", + "Dma.Request1=USART2_TX", + "Dma.RequestsNb=2", + "Dma.USART2_RX.0.Direction=DMA_PERIPH_TO_MEMORY", + "Dma.USART2_RX.0.Instance=DMA1_Stream5", + "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.Instance=DMA1_Stream6", + "Dma.USART2_TX.1.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode", + "Mcu.IP0=DMA", + "Mcu.IP1=NVIC", + "Mcu.IP2=RCC", + "Mcu.IP3=SYS", + "Mcu.IP4=USART2", + "Mcu.IPNb=5", + "NVIC.DMA1_Stream5_IRQn=true\\:0\\:0\\:false\\:false\\:true\\:false\\:true\\:true", + "NVIC.DMA1_Stream6_IRQn=true\\:0\\:0\\:false\\:false\\:true\\:false\\:true\\:true", + "NVIC.ForceEnableDMAVector=true", + "NVIC.USART2_IRQn=true\\:0\\:0\\:false\\:false\\:true\\:false\\:false\\:true", + "ProjectManager.UnderRoot=true", + "ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_DMA_Init-DMA-false-HAL-true,4-MX_USART2_UART_Init-USART2-false-HAL-true" +) + +$newLines = $content | Where-Object { + $_ -notmatch '^RCC\.EthernetFreq_Value' -and + $_ -notmatch '^RCC\.PLLP' -and + $_ -notmatch '^Dma\.' -and + $_ -notmatch '^Mcu\.IP' -and + $_ -notmatch '^NVIC\.DMA' -and + $_ -notmatch '^NVIC\.USART2_IRQn' -and + $_ -notmatch '^NVIC\.ForceEnableDMAVector' -and + $_ -notmatch '^ProjectManager\.functionlistsort' -and + $_ -notmatch '^ProjectManager\.UnderRoot' +} + +$newLines += $fixes +$newLines | Set-Content -Encoding ascii $ioc +``` + +## 4. Configure peripheral modes and generate code + +Use CubeMX script mode for the main project shape, then generate. + +```powershell +@' +config load BMSv4.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 +set ip parameters RCC OscillatorType RCC_OSCILLATORTYPE_HSE, OscillatorTypeHSE RCC_OSCILLATORTYPE_HSE, HSEState RCC_HSE_ON, PLLState RCC_PLL_ON, PLLSource RCC_PLLSOURCE_HSE, PLLM 25, PLLN 168, PLLP PLLP_DIV2, PLLQ 4, SYSCLKSource RCC_SYSCLKSOURCE_PLLCLK, AHBCLKDivider RCC_SYSCLK_DIV1, APB1CLKDivider RCC_HCLK_DIV2, APB2CLKDivider RCC_HCLK_DIV1 +set ip parameters USART2 VirtualMode VM_ASYNC, BaudRate 115200, Mode MODE_TX_RX, OverSampling UART_OVERSAMPLING_16 +config save +generate code . +exit +'@ | Set-Content -Encoding ascii .mx_config.txt + +& $javaExe -jar $mxExe -q .mx_config.txt +``` + +## 5. Add the minimal user code needed for reproduction + +Apply only small, isolated changes inside user-code regions. + +```powershell +$usartFile = "Core/Src/usart.c" +$usart = Get-Content $usartFile -Raw +$usartPatch = "/* USER CODE BEGIN 1 */`r`nint __io_putchar(int ch)`r`n{`r`n HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 1000);`r`n return ch;`r`n}`r`n/* USER CODE END 1 */" +$usart = $usart -replace '(?s)/\* USER CODE BEGIN 1 \*/.*?/\* USER CODE END 1 \*/', $usartPatch +$usart | Set-Content -Encoding utf8 $usartFile + +$mainFile = "Core/Src/main.c" +$main = Get-Content $mainFile -Raw +$main = $main -replace '(?s)/\* USER CODE BEGIN PV \*/.*?/\* USER CODE END PV \*/', "/* USER CODE BEGIN PV */`r`nuint8_t receiveBuf50[50];`r`n/* USER CODE END PV */" +$main = $main -replace '(?s)/\* USER CODE BEGIN 2 \*/.*?/\* USER CODE END 2 \*/', " /* USER CODE BEGIN 2 */`r`n HAL_UARTEx_ReceiveToIdle_DMA(&huart2, receiveBuf50, sizeof(receiveBuf50));`r`n /* USER CODE END 2 */" +$main = $main -replace '(?s)/\* USER CODE BEGIN 4 \*/.*?/\* USER CODE END 4 \*/', "/* USER CODE BEGIN 4 */`r`nvoid HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)`r`n{`r`n if (huart->Instance == USART2)`r`n {`r`n HAL_UART_Transmit_DMA(&huart2, receiveBuf50, Size);`r`n HAL_UARTEx_ReceiveToIdle_DMA(&huart2, receiveBuf50, sizeof(receiveBuf50));`r`n }`r`n}`r`n/* USER CODE END 4 */" +$main = $main -replace 'PLLP_DIV2', 'RCC_PLLP_DIV2' +$main | Set-Content -Encoding utf8 $mainFile +``` + +## 6. Restore the VS Code workflow only if needed + +If the reproduction must match the existing debug flow, rebuild the `.vscode` files using the patterns in [DEBUG_SETUP.md](./DEBUG_SETUP.md). + +## 7. Validate the reproduction + +```powershell +cmake --preset Debug +cmake --build --preset Debug +``` + +Required checks: + +- `BMSv4.ioc` reopens cleanly in CubeMX. +- `Core/Src/usart.c` contains the `__io_putchar` user patch. +- `Core/Src/main.c` contains the DMA receive-to-idle user patch. +- `build/Debug/BMSv4.elf` exists after build. diff --git a/cubemx-min-prj/SKILL.md b/cubemx-min-prj/SKILL.md new file mode 100644 index 0000000..11d4425 --- /dev/null +++ b/cubemx-min-prj/SKILL.md @@ -0,0 +1,62 @@ +--- +name: cubemx-min-prj +description: Create a minimal STM32CubeMX reproduction project from scratch, regenerate code, and verify the local build/debug setup. Use when Codex needs to reproduce an STM32 issue in a clean workspace, derive a smallest CubeMX+CMake project from an existing board/project, rebuild `.vscode` STM32 debug files, or document the exact CubeMX CLI and `.ioc` patching steps required to recreate the project. +--- + +# CubeMX Minimal Project + +Create a fresh STM32CubeMX project that reproduces only the hardware and firmware behavior the user needs to debug. Prefer a clean, scriptable reproduction over copying a large existing workspace. + +## Workflow + +1. Inspect the source context. +- Read the target `.ioc`, build presets, and any `.vscode` files before creating the reproduction. +- Identify the minimum MCU, clock tree, peripherals, DMA/NVIC settings, and user-code hooks required to reproduce the issue. +- Keep explicit dates and tool versions. For this workspace, the known-good CubeMX version is `6.11.1`. + +2. Verify local tools. +- Detect the installed STM32CubeMX path and version before touching `.ioc` metadata. +- Run the local version check command from [REPRODUCTION_GUIDE.md](./REPRODUCTION_GUIDE.md) first. +- Stop immediately unless the detected version is exactly `6.11.1` or starts with `6.11.1-`. +- Confirm CMake, the selected toolchain, and any STM32CubeCLT paths needed for build/debug are present. +- If the installed CubeMX is older than the source `.ioc` format, stop and report the version mismatch. + +3. Create the reproduction workspace. +- Default to a new subdirectory such as `reproduction/` under the current workspace. +- Generate the base project from CubeMX CLI/script mode instead of copying generated sources. +- Keep the project minimal: only add the peripherals, pins, and middleware needed to reproduce the issue. + +4. Configure CubeMX deterministically. +- Use CubeMX script commands for project creation, pin assignment, peripheral mode selection, and code generation whenever the CLI supports it. +- If CubeMX CLI cannot express required metadata, patch the `.ioc` directly with exact keys and then regenerate code. +- Treat the `.ioc` as the source of truth. Do not hand-edit generated C files first and backfill the `.ioc` later. + +5. Patch only the user-owned parts of generated code. +- Restrict manual source changes to `/* USER CODE BEGIN */` regions or isolated helper functions added specifically for the reproduction. +- Use this for items like `printf` retargeting, DMA idle receive callbacks, or small harness logic that CubeMX cannot generate. + +6. Rebuild the developer workflow when requested. +- Mirror `.vscode/settings.json`, `tasks.json`, `launch.json`, `c_cpp_properties.json`, and `extensions.json` only if the user wants a debug-ready workspace. +- Reuse the existing project's naming and only swap the target ELF/project name where needed. +- Read [DEBUG_SETUP.md](./DEBUG_SETUP.md) for the BMSv31-style VS Code template expected in this workspace. + +7. Validate before finishing. +- Re-open the `.ioc` in CubeMX after any direct file patching and confirm the GUI reflects the intended configuration. +- Run `cmake --preset Debug` and `cmake --build --preset Debug` unless the user explicitly asks only for scaffolding. +- Confirm the expected ELF exists under `build/Debug/`. +- Treat the task as incomplete if CubeMX generation or local build verification was skipped without user approval. + +## Guardrails + +- Prefer the smallest reproducible project, not a feature-complete clone. +- Do not proceed with project creation, `.ioc` edits, or code generation when CubeMX is not `6.11.1` or `6.11.1-*`. +- Preserve exact issue-critical details such as clock values, DMA streams, NVIC enables, and peripheral modes. +- Use absolute paths inside one-off local commands only when required by CubeMX or local tooling. +- Keep generated project names, MCU names, and toolchain selections explicit in the final notes. +- If reproducing from a larger project, document what was intentionally omitted. +- If CubeMX silently rewrites required metadata, capture the exact `.ioc` keys that must be re-applied. + +## References + +- Read [REPRODUCTION_GUIDE.md](./REPRODUCTION_GUIDE.md) when the task is specifically to recreate the known STM32F407ZGTx/BMSv4 minimal project with CubeMX CLI, `.ioc` patching, user-code updates, and local build verification. +- Read [DEBUG_SETUP.md](./DEBUG_SETUP.md) when the task includes restoring VS Code Cortex-Debug, flash tasks, STM32CubeCLT paths, or extension recommendations. diff --git a/cubemx-min-prj/agents/openai.yaml b/cubemx-min-prj/agents/openai.yaml new file mode 100644 index 0000000..9029569 --- /dev/null +++ b/cubemx-min-prj/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "CubeMX Minimal Project" + short_description: "Create and verify a minimal STM32CubeMX reproduction project." + default_prompt: "Use $cubemx-min-prj to create a minimal STM32CubeMX project that reproduces the target configuration and builds locally." diff --git a/cubemx-min-prj/bak b/cubemx-min-prj/bak new file mode 100644 index 0000000..4e7ef53 --- /dev/null +++ b/cubemx-min-prj/bak @@ -0,0 +1,428 @@ +--- +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 +``` diff --git a/cubemx-min-prj/c_cpp_properties.json b/cubemx-min-prj/c_cpp_properties.json new file mode 100644 index 0000000..304929b --- /dev/null +++ b/cubemx-min-prj/c_cpp_properties.json @@ -0,0 +1,16 @@ +{ + "version": 4, + "configurations": [ + { + /** + * ms-vscode.cmake-tools plugin should be installed. + * + * It provides data for C/C++ plugin, + * such as include paths, browse paths, defines, etc. + */ + "name": "STM32", + "configurationProvider": "ms-vscode.cmake-tools", + "intelliSenseMode": "${default}" + } + ] +} \ No newline at end of file diff --git a/cubemx-min-prj/extensions.json b/cubemx-min-prj/extensions.json new file mode 100644 index 0000000..9ec15cc --- /dev/null +++ b/cubemx-min-prj/extensions.json @@ -0,0 +1,19 @@ +{ + "recommendations": [ + "ms-vscode.cpptools", // (dependencies to ms-vscode.cpptools-extension-pack) + "ms-vscode.cpptools-themes", // (dependencies to ms-vscode.cpptools-extension-pack) + "ms-vscode.cmake-tools", // (dependencies to ms-vscode.cpptools-extension-pack) + "twxs.cmake", // (dependencies to ms-vscode.cpptools-extension-pack) + "ms-vscode.cpptools-extension-pack", // Provides CMake and C++ file coloring, completion & support + "dan-c-underwood.arm", // Provides syntax highlighting for the Arm Assembly language + "zixuanwang.linkerscript", // Provides syntax highlighting for linker scripts + "ms-vscode.hexeditor", // Provides hex editor fo viewing & anipulating files in their raw hexadecimal representation + "trond-snekvik.gnu-mapfiles", // Provides syntax highlighting and symbol listing for GNU linker .map files + "jeff-hykin.better-cpp-syntax", // Provides syntax highlighting for C++ + "marus25.cortex-debug", // Provides debug support on Arm Cortex-M + "mcu-debug.debug-tracker-vscode", // Dependencies to "marus25.cortex-debug" + "mcu-debug.memory-view", // Dependencies to "marus25.cortex-debug" + "mcu-debug.peripheral-viewer", // Dependencies to "marus25.cortex-debug" + "mcu-debug.rtos-views" // Dependencies to "marus25.cortex-debug" + ] +} \ No newline at end of file diff --git a/cubemx-min-prj/launch.json b/cubemx-min-prj/launch.json new file mode 100644 index 0000000..bfa74e8 --- /dev/null +++ b/cubemx-min-prj/launch.json @@ -0,0 +1,66 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Build & Debug Microcontroller - ST-Link", + "cwd": "${workspaceFolder}", + "type": "cortex-debug", + "executable": "${workspaceFolder}/build/Debug/BMSv3.elf", + // Let CMake extension decide executable: "${command:cmake.launchTargetPath}" + // Or fixed file path: "${workspaceFolder}/path/to/filename.elf" + "request": "launch", + "servertype": "stlink", + "device": "STM32F407ZGTx", //MCU used + "interface": "swd", + "serialNumber": "", //Set ST-Link ID if you use multiple at the same time + "runToEntryPoint": "main", + "showDevDebugOutput": "raw", + "svdFile": "${config:STM32VSCodeExtension.cubeCLT.path}/STMicroelectronics_CMSIS_SVD/STM32F407.svd", + "v1": false, //Change it depending on ST Link version + "serverpath": "${config:STM32VSCodeExtension.cubeCLT.path}/STLink-gdb-server/bin/ST-LINK_gdbserver", + "stm32cubeprogrammer":"${config:STM32VSCodeExtension.cubeCLT.path}/STM32CubeProgrammer/bin", + "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", + "serverArgs": [ + "-m","0", + ], + "preLaunchTask": "CMake: clean rebuild" + /* If you use external loader, add additional arguments */ + //"serverArgs": ["--extload", "path/to/ext/loader.stldr"], + }, + { + "name": "Attach to Microcontroller - ST-Link", + "cwd": "${workspaceFolder}", + "type": "cortex-debug", + "executable": "${workspaceFolder}/build/Debug/BMSv3.elf", + // Let CMake extension decide executable: "${command:cmake.launchTargetPath}" + // Or fixed file path: "${workspaceFolder}/path/to/filename.elf" + "request": "attach", + "servertype": "stlink", + "device": "STM32F407ZGTx", //MCU used + "interface": "swd", + "serialNumber": "", //Set ST-Link ID if you use multiple at the same time + "runToEntryPoint": "main", + "showDevDebugOutput": "raw", + "svdFile": "${config:STM32VSCodeExtension.cubeCLT.path}/STMicroelectronics_CMSIS_SVD/STM32F407.svd", + "v1": false, //Change it depending on ST Link version + "serverpath": "${config:STM32VSCodeExtension.cubeCLT.path}/STLink-gdb-server/bin/ST-LINK_gdbserver", + "stm32cubeprogrammer":"${config:STM32VSCodeExtension.cubeCLT.path}/STM32CubeProgrammer/bin", + "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", + "serverArgs": [ + "-m","0", + ], + /* If you use external loader, add additional arguments */ + //"serverArgs": ["--extload", "path/to/ext/loader.stldr"], + } + ] +} + + + diff --git a/cubemx-min-prj/settings.json b/cubemx-min-prj/settings.json new file mode 100644 index 0000000..2a191b5 --- /dev/null +++ b/cubemx-min-prj/settings.json @@ -0,0 +1,10 @@ +{ + "files.associations": { + "tcp_client.h": "c", + "lwip.h": "c", + "ethernetif.h": "c" + }, + "cmake.configurePreset": "Debug", + "cmake.buildPreset": "Debug", + "STM32VSCodeExtension.cubeCLT.path": "C:/ST/STM32CubeCLT_1.19.0" +} \ No newline at end of file diff --git a/cubemx-min-prj/tasks.json b/cubemx-min-prj/tasks.json new file mode 100644 index 0000000..26bc8a1 --- /dev/null +++ b/cubemx-min-prj/tasks.json @@ -0,0 +1,62 @@ +{ + "version": "2.0.0", + "windows": { + "options": { + "shell": { + "executable": "cmd.exe", + "args": ["/d", "/c"] + } + } + }, + "tasks": [ + { + "type": "shell", + "label": "CubeProg: Flash project (SWD)", + "command": "STM32_Programmer_CLI", + "args": [ + "--connect", + "port=swd", + "--download", + "${command:cmake.launchTargetPath}", + // Let CMake extension decide executable: "${command:cmake.launchTargetPath}", + "-hardRst", // Hardware reset - if rst pin is connected + "-rst", // Software reset (backup) + "--start" // Start execution + ], + "options": { + "cwd": "${workspaceFolder}" + }, + "problemMatcher": [] + }, + { + "label": "Build + Flash", + "dependsOrder": "sequence", + "dependsOn": [ + "CMake: clean rebuild", + "CubeProg: Flash project (SWD)", + ] + }, + { + "type": "cmake", + "label": "CMake: clean rebuild", + "command": "cleanRebuild", + "targets": [ + "all" + ], + "preset": "${command:cmake.activeBuildPresetName}", + "group": "build", + "problemMatcher": [], + "detail": "CMake template clean rebuild task" + }, + { + "type": "shell", + "label": "CubeProg: List all available communication interfaces", + "command": "STM32_Programmer_CLI", + "args": ["--list"], + "options": { + "cwd": "${workspaceFolder}" + }, + "problemMatcher": [] + } + ] +}