first commit

This commit is contained in:
2026-03-21 22:09:36 +08:00
commit 5b22cacc13
3 changed files with 528 additions and 0 deletions

222
MultiMicphoneLocat.ioc Normal file
View File

@@ -0,0 +1,222 @@
#MicroXplorer Configuration settings - do not modify
CAD.formats=[]
CAD.pinconfig=Dual
CAD.provider=Component Search Engine
DFSDM2.Filter_regChannel_FIL0=DFSDM_CHANNEL_0
DFSDM2.Filter_regChannel_FIL1=DFSDM_CHANNEL_1
DFSDM2.Filter_regChannel_FIL2=DFSDM_CHANNEL_2
DFSDM2.IPParameters=Filter_regChannel_FIL0,Filter_regChannel_FIL1,Filter_regChannel_FIL2,Selection
DFSDM2.Selection=DFSDM_CHANNEL_OUTPUT_CLOCK_SYSTEM
Dma.DFSDM2_FLT0.0.Direction=DMA_PERIPH_TO_MEMORY
Dma.DFSDM2_FLT0.0.FIFOMode=DMA_FIFOMODE_DISABLE
Dma.DFSDM2_FLT0.0.Instance=DMA2_Stream0
Dma.DFSDM2_FLT0.0.MemDataAlignment=DMA_MDATAALIGN_WORD
Dma.DFSDM2_FLT0.0.MemInc=DMA_MINC_ENABLE
Dma.DFSDM2_FLT0.0.Mode=DMA_NORMAL
Dma.DFSDM2_FLT0.0.PeriphDataAlignment=DMA_PDATAALIGN_WORD
Dma.DFSDM2_FLT0.0.PeriphInc=DMA_PINC_DISABLE
Dma.DFSDM2_FLT0.0.Priority=DMA_PRIORITY_LOW
Dma.DFSDM2_FLT0.0.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode
Dma.DFSDM2_FLT1.1.Direction=DMA_PERIPH_TO_MEMORY
Dma.DFSDM2_FLT1.1.FIFOMode=DMA_FIFOMODE_DISABLE
Dma.DFSDM2_FLT1.1.Instance=DMA2_Stream1
Dma.DFSDM2_FLT1.1.MemDataAlignment=DMA_MDATAALIGN_WORD
Dma.DFSDM2_FLT1.1.MemInc=DMA_MINC_ENABLE
Dma.DFSDM2_FLT1.1.Mode=DMA_NORMAL
Dma.DFSDM2_FLT1.1.PeriphDataAlignment=DMA_PDATAALIGN_WORD
Dma.DFSDM2_FLT1.1.PeriphInc=DMA_PINC_DISABLE
Dma.DFSDM2_FLT1.1.Priority=DMA_PRIORITY_LOW
Dma.DFSDM2_FLT1.1.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode
Dma.DFSDM2_FLT2.2.Direction=DMA_PERIPH_TO_MEMORY
Dma.DFSDM2_FLT2.2.FIFOMode=DMA_FIFOMODE_DISABLE
Dma.DFSDM2_FLT2.2.Instance=DMA2_Stream2
Dma.DFSDM2_FLT2.2.MemDataAlignment=DMA_MDATAALIGN_WORD
Dma.DFSDM2_FLT2.2.MemInc=DMA_MINC_ENABLE
Dma.DFSDM2_FLT2.2.Mode=DMA_NORMAL
Dma.DFSDM2_FLT2.2.PeriphDataAlignment=DMA_PDATAALIGN_WORD
Dma.DFSDM2_FLT2.2.PeriphInc=DMA_PINC_DISABLE
Dma.DFSDM2_FLT2.2.Priority=DMA_PRIORITY_LOW
Dma.DFSDM2_FLT2.2.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode
Dma.Request0=DFSDM2_FLT0
Dma.Request1=DFSDM2_FLT1
Dma.Request2=DFSDM2_FLT2
Dma.RequestsNb=3
File.Version=6
GPIO.groupedBy=Group By Peripherals
KeepUserPlacement=false
Mcu.CPN=STM32F413RGT6
Mcu.Family=STM32F4
Mcu.IP0=DFSDM2
Mcu.IP1=DMA
Mcu.IP2=NVIC
Mcu.IP3=RCC
Mcu.IP4=SPI1
Mcu.IP5=SYS
Mcu.IP6=USART1
Mcu.IPNb=7
Mcu.Name=STM32F413R(G-H)Tx
Mcu.Package=LQFP64
Mcu.Pin0=PH0 - OSC_IN
Mcu.Pin1=PH1 - OSC_OUT
Mcu.Pin10=PB3
Mcu.Pin11=PB4
Mcu.Pin12=PB5
Mcu.Pin13=VP_SYS_VS_Systick
Mcu.Pin2=PA7
Mcu.Pin3=PC5
Mcu.Pin4=PB10
Mcu.Pin5=PC9
Mcu.Pin6=PA9
Mcu.Pin7=PA10
Mcu.Pin8=PA13
Mcu.Pin9=PA14
Mcu.PinsNb=14
Mcu.ThirdPartyNb=0
Mcu.UserConstants=
Mcu.UserName=STM32F413RGTx
MxCube.Version=6.16.1
MxDb.Version=DB.6.0.161
NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.DMA2_Stream0_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:true
NVIC.DMA2_Stream1_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:true
NVIC.DMA2_Stream2_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.SPI1_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true
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.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
PA10.Mode=Asynchronous
PA10.Signal=USART1_RX
PA13.Mode=Serial_Wire
PA13.Signal=SYS_JTMS-SWDIO
PA14.Mode=Serial_Wire
PA14.Signal=SYS_JTCK-SWCLK
PA7.Signal=S_DATAIN1DFSDM2
PA9.Mode=Asynchronous
PA9.Signal=USART1_TX
PB10.Signal=S_CKOUTDFSDM2
PB3.Locked=true
PB3.Mode=Full_Duplex_Slave
PB3.Signal=SPI1_SCK
PB4.Locked=true
PB4.Mode=Full_Duplex_Slave
PB4.Signal=SPI1_MISO
PB5.Mode=Full_Duplex_Slave
PB5.Signal=SPI1_MOSI
PC5.Signal=S_DATAIN2DFSDM2
PC9.Signal=S_DATAIN3DFSDM2
PCC.Checker=false
PCC.Line=STM32F413/423
PCC.MCU=STM32F413R(G-H)Tx
PCC.PartNumber=STM32F413RGTx
PCC.Series=STM32F4
PCC.Temperature=25
PCC.Vdd=1.7
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.CompilerLinker=GCC
ProjectManager.CompilerOptimize=6
ProjectManager.ComputerToolchain=false
ProjectManager.CoupleFile=false
ProjectManager.CustomerFirmwarePackage=
ProjectManager.DefaultFWLocation=true
ProjectManager.DeletePrevious=true
ProjectManager.DeviceId=STM32F413RGTx
ProjectManager.FirmwarePackage=STM32Cube FW_F4 V1.28.3
ProjectManager.FreePins=false
ProjectManager.FreePinsContext=
ProjectManager.HalAssertFull=false
ProjectManager.HeapSize=0x200
ProjectManager.KeepUserCode=true
ProjectManager.LastFirmware=true
ProjectManager.LibraryCopy=0
ProjectManager.MainLocation=Core/Src
ProjectManager.NoMain=false
ProjectManager.PreviousToolchain=
ProjectManager.ProjectBuild=false
ProjectManager.ProjectFileName=MultiMicphoneLocat.ioc
ProjectManager.ProjectName=MultiMicphoneLocat
ProjectManager.ProjectStructure=
ProjectManager.RegisterCallBack=
ProjectManager.StackSize=0x400
ProjectManager.TargetToolchain=MDK-ARM V5.32
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_DFSDM2_Init-DFSDM2-false-HAL-true,5-MX_SPI1_Init-SPI1-false-HAL-true,6-MX_USART1_UART_Init-USART1-false-HAL-true
RCC.AHBFreq_Value=100000000
RCC.APB1CLKDivider=RCC_HCLK_DIV2
RCC.APB1Freq_Value=50000000
RCC.APB1TimFreq_Value=100000000
RCC.APB2Freq_Value=100000000
RCC.APB2TimFreq_Value=100000000
RCC.CortexFreq_Value=100000000
RCC.DFSDM2AudioFreq_Value=48000000
RCC.DFSDM2Freq_Value=100000000
RCC.DFSDMAudioFreq_Value=48000000
RCC.DFSDMFreq_Value=100000000
RCC.FCLKCortexFreq_Value=100000000
RCC.FMPI2C1Freq_Value=50000000
RCC.FamilyName=M
RCC.HCLKFreq_Value=100000000
RCC.HSE_VALUE=8000000
RCC.I2S1Freq_Value=48000000
RCC.I2S2Freq_Value=48000000
RCC.IPParameters=AHBFreq_Value,APB1CLKDivider,APB1Freq_Value,APB1TimFreq_Value,APB2Freq_Value,APB2TimFreq_Value,CortexFreq_Value,DFSDM2AudioFreq_Value,DFSDM2Freq_Value,DFSDMAudioFreq_Value,DFSDMFreq_Value,FCLKCortexFreq_Value,FMPI2C1Freq_Value,FamilyName,HCLKFreq_Value,HSE_VALUE,I2S1Freq_Value,I2S2Freq_Value,LPTimerFreq_Value,MCO2PinFreq_Value,PLLCLKFreq_Value,PLLI2SQCLKFreq_Value,PLLI2SRCLKFreq_Value,PLLM,PLLN,PLLP,PLLQCLKFreq_Value,PLLQoutputFreq_Value,PLLRCLKFreq_Value,PLLRoutputFreq_Value,PLLSourceVirtual,PWRFreq_Value,RNGFreq_Value,SAI1AFreq_Value,SAI1BFreq_Value,SDIOFreq_Value,SYSCLKFreq_VALUE,SYSCLKSource,USBFreq_Value,VCOI2SInputFreq_Value,VCOI2SOutputFreq_Value,VCOInputFreq_Value,VCOOutputFreq_Value
RCC.LPTimerFreq_Value=50000000
RCC.MCO2PinFreq_Value=100000000
RCC.PLLCLKFreq_Value=100000000
RCC.PLLI2SQCLKFreq_Value=48000000
RCC.PLLI2SRCLKFreq_Value=48000000
RCC.PLLM=8
RCC.PLLN=400
RCC.PLLP=RCC_PLLP_DIV4
RCC.PLLQCLKFreq_Value=200000000
RCC.PLLQoutputFreq_Value=200000000
RCC.PLLRCLKFreq_Value=200000000
RCC.PLLRoutputFreq_Value=200000000
RCC.PLLSourceVirtual=RCC_PLLSOURCE_HSE
RCC.PWRFreq_Value=100000000
RCC.RNGFreq_Value=200000000
RCC.SAI1AFreq_Value=8000000
RCC.SAI1BFreq_Value=8000000
RCC.SDIOFreq_Value=200000000
RCC.SYSCLKFreq_VALUE=100000000
RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK
RCC.USBFreq_Value=200000000
RCC.VCOI2SInputFreq_Value=500000
RCC.VCOI2SOutputFreq_Value=96000000
RCC.VCOInputFreq_Value=1000000
RCC.VCOOutputFreq_Value=400000000
SH.S_CKOUTDFSDM2.0=DFSDM2_CKOUT,PDM_SPI_Input_from_ch01_and_Internal_Clock
SH.S_CKOUTDFSDM2.1=DFSDM2_CKOUT,CKOUT
SH.S_CKOUTDFSDM2.2=DFSDM2_CKOUT,PDM_SPI_Input_from_ch12_and_Internal_Clock
SH.S_CKOUTDFSDM2.3=DFSDM2_CKOUT,PDM_SPI_Input_from_ch23_and_Internal_Clock
SH.S_CKOUTDFSDM2.ConfNb=4
SH.S_DATAIN1DFSDM2.0=DFSDM2_DATIN1,PDM_SPI_Input_from_ch01_and_Internal_Clock
SH.S_DATAIN1DFSDM2.ConfNb=1
SH.S_DATAIN2DFSDM2.0=DFSDM2_DATIN2,PDM_SPI_Input_from_ch12_and_Internal_Clock
SH.S_DATAIN2DFSDM2.ConfNb=1
SH.S_DATAIN3DFSDM2.0=DFSDM2_DATIN3,PDM_SPI_Input_from_ch23_and_Internal_Clock
SH.S_DATAIN3DFSDM2.ConfNb=1
SPI1.Direction=SPI_DIRECTION_2LINES
SPI1.IPParameters=VirtualType,Mode,Direction
SPI1.Mode=SPI_MODE_SLAVE
SPI1.VirtualType=VM_SLAVE
USART1.IPParameters=VirtualMode
USART1.VirtualMode=VM_ASYNC
VP_SYS_VS_Systick.Mode=SysTick
VP_SYS_VS_Systick.Signal=SYS_VS_Systick
board=custom

View File

@@ -0,0 +1,57 @@
# STM32CubeMX IOC Reader
## Use this skill when
- The user asks to read, analyze, summarize, or validate an STM32CubeMX `.ioc` file.
- The user wants pin mapping, clock config, peripheral setup, middleware settings, or project metadata from `.ioc`.
- The user wants a machine-readable export (JSON) of `.ioc` content.
## Do not use this skill when
- The request is about generated C code (`main.c`, `stm32xx_hal_msp.c`) and not `.ioc` itself.
- The file is not an STM32CubeMX `.ioc` file.
## What this skill does
- Parses `.ioc` key-value entries.
- Groups configuration by domain: MCU, pins, RCC/clock, peripherals, middleware, and project manager.
- Produces readable summaries for fast review.
- Optionally exports structured JSON for tooling.
## Workflow
1. Confirm the target `.ioc` path.
2. Run parser script:
```bash
python scripts/parse_ioc.py --ioc <path/to/project.ioc>
```
3. For JSON output:
```bash
python scripts/parse_ioc.py --ioc <path/to/project.ioc> --json
```
4. For saved JSON file:
```bash
python scripts/parse_ioc.py --ioc <path/to/project.ioc> --json --out parsed_ioc.json
```
## Response style guidelines
- Start with a concise project overview (MCU, board, toolchain, project name).
- Then list enabled peripherals and notable pin assignments.
- Then call out clock source and important RCC settings.
- Mention anomalies (empty values, duplicate keys, unknown domains).
## Notes about `.ioc` format
- `.ioc` is an INI-like key-value format (not strict XML).
- Typical key prefixes:
- `Mcu.` for target MCU/package/family
- `PAx`/`PBx`... for pin assignment and signal labels
- `RCC.` for clocks
- `<PERIPH>.` (for example `USART1.`, `I2C1.`, `TIM3.`) for peripheral settings
- `ProjectManager.` for generated project metadata

View File

@@ -0,0 +1,249 @@
#!/usr/bin/env python3
"""Parse and summarize STM32CubeMX .ioc files."""
from __future__ import annotations
import argparse
import json
from collections import defaultdict
from pathlib import Path
from typing import TypedDict
StrMap = dict[str, str]
class ClassifiedIOC(TypedDict):
domains: dict[str, StrMap]
peripherals: dict[str, StrMap]
other: StrMap
def parse_ioc(ioc_path: Path) -> tuple[StrMap, list[str]]:
entries: StrMap = {}
anomalies: list[str] = []
lines = ioc_path.read_text(encoding="utf-8", errors="replace").splitlines()
for index, raw in enumerate(lines, start=1):
line = raw.strip()
if not line or line.startswith("#"):
continue
if "=" not in line:
anomalies.append(f"line {index}: no '=' separator")
continue
key, value = line.split("=", 1)
key = key.strip()
value = value.strip()
if not key:
anomalies.append(f"line {index}: empty key")
continue
if key in entries:
anomalies.append(f"line {index}: duplicate key '{key}' (last value kept)")
entries[key] = value
return entries, anomalies
def classify(entries: StrMap) -> ClassifiedIOC:
domains: dict[str, StrMap] = {
"mcu": {},
"rcc": {},
"project_manager": {},
"pins": {},
"middleware": {},
}
peripherals: dict[str, StrMap] = defaultdict(dict)
other: StrMap = {}
middleware_roots = {
"freertos",
"fatfs",
"lwip",
"usb",
"touchgfx",
"azure_rtos",
"threadx",
"netxduo",
"filex",
"ux_device",
"ux_host",
}
for key, value in entries.items():
if key.startswith("Mcu."):
domains["mcu"][key] = value
continue
if key.startswith("RCC."):
domains["rcc"][key] = value
continue
if key.startswith("ProjectManager."):
domains["project_manager"][key] = value
continue
# Pin records usually look like PA0.Mode, PA0.Signal, PB6.GPIO_Label...
if len(key) >= 3 and key[0] == "P" and key[1].isalpha():
pin = key.split(".", 1)[0]
if len(pin) >= 3 and pin[2].isdigit():
domains["pins"][key] = value
continue
root = key.split(".", 1)[0]
root_l = root.lower()
if root_l in middleware_roots or root_l.startswith("cmsis"):
domains["middleware"][key] = value
continue
# Heuristic: uppercase root token often indicates a peripheral (USART1, I2C1, TIM3...)
if root and root.upper() == root and any(ch.isdigit() for ch in root):
peripherals[root][key] = value
continue
other[key] = value
return {
"domains": domains,
"peripherals": dict(sorted(peripherals.items())),
"other": other,
}
def summarize(classified: ClassifiedIOC, ioc_path: Path, anomalies: list[str]) -> str:
domains = classified["domains"]
peripherals = classified["peripherals"]
other = classified["other"]
mcu = domains["mcu"]
project_manager = domains["project_manager"]
rcc = domains["rcc"]
pins = domains["pins"]
middleware = domains["middleware"]
lines: list[str] = []
lines.append(f"IOC file: {ioc_path}")
lines.append("")
lines.append("== Project Overview ==")
lines.append(f"- MCU keys: {len(mcu)}")
lines.append(f"- ProjectManager keys: {len(project_manager)}")
lines.append(f"- RCC keys: {len(rcc)}")
top_overview = [
"Mcu.Name",
"Mcu.Package",
"Mcu.Family",
"Mcu.UserName",
"ProjectManager.ProjectName",
"ProjectManager.ToolChain",
"ProjectManager.TargetToolchain",
]
for key in top_overview:
if key in mcu:
lines.append(f"- {key}: {mcu[key]}")
elif key in project_manager:
lines.append(f"- {key}: {project_manager[key]}")
lines.append("")
lines.append("== Peripherals ==")
lines.append(f"- Count: {len(peripherals)}")
if peripherals:
lines.append("- Enabled/peripheral roots: " + ", ".join(peripherals.keys()))
lines.append("")
lines.append("== Pins ==")
lines.append(f"- Pin-related keys: {len(pins)}")
# Extract a compact map of pin -> signal
pin_signals: dict[str, str] = {}
for key, value in pins.items():
if key.endswith(".Signal"):
pin = key.split(".", 1)[0]
pin_signals[pin] = value
if pin_signals:
preview = sorted(pin_signals.items())[:20]
for pin, signal in preview:
lines.append(f"- {pin}: {signal}")
if len(pin_signals) > len(preview):
lines.append(f"- ... ({len(pin_signals) - len(preview)} more)")
lines.append("")
lines.append("== Middleware ==")
lines.append(f"- Middleware keys: {len(middleware)}")
lines.append("")
lines.append("== Diagnostics ==")
lines.append(f"- Other keys: {len(other)}")
lines.append(f"- Anomalies: {len(anomalies)}")
if anomalies:
for item in anomalies[:20]:
lines.append(f"- {item}")
if len(anomalies) > 20:
lines.append(f"- ... ({len(anomalies) - 20} more)")
return "\n".join(lines)
def build_json(
ioc_path: Path,
entries: StrMap,
classified: ClassifiedIOC,
anomalies: list[str],
) -> dict[str, object]:
return {
"ioc_path": str(ioc_path),
"counts": {
"entries": len(entries),
"mcu": len(classified["domains"]["mcu"]),
"rcc": len(classified["domains"]["rcc"]),
"project_manager": len(classified["domains"]["project_manager"]),
"pins": len(classified["domains"]["pins"]),
"middleware": len(classified["domains"]["middleware"]),
"peripherals": len(classified["peripherals"]),
"other": len(classified["other"]),
"anomalies": len(anomalies),
},
"domains": classified["domains"],
"peripherals": classified["peripherals"],
"other": classified["other"],
"anomalies": anomalies,
}
def main() -> int:
parser = argparse.ArgumentParser(
description="Read and summarize STM32CubeMX .ioc files"
)
parser.add_argument("--ioc", required=True, help="Path to .ioc file")
parser.add_argument("--json", action="store_true", help="Print JSON output")
parser.add_argument(
"--out", help="Optional output file path (for --json or text summary)"
)
args = parser.parse_args()
ioc_path = Path(args.ioc)
if not ioc_path.exists() or not ioc_path.is_file():
raise SystemExit(f"error: ioc file not found: {ioc_path}")
entries, anomalies = parse_ioc(ioc_path)
classified = classify(entries)
if args.json:
payload = build_json(ioc_path, entries, classified, anomalies)
rendered = json.dumps(payload, ensure_ascii=True, indent=2)
else:
rendered = summarize(classified, ioc_path, anomalies)
if args.out:
Path(args.out).write_text(rendered + "\n", encoding="utf-8")
else:
print(rendered)
return 0
if __name__ == "__main__":
raise SystemExit(main())