MSPM0 Agent Skill Use this skill for TI MSPM0 firmware projects that use SysConfig and DriverLib through CCS / CCS Theia, Keil/uVision, or CMake + Arm GNU Toolchain + OpenOCD workflows. It is intended for Claude Code, OpenCode, OpenClaw, Continue, Cursor, Codex, and similar CLI/editor agents. Default Workflow 1. Locate the project or , editable source files, generated , and the active project entrypoint: for CCS, plus scatter file for Keil/uVision, or plus OpenOCD files for CMake/GCC/OpenOCD. 2. Run when this skill is available. 3. Read metadata: device, package, SDK product, SysConfig versio…

,\n line.strip(),\n flags=re.IGNORECASE,\n )\n if not match:\n return None\n args = parse_known_args(parse_cli_tokens(match.group(\"args\")))\n return BuildEvidence(\n tool=match.group(\"tool\"),\n script=args.get(\"script\", \"\"),\n product=args.get(\"product\", \"\"),\n compiler=args.get(\"compiler\", \"\"),\n source=str(source),\n )\n\n\ndef find_build_evidence(project: Path, script: Path) -> list[BuildEvidence]:\n evidence: list[BuildEvidence] = []\n seen: set[tuple[str, str, str, str]] = set()\n for build_dir in (\"Debug\", \"Release\"):\n rule_path = project / build_dir / \"subdir_rules.mk\"\n if not rule_path.is_file():\n continue\n for line in read_text(rule_path).splitlines():\n parsed = parse_build_rule(line, rule_path)\n if not parsed:\n continue\n if parsed.script:\n rule_script = Path(parsed.script)\n if not rule_script.is_absolute():\n rule_script = rule_path.parent / rule_script\n rule_script = rule_script.resolve()\n if rule_script != script:\n continue\n key = (\n os.path.normcase(parsed.tool),\n os.path.normcase(parsed.script),\n os.path.normcase(parsed.product),\n parsed.compiler,\n )\n if key not in seen:\n seen.add(key)\n evidence.append(parsed)\n return evidence\n\n\ndef inspect_project(project: Path, explicit_script: str | None = None) -> ProjectInfo:\n project = project.resolve()\n if not project.is_dir():\n raise ResolutionError(f\"project directory not found: {project}\")\n script = find_syscfg(project, explicit_script)\n metadata = parse_syscfg_metadata(read_text(script))\n ccs = inspect_ccs_project(project)\n return ProjectInfo(\n project=str(project),\n script=str(script),\n metadata=metadata,\n ccs_products=dict(ccs[\"products\"]),\n ccs_product_conflicts=dict(ccs[\"product_conflicts\"]),\n ccs_compiler=str(ccs[\"compiler\"]),\n ccs_compiler_conflicts=list(ccs[\"compiler_conflicts\"]),\n build_evidence=find_build_evidence(project, script),\n )\n\n\ndef resolve_tool_path(value: str) -> Path:\n candidate = Path(os.path.expandvars(os.path.expanduser(value))).resolve()\n if candidate.is_dir():\n for name in TOOL_NAMES:\n tool = candidate / name\n if tool.is_file():\n return tool.resolve()\n raise ResolutionError(f\"SysConfig directory has no CLI executable: {candidate}\")\n if not candidate.is_file():\n raise ResolutionError(f\"SysConfig CLI not found: {candidate}\")\n return candidate\n\n\ndef command_for_tool(tool: Path, args: list[str]) -> list[str]:\n # Python launches .bat files directly on Windows; cmd /c broke quoted paths with spaces.\n return [str(tool), *args]\n\n\ndef run_tool(\n tool: Path,\n args: list[str],\n *,\n cwd: Path | None = None,\n timeout: int = 120,\n) -> subprocess.CompletedProcess[str]:\n return subprocess.run(\n command_for_tool(tool, args),\n cwd=str(cwd) if cwd else None,\n text=True,\n capture_output=True,\n timeout=timeout,\n check=False,\n )\n\n\ndef query_tool_version(tool: Path) -> str:\n try:\n result = run_tool(tool, [\"--version\"], timeout=20)\n except (OSError, subprocess.SubprocessError) as exc:\n raise ResolutionError(f\"cannot run SysConfig CLI {tool}: {exc}\") from exc\n if result.returncode != 0:\n detail = (result.stderr or result.stdout).strip()\n raise ResolutionError(f\"cannot query SysConfig version from {tool}: {detail}\")\n return result.stdout.strip().splitlines()[0] if result.stdout.strip() else \"\"\n\n\ndef add_tool_candidate(\n candidates: dict[str, ToolCandidate],\n value: str | Path,\n source: str,\n *,\n ignore_missing: bool = True,\n) -> None:\n try:\n path = resolve_tool_path(str(value))\n except ResolutionError:\n if ignore_missing:\n return\n raise\n key = os.path.normcase(str(path))\n if key in candidates:\n return\n candidates[key] = ToolCandidate(str(path), query_tool_version(path), source)\n\n\ndef common_tool_paths() -> Iterable[Path]:\n if os.name == \"nt\":\n ti_root = Path(os.environ.get(\"TI_ROOT\", \"C:/ti\"))\n if ti_root.is_dir():\n yield from ti_root.glob(\"sysconfig_*/sysconfig_cli.bat\")\n yield from ti_root.glob(\"ccs*/ccs/utils/sysconfig_*/sysconfig_cli.bat\")\n else:\n for root in (Path(\"/opt/ti\"), Path.home() / \"ti\"):\n if not root.is_dir():\n continue\n yield from root.glob(\"sysconfig_*/sysconfig_cli.sh\")\n yield from root.glob(\"sysconfig_*/sysconfig_cli\")\n yield from root.glob(\"ccs*/ccs/utils/sysconfig_*/sysconfig_cli.sh\")\n\n\ndef discover_tools(build_evidence: list[BuildEvidence]) -> list[ToolCandidate]:\n candidates: dict[str, ToolCandidate] = {}\n for evidence in build_evidence:\n add_tool_candidate(candidates, evidence.tool, f\"build rule: {evidence.source}\")\n for variable in TOOL_ENV_VARS:\n value = os.environ.get(variable)\n if value:\n add_tool_candidate(candidates, value, f\"environment: {variable}\")\n for name in TOOL_NAMES:\n value = shutil.which(name)\n if value:\n add_tool_candidate(candidates, value, \"PATH\")\n for path in common_tool_paths():\n add_tool_candidate(candidates, path, \"common install root\")\n return sorted(candidates.values(), key=lambda item: (version_key(item.version), item.path))\n\n\ndef base_version(version: str) -> str:\n return version.strip().split(\"+\", 1)[0]\n\n\ndef version_key(version: str) -> tuple[int, ...]:\n numbers = re.findall(r\"\\d+\", base_version(version))\n return tuple(int(number) for number in numbers)\n\n\ndef versions_match(left: str, right: str) -> bool:\n return bool(left and right and version_key(left) == version_key(right))\n\n\ndef expected_tool_versions(info: ProjectInfo) -> list[tuple[str, str]]:\n versions: list[tuple[str, str]] = []\n metadata_version = str(info.metadata.get(\"tool_version\", \"\"))\n if metadata_version:\n versions.append((metadata_version, \".syscfg @versions\"))\n ccs_version = info.ccs_products.get(\"sysconfig\", \"\")\n if ccs_version:\n versions.append((ccs_version, \".cproject PRODUCTS\"))\n return versions\n\n\ndef ccs_conflicting_product_versions(\n info: ProjectInfo,\n normalized_name: str,\n) -> tuple[str, list[str]] | None:\n for name, versions in info.ccs_product_conflicts.items():\n if normalize_product_name(name) == normalized_name:\n return name, versions\n return None\n\n\ndef select_tool(\n info: ProjectInfo,\n explicit: str | None,\n) -> tuple[ToolCandidate, list[str], list[ToolCandidate]]:\n warnings: list[str] = []\n expected = expected_tool_versions(info)\n\n if explicit:\n path = resolve_tool_path(explicit)\n selected = ToolCandidate(str(path), query_tool_version(path), \"explicit --tool\")\n for version, source in expected:\n if not versions_match(selected.version, version):\n warnings.append(\n f\"explicit SysConfig {selected.version} differs from {source} {version}\"\n )\n return selected, warnings, [selected]\n\n if info.build_evidence:\n tools = {\n os.path.normcase(str(Path(item.tool).resolve())): item\n for item in info.build_evidence\n if Path(item.tool).is_file()\n }\n if len(tools) > 1:\n raise ResolutionError(\"build rules reference multiple SysConfig tools; choose one with --tool\")\n if tools:\n evidence = next(iter(tools.values()))\n path = resolve_tool_path(evidence.tool)\n selected = ToolCandidate(\n str(path),\n query_tool_version(path),\n f\"build rule: {evidence.source}\",\n )\n mismatches = [\n f\"{source} {version}\"\n for version, source in expected\n if not versions_match(selected.version, version)\n ]\n if mismatches:\n raise ResolutionError(\n f\"build-rule SysConfig {selected.version} conflicts with \"\n f\"{', '.join(mismatches)}; use --tool for an intentional override\"\n )\n return selected, warnings, [selected]\n\n ccs_conflict = ccs_conflicting_product_versions(info, \"sysconfig\")\n if ccs_conflict:\n name, versions = ccs_conflict\n raise ResolutionError(\n f\"CCS configurations declare multiple {name} versions \"\n f\"({', '.join(versions)}); select one with --tool\"\n )\n\n distinct_expected = {version_key(version) for version, _source in expected}\n if len(distinct_expected) > 1:\n detail = \", \".join(f\"{source}={version}\" for version, source in expected)\n raise ResolutionError(f\"conflicting SysConfig version declarations ({detail}); use --tool\")\n\n candidates = discover_tools(info.build_evidence)\n if not candidates:\n raise ResolutionError(\"no SysConfig CLI found; install it or pass --tool\")\n\n if distinct_expected:\n expected_key = next(iter(distinct_expected))\n expected_version = expected[0][0]\n matches = [item for item in candidates if version_key(item.version) == expected_key]\n if len(matches) == 1:\n return matches[0], warnings, candidates\n if len(matches) > 1:\n choices = \", \".join(item.path for item in matches)\n raise ResolutionError(\n f\"multiple SysConfig {expected_version} CLIs found ({choices}); use --tool\"\n )\n available = \", \".join(f\"{item.version} ({item.path})\" for item in candidates)\n raise ResolutionError(\n f\"project requires SysConfig {expected_version}, but it was not found; \"\n f\"available: {available}. Use --tool to override explicitly.\"\n )\n\n if len(candidates) == 1:\n return candidates[0], warnings, candidates\n available = \", \".join(f\"{item.version} ({item.path})\" for item in candidates)\n raise ResolutionError(\n f\"project does not declare a SysConfig version and multiple tools are installed: \"\n f\"{available}. Select one with --tool.\"\n )\n\n\ndef product_from_json(path: Path, source: str) -> ProductCandidate:\n path = path.resolve()\n if path.is_dir():\n path = path / \".metadata\" / \"product.json\"\n if not path.is_file():\n raise ResolutionError(f\"SysConfig product.json not found: {path}\")\n try:\n data = json.loads(read_text(path))\n except json.JSONDecodeError as exc:\n raise ResolutionError(f\"invalid product.json {path}: {exc}\") from exc\n return ProductCandidate(\n path=str(path),\n name=str(data.get(\"name\", \"\")),\n version=str(data.get(\"version\", \"\")),\n source=source,\n )\n\n\ndef add_product_candidate(\n candidates: dict[str, ProductCandidate],\n value: str | Path,\n source: str,\n *,\n ignore_missing: bool = True,\n) -> None:\n try:\n candidate = product_from_json(\n Path(os.path.expandvars(os.path.expanduser(str(value)))),\n source,\n )\n except ResolutionError:\n if ignore_missing:\n return\n raise\n key = os.path.normcase(candidate.path)\n candidates.setdefault(key, candidate)\n\n\ndef common_product_paths() -> Iterable[Path]:\n roots: list[Path]\n if os.name == \"nt\":\n roots = [Path(os.environ.get(\"TI_ROOT\", \"C:/ti\"))]\n else:\n roots = [Path(\"/opt/ti\"), Path.home() / \"ti\"]\n for root in roots:\n if root.is_dir():\n yield from root.glob(\"mspm0_sdk_*/.metadata/product.json\")\n\n\ndef discover_products(build_evidence: list[BuildEvidence]) -> list[ProductCandidate]:\n candidates: dict[str, ProductCandidate] = {}\n for evidence in build_evidence:\n if evidence.product and \"@\" not in evidence.product:\n add_product_candidate(\n candidates,\n evidence.product,\n f\"build rule: {evidence.source}\",\n )\n for variable in PRODUCT_ENV_VARS:\n value = os.environ.get(variable)\n if value:\n add_product_candidate(candidates, value, f\"environment: {variable}\")\n for path in common_product_paths():\n add_product_candidate(candidates, path, \"common install root\")\n return sorted(candidates.values(), key=lambda item: (version_key(item.version), item.path))\n\n\ndef normalize_product_name(name: str) -> str:\n return re.sub(r\"[^a-z0-9]\", \"\", name.lower())\n\n\ndef product_install_version(candidate: ProductCandidate) -> str:\n product_path = Path(candidate.path)\n install_dir = (\n product_path.parent.parent\n if product_path.parent.name == \".metadata\"\n else product_path.parent\n )\n match = re.search(r\"(\\d+(?:[._-]\\d+){2,})$\", install_dir.name)\n if not match:\n return \"\"\n return re.sub(r\"[._-]\", \".\", match.group(1))\n\n\ndef product_matches_requirement(\n candidate: ProductCandidate,\n name: str,\n version: str,\n source: str,\n) -> bool:\n if normalize_product_name(candidate.name) != normalize_product_name(name):\n return False\n if versions_match(candidate.version, version):\n return True\n return source == \".cproject PRODUCTS\" and versions_match(\n product_install_version(candidate),\n version,\n )\n\n\ndef is_product_path_value(value: str) -> bool:\n expanded = os.path.expandvars(os.path.expanduser(value.strip()))\n return (\n \"/\" in expanded\n or \"\\\\\" in expanded\n or expanded.lower().endswith(\"product.json\")\n or Path(expanded).is_absolute()\n )\n\n\ndef metadata_product_requirement(info: ProjectInfo) -> tuple[str, str]:\n args = info.metadata.get(\"effective_args\", {})\n if not isinstance(args, dict):\n return \"\", \"\"\n product = str(args.get(\"product\", \"\")).strip()\n if is_product_path_value(product) or \"@\" not in product:\n return \"\", \"\"\n name, version = product.rsplit(\"@\", 1)\n return name, version\n\n\ndef metadata_product_path(info: ProjectInfo) -> Path | None:\n args = info.metadata.get(\"effective_args\", {})\n if not isinstance(args, dict):\n return None\n product = str(args.get(\"product\", \"\")).strip()\n if not product or (\"@\" in product and not is_product_path_value(product)):\n return None\n path = Path(os.path.expandvars(os.path.expanduser(product)))\n if not path.is_absolute():\n path = Path(info.script).parent / path\n return path.resolve()\n\n\ndef ccs_product_requirement(info: ProjectInfo) -> tuple[str, str]:\n for name, version in info.ccs_products.items():\n if normalize_product_name(name) == \"mspm0sdk\":\n return name, version\n return \"\", \"\"\n\n\ndef select_product(\n info: ProjectInfo,\n explicit: str | None,\n) -> tuple[ProductCandidate, list[str], list[ProductCandidate]]:\n warnings: list[str] = []\n requirements = [\n item\n for item in (\n (*metadata_product_requirement(info), \".syscfg metadata\"),\n (*ccs_product_requirement(info), \".cproject PRODUCTS\"),\n )\n if item[0] and item[1]\n ]\n metadata_candidate: ProductCandidate | None = None\n metadata_path = metadata_product_path(info)\n if metadata_path:\n try:\n metadata_candidate = product_from_json(\n metadata_path,\n \".syscfg metadata path\",\n )\n except ResolutionError as exc:\n if not explicit:\n raise\n warnings.append(str(exc))\n if metadata_candidate:\n requirements.append(\n (\n metadata_candidate.name,\n metadata_candidate.version,\n \".syscfg metadata path\",\n )\n )\n\n if explicit:\n selected = product_from_json(Path(explicit), \"explicit --product\")\n for name, version, source in requirements:\n if not product_matches_requirement(selected, name, version, source):\n warnings.append(\n f\"explicit product {selected.name}@{selected.version} differs from \"\n f\"{source} {name}@{version}\"\n )\n return selected, warnings, [selected]\n\n build_products = {\n os.path.normcase(str(Path(item.product).resolve())): item\n for item in info.build_evidence\n if item.product and \"@\" not in item.product and Path(item.product).is_file()\n }\n if len(build_products) > 1:\n raise ResolutionError(\"build rules reference multiple SysConfig products; use --product\")\n if build_products:\n evidence = next(iter(build_products.values()))\n selected = product_from_json(\n Path(evidence.product),\n f\"build rule: {evidence.source}\",\n )\n mismatches = [\n f\"{source} {name}@{version}\"\n for name, version, source in requirements\n if not product_matches_requirement(selected, name, version, source)\n ]\n if mismatches:\n raise ResolutionError(\n f\"build-rule product {selected.name}@{selected.version} conflicts with \"\n f\"{', '.join(mismatches)}; use --product for an intentional override\"\n )\n return selected, warnings, [selected]\n\n ccs_conflict = ccs_conflicting_product_versions(info, \"mspm0sdk\")\n if ccs_conflict:\n name, versions = ccs_conflict\n raise ResolutionError(\n f\"CCS configurations declare multiple {name} versions \"\n f\"({', '.join(versions)}); select one with --product\"\n )\n\n if metadata_candidate:\n mismatches = [\n f\"{source} {name}@{version}\"\n for name, version, source in requirements\n if not product_matches_requirement(\n metadata_candidate,\n name,\n version,\n source,\n )\n ]\n if mismatches:\n raise ResolutionError(\n f\"metadata product {metadata_candidate.name}@{metadata_candidate.version} \"\n f\"conflicts with {', '.join(mismatches)}; \"\n \"use --product for an intentional override\"\n )\n return metadata_candidate, warnings, [metadata_candidate]\n\n candidates = discover_products(info.build_evidence)\n if not candidates:\n raise ResolutionError(\"no MSPM0 SDK product.json found; pass --product\")\n\n if requirements:\n required_version = requirements[0][1]\n matches = [\n item\n for item in candidates\n if all(\n product_matches_requirement(item, name, version, source)\n for name, version, source in requirements\n )\n ]\n if len(matches) == 1:\n return matches[0], warnings, candidates\n if len(matches) > 1:\n choices = \", \".join(item.path for item in matches)\n raise ResolutionError(\n f\"multiple products satisfy project declarations ({choices}); use --product\"\n )\n normalized_requirements = {\n (normalize_product_name(name), version_key(version))\n for name, version, _source in requirements\n }\n if len(normalized_requirements) > 1:\n detail = \", \".join(\n f\"{source}={name}@{version}\"\n for name, version, source in requirements\n )\n raise ResolutionError(\n f\"conflicting SDK product declarations ({detail}); use --product\"\n )\n required_name = normalize_product_name(requirements[0][0])\n available = \", \".join(\n f\"{item.name}@{item.version} ({item.path})\" for item in candidates\n )\n raise ResolutionError(\n f\"project requires {required_name}@{required_version}, but it was not found; \"\n f\"available: {available}. Use --product to override explicitly.\"\n )\n\n if len(candidates) == 1:\n return candidates[0], warnings, candidates\n available = \", \".join(f\"{item.name}@{item.version} ({item.path})\" for item in candidates)\n raise ResolutionError(\n f\"project does not declare an SDK product and multiple products are installed: \"\n f\"{available}. Select one with --product.\"\n )\n\n\ndef select_compiler(info: ProjectInfo, explicit: str | None) -> tuple[str, str]:\n if explicit:\n return explicit, \"explicit --compiler\"\n build_compilers = {item.compiler for item in info.build_evidence if item.compiler}\n if len(build_compilers) > 1:\n raise ResolutionError(\"build rules declare multiple SysConfig compilers; use --compiler\")\n if build_compilers:\n return next(iter(build_compilers)), \"build rule\"\n if info.ccs_compiler_conflicts:\n raise ResolutionError(\n \"CCS configurations declare multiple SysConfig compilers \"\n f\"({', '.join(info.ccs_compiler_conflicts)}); use --compiler\"\n )\n if info.ccs_compiler:\n return info.ccs_compiler, \".cproject\"\n metadata_args = info.metadata.get(\"effective_args\", {})\n if isinstance(metadata_args, dict) and metadata_args.get(\"compiler\"):\n return str(metadata_args[\"compiler\"]), \".syscfg metadata\"\n return \"\", \"SysConfig default\"\n\n\ndef format_command(command: list[str]) -> str:\n if os.name == \"nt\":\n return subprocess.list2cmdline(command)\n return shlex.join(command)\n\n\ndef collect_generated_files(output: Path) -> list[str]:\n if not output.is_dir():\n return []\n return sorted(str(path.relative_to(output)) for path in output.rglob(\"*\") if path.is_file())\n\n\ndef build_report(\n info: ProjectInfo,\n tool: ToolCandidate,\n product: ProductCandidate,\n compiler: str,\n compiler_source: str,\n warnings: list[str],\n candidates: tuple[list[ToolCandidate], list[ProductCandidate]],\n output: Path,\n command: list[str],\n *,\n dry_run: bool,\n keep_output: bool,\n) -> dict[str, object]:\n return {\n \"status\": \"dry-run\" if dry_run else \"pending\",\n \"project\": info.project,\n \"script\": info.script,\n \"tool\": asdict(tool),\n \"product\": asdict(product),\n \"compiler\": {\"value\": compiler, \"source\": compiler_source},\n \"output\": {\"path\": str(output), \"temporary\": True, \"kept\": keep_output},\n \"command\": command,\n \"command_text\": format_command(command),\n \"warnings\": warnings,\n \"available_tools\": [asdict(item) for item in candidates[0]],\n \"available_products\": [asdict(item) for item in candidates[1]],\n \"returncode\": None,\n \"stdout\": \"\",\n \"stderr\": \"\",\n \"generated_files\": [],\n }\n\n\ndef print_text(report: dict[str, object]) -> None:\n print(f\"SysConfig validation: {report['project']}\")\n print(f\"- script: {report['script']}\")\n tool = report[\"tool\"]\n product = report[\"product\"]\n compiler = report[\"compiler\"]\n output = report[\"output\"]\n assert isinstance(tool, dict)\n assert isinstance(product, dict)\n assert isinstance(compiler, dict)\n assert isinstance(output, dict)\n print(f\"- tool: {tool['version']} ({tool['source']})\")\n print(f\" {tool['path']}\")\n print(f\"- product: {product['name']}@{product['version']} ({product['source']})\")\n print(f\" {product['path']}\")\n print(f\"- compiler: {compiler['value'] or '\u003cSysConfig default>'} ({compiler['source']})\")\n print(f\"- output: {output['path']} (temporary={output['temporary']}, kept={output['kept']})\")\n for warning in report.get(\"warnings\", []):\n print(f\"WARNING {warning}\")\n print(f\"- command: {report['command_text']}\")\n if report[\"status\"] == \"dry-run\":\n print(\"DRY-RUN SysConfig CLI was not executed.\")\n return\n stdout = str(report.get(\"stdout\", \"\")).strip()\n stderr = str(report.get(\"stderr\", \"\")).strip()\n if stdout:\n print(stdout)\n if stderr:\n print(stderr, file=sys.stderr)\n print(\n f\"RESULT status={report['status']} returncode={report['returncode']} \"\n f\"generated_files={len(report.get('generated_files', []))}\"\n )\n\n\ndef parse_args(argv: list[str] | None = None) -> argparse.Namespace:\n parser = argparse.ArgumentParser(\n description=\"Safely validate an MSPM0 .syscfg using TI SysConfig CLI.\"\n )\n parser.add_argument(\"project\", nargs=\"?\", default=\".\", help=\"MSPM0 project directory.\")\n parser.add_argument(\"--script\", help=\"Project-relative .syscfg path when more than one exists.\")\n parser.add_argument(\"--tool\", help=\"Explicit SysConfig CLI file or installation directory.\")\n parser.add_argument(\"--product\", help=\"Explicit MSPM0 SDK root or .metadata/product.json.\")\n parser.add_argument(\"--compiler\", help=\"Override the SysConfig compiler identifier.\")\n parser.add_argument(\"--strict\", action=\"store_true\", help=\"Treat SysConfig warnings as errors.\")\n parser.add_argument(\"--dry-run\", action=\"store_true\", help=\"Resolve and print without generating.\")\n parser.add_argument(\n \"--keep-output\",\n action=\"store_true\",\n help=\"Keep the newly created temporary output directory for inspection.\",\n )\n parser.add_argument(\"--json\", action=\"store_true\", help=\"Print machine-readable JSON.\")\n return parser.parse_args(argv)\n\n\ndef main(argv: list[str] | None = None) -> int:\n args = parse_args(argv)\n try:\n project = Path(args.project).resolve()\n info = inspect_project(project, args.script)\n tool, tool_warnings, tool_candidates = select_tool(info, args.tool)\n product, product_warnings, product_candidates = select_product(info, args.product)\n compiler, compiler_source = select_compiler(info, args.compiler)\n warnings = tool_warnings + product_warnings\n\n if args.dry_run:\n output = Path(tempfile.gettempdir()) / \"mspm0-sysconfig-\u003ctemporary>\"\n cleanup = None\n elif args.keep_output:\n output = Path(tempfile.mkdtemp(prefix=\"mspm0-sysconfig-\")).resolve()\n cleanup = None\n else:\n cleanup = tempfile.TemporaryDirectory(prefix=\"mspm0-sysconfig-\")\n output = Path(cleanup.name).resolve()\n\n cli_args = [\n \"--script\",\n info.script,\n \"--output\",\n str(output),\n \"--product\",\n product.path,\n ]\n if compiler:\n cli_args.extend([\"--compiler\", compiler])\n if args.strict:\n cli_args.append(\"--treatWarningsAsErrors\")\n command = command_for_tool(Path(tool.path), cli_args)\n report = build_report(\n info,\n tool,\n product,\n compiler,\n compiler_source,\n warnings,\n (tool_candidates, product_candidates),\n output,\n command,\n dry_run=args.dry_run,\n keep_output=args.keep_output,\n )\n\n if args.dry_run:\n exit_code = 0\n else:\n try:\n result = run_tool(Path(tool.path), cli_args, cwd=project)\n except (OSError, subprocess.SubprocessError) as exc:\n report[\"status\"] = \"error\"\n report[\"stderr\"] = str(exc)\n report[\"returncode\"] = 1\n exit_code = 1\n else:\n report[\"returncode\"] = result.returncode\n report[\"stdout\"] = result.stdout\n report[\"stderr\"] = result.stderr\n report[\"generated_files\"] = collect_generated_files(output)\n combined = f\"{result.stdout}\\n{result.stderr}\"\n has_warning = bool(warnings) or bool(\n re.search(r\"\\bwarning\\b\", combined, flags=re.IGNORECASE)\n )\n if result.returncode != 0:\n report[\"status\"] = \"error\"\n exit_code = 1\n elif args.strict and has_warning:\n report[\"status\"] = \"error\"\n exit_code = 1\n elif has_warning:\n report[\"status\"] = \"warning\"\n exit_code = 0\n else:\n report[\"status\"] = \"ok\"\n exit_code = 0\n\n if args.json:\n print(json.dumps(report, ensure_ascii=False, indent=2))\n else:\n print_text(report)\n if cleanup is not None:\n cleanup.cleanup()\n return exit_code\n except ResolutionError as exc:\n if args.json:\n print(json.dumps({\"status\": \"resolution-error\", \"error\": str(exc)}, ensure_ascii=False, indent=2))\n else:\n print(f\"ERROR {exc}\", file=sys.stderr)\n return 2\n\n\nif __name__ == \"__main__\":\n raise SystemExit(main())\n","content_type":"text/x-python; charset=utf-8","language":"python","size":37458,"content_sha256":"7ac1a6e8dcbb16f9f7db67eb1b9774ee1f2615de618cafa9e195d6937cf03ed0"},{"filename":"scripts/serial_console.py","content":"#!/usr/bin/env python3\n\"\"\"Small serial console for MSPM0 UART smoke tests.\"\"\"\n\nfrom __future__ import annotations\n\nimport argparse\nimport sys\nimport time\nfrom datetime import datetime\n\ntry:\n import serial\n import serial.tools.list_ports\nexcept ImportError as exc:\n raise SystemExit(\n \"pyserial is required. Install it with: python -m pip install pyserial\"\n ) from exc\n\n\ndef list_ports() -> int:\n ports = list(serial.tools.list_ports.comports())\n if not ports:\n print(\"No serial ports found.\")\n return 1\n for port in ports:\n print(f\"{port.device}\\t{port.description}\\t{port.hwid}\")\n return 0\n\n\ndef format_bytes(data: bytes, *, as_hex: bool, encoding: str) -> str:\n if as_hex:\n return \" \".join(f\"{byte:02X}\" for byte in data)\n return data.decode(encoding, errors=\"replace\")\n\n\ndef timestamp_prefix() -> str:\n now = datetime.now()\n return f\"[{now:%H:%M:%S}.{now.microsecond // 1000:03d}]\"\n\n\ndef parse_hex_payload(text: str) -> bytes:\n compact = text.replace(\",\", \" \").replace(\"0x\", \"\").replace(\"0X\", \"\")\n parts = compact.split()\n if len(parts) == 1 and len(parts[0]) > 2:\n compact = parts[0]\n if len(compact) % 2:\n raise ValueError(\"hex payload must contain an even number of digits\")\n parts = [compact[index : index + 2] for index in range(0, len(compact), 2)]\n try:\n return bytes(int(part, 16) for part in parts)\n except ValueError as exc:\n raise ValueError(f\"invalid hex payload: {text}\") from exc\n\n\ndef build_tx_payload(args: argparse.Namespace) -> bytes | None:\n if args.send is not None and args.send_hex is not None:\n raise ValueError(\"use only one of --send or --send-hex\")\n if args.send_hex is not None:\n payload = parse_hex_payload(args.send_hex)\n elif args.send is not None:\n payload = args.send.encode(args.encoding)\n else:\n return None\n\n if args.send_crlf:\n payload += b\"\\r\\n\"\n elif args.send_line or args.append_newline:\n payload += b\"\\n\"\n return payload\n\n\ndef open_serial(args: argparse.Namespace) -> serial.Serial:\n return serial.Serial(\n port=args.port,\n baudrate=args.baudrate,\n bytesize=args.bytesize,\n parity=args.parity,\n stopbits=args.stopbits,\n timeout=args.timeout,\n write_timeout=args.write_timeout,\n rtscts=args.rtscts,\n dsrdtr=args.dsrdtr,\n xonxoff=args.xonxoff,\n )\n\n\ndef run_console(args: argparse.Namespace) -> int:\n start = time.monotonic()\n received = 0\n\n try:\n payload = build_tx_payload(args)\n with open_serial(args) as ser:\n print(\n f\"Opened {ser.port} at {ser.baudrate} \"\n f\"{ser.bytesize}{ser.parity}{ser.stopbits}\"\n )\n\n sent_count = 0\n next_send = time.monotonic()\n if payload is not None and args.repeat \u003c 1:\n raise ValueError(\"--repeat must be at least 1\")\n\n while True:\n if payload is not None and sent_count \u003c args.repeat and time.monotonic() >= next_send:\n ser.write(payload)\n ser.flush()\n sent_count += 1\n print(f\"TX {len(payload)} bytes\")\n next_send = time.monotonic() + args.interval\n\n if args.duration is not None and time.monotonic() - start >= args.duration:\n break\n\n data = ser.read(args.chunk_size)\n if not data:\n continue\n\n received += len(data)\n text = format_bytes(data, as_hex=args.hex, encoding=args.encoding)\n if args.timestamp:\n prefix = timestamp_prefix()\n print(f\"{prefix} {text}\", end=\"\" if not args.hex else \"\\n\")\n else:\n print(text, end=\"\" if not args.hex else \"\\n\")\n sys.stdout.flush()\n\n except serial.SerialException as exc:\n print(f\"Serial error: {exc}\", file=sys.stderr)\n return 2\n except ValueError as exc:\n print(f\"Argument error: {exc}\", file=sys.stderr)\n return 2\n except KeyboardInterrupt:\n print()\n\n if args.duration is not None:\n print(f\"\\nDone. RX {received} bytes.\")\n return 0\n\n\ndef build_parser() -> argparse.ArgumentParser:\n parser = argparse.ArgumentParser(description=\"Read and write a UART serial port.\")\n parser.add_argument(\"--list\", action=\"store_true\", help=\"List available serial ports and exit.\")\n parser.add_argument(\"-p\", \"--port\", help=\"Serial port, such as COM6.\")\n parser.add_argument(\"-b\", \"--baudrate\", type=int, default=115200, help=\"Baud rate. Default: 115200.\")\n parser.add_argument(\"--bytesize\", type=int, default=8, choices=(5, 6, 7, 8), help=\"Data bits. Default: 8.\")\n parser.add_argument(\"--parity\", default=\"N\", choices=(\"N\", \"E\", \"O\", \"M\", \"S\"), help=\"Parity. Default: N.\")\n parser.add_argument(\"--stopbits\", type=float, default=1, choices=(1, 1.5, 2), help=\"Stop bits. Default: 1.\")\n parser.add_argument(\"--timeout\", type=float, default=0.2, help=\"Read timeout seconds. Default: 0.2.\")\n parser.add_argument(\"--write-timeout\", type=float, default=1.0, help=\"Write timeout seconds. Default: 1.0.\")\n parser.add_argument(\"--duration\", type=float, help=\"Read duration seconds. Omit to read until Ctrl+C.\")\n parser.add_argument(\"--chunk-size\", type=int, default=128, help=\"Read chunk size. Default: 128.\")\n parser.add_argument(\"--encoding\", default=\"utf-8\", help=\"Text encoding. Default: utf-8.\")\n parser.add_argument(\"--hex\", action=\"store_true\", help=\"Print received bytes as hex.\")\n parser.add_argument(\"--timestamp\", action=\"store_true\", help=\"Prefix received data with local timestamps.\")\n parser.add_argument(\"--send\", help=\"Text to send after opening the port.\")\n parser.add_argument(\"--send-line\", action=\"store_true\", help=\"Append LF to the sent payload. Useful for line-based MCU parsers.\")\n parser.add_argument(\"--append-newline\", action=\"store_true\", help=\"Deprecated alias for --send-line.\")\n parser.add_argument(\"--send-crlf\", action=\"store_true\", help=\"Append CRLF to the sent payload. If combined with --send-line, CRLF is used instead of LF.\")\n parser.add_argument(\"--send-hex\", help=\"Hex bytes to send, such as '01 02 0A' or '01020A'.\")\n parser.add_argument(\"--repeat\", type=int, default=1, help=\"Number of times to send the payload. Default: 1.\")\n parser.add_argument(\"--interval\", type=float, default=1.0, help=\"Seconds between repeated sends. Default: 1.0.\")\n parser.add_argument(\"--rtscts\", action=\"store_true\", help=\"Enable RTS/CTS flow control.\")\n parser.add_argument(\"--dsrdtr\", action=\"store_true\", help=\"Enable DSR/DTR flow control.\")\n parser.add_argument(\"--xonxoff\", action=\"store_true\", help=\"Enable software flow control.\")\n return parser\n\n\ndef main() -> int:\n parser = build_parser()\n args = parser.parse_args()\n if args.list:\n return list_ports()\n if not args.port:\n parser.error(\"--port is required unless --list is used\")\n return run_console(args)\n\n\nif __name__ == \"__main__\":\n raise SystemExit(main())\n","content_type":"text/x-python; charset=utf-8","language":"python","size":7225,"content_sha256":"ec985166febf397c207d2dc506299cd7f97adca677ed207bbe72d30709ea02ac"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"MSPM0 Agent Skill","type":"text"}]},{"type":"paragraph","content":[{"text":"Use this skill for TI MSPM0 firmware projects that use SysConfig and DriverLib through CCS / CCS Theia, Keil/uVision, or CMake + Arm GNU Toolchain + OpenOCD workflows. It is intended for Claude Code, OpenCode, OpenClaw, Continue, Cursor, Codex, and similar CLI/editor agents.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Default Workflow","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Locate the project ","type":"text"},{"text":".syscfg","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"system.syscfg","type":"text","marks":[{"type":"code_inline"}]},{"text":", editable source files, generated ","type":"text"},{"text":"ti_msp_dl_config.h","type":"text","marks":[{"type":"code_inline"}]},{"text":", and the active project entrypoint: ","type":"text"},{"text":"targetConfigs/*.ccxml","type":"text","marks":[{"type":"code_inline"}]},{"text":" for CCS, ","type":"text"},{"text":"*.uvprojx","type":"text","marks":[{"type":"code_inline"}]},{"text":" plus scatter file for Keil/uVision, or ","type":"text"},{"text":"CMakeLists.txt","type":"text","marks":[{"type":"code_inline"}]},{"text":" plus OpenOCD ","type":"text"},{"text":".cfg","type":"text","marks":[{"type":"code_inline"}]},{"text":" files for CMake/GCC/OpenOCD.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Run ","type":"text"},{"text":"python scripts/check_syscfg.py \u003cproject-dir>","type":"text","marks":[{"type":"code_inline"}]},{"text":" when this skill is available.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Read ","type":"text"},{"text":".syscfg","type":"text","marks":[{"type":"code_inline"}]},{"text":" metadata: device, package, SDK product, SysConfig version, modules, instances, pins, clocks, and interrupts.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Inspect generated ","type":"text"},{"text":"ti_msp_dl_config.h","type":"text","marks":[{"type":"code_inline"}]},{"text":" for macro names, IRQ names, instance names, and the exact SysConfig init function spelling.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Before adding unfamiliar SysConfig fields, inspect the user's existing ","type":"text"},{"text":".syscfg","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"examples/*/manifest.json","type":"text","marks":[{"type":"code_inline"}]},{"text":", TI SDK examples, or ","type":"text"},{"text":"source/ti/driverlib/.meta/*.syscfg.js","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Modify the smallest relevant ","type":"text"},{"text":".syscfg","type":"text","marks":[{"type":"code_inline"}]},{"text":" and application-code surface.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"By default, make the smallest evidence-based ","type":"text"},{"text":".syscfg","type":"text","marks":[{"type":"code_inline"}]},{"text":" edit and run ","type":"text"},{"text":"python scripts/run_sysconfig.py \u003cproject-dir>","type":"text","marks":[{"type":"code_inline"}]},{"text":" before rebuilding. Use CCS SysConfig MCP only when the user explicitly requests it or the current session already exposes a confirmed SysConfig MCP tool.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"If flashing or debugging, run ","type":"text"},{"text":"python scripts/detect_probe.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"python scripts/check_syscfg.py \u003cproject-dir> --probe","type":"text","marks":[{"type":"code_inline"}]},{"text":" before selecting a backend. Confirm the configured probe matches the connected hardware and prefer a System Reset after programming.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Core Rules","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Treat ","type":"text"},{"text":".syscfg","type":"text","marks":[{"type":"code_inline"}]},{"text":" as the source of truth for pinmux, peripheral setup, clocks, interrupts, DMA ownership, and generated initialization.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Prefer SysConfig + DriverLib for GPIO, UART, PWM, Timer, ADC, I2C, SPI, DMA, and clock setup.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Do not hand-edit generated outputs such as ","type":"text"},{"text":"Debug/ti_msp_dl_config.c","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"Debug/ti_msp_dl_config.h","type":"text","marks":[{"type":"code_inline"}]},{"text":", the project-root ","type":"text"},{"text":"ti_msp_dl_config.c","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"ti_msp_dl_config.h","type":"text","marks":[{"type":"code_inline"}]},{"text":" pair in Keil layouts, ","type":"text"},{"text":"device_linker.cmd","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"Objects/","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"Listings/","type":"text","marks":[{"type":"code_inline"}]},{"text":", object files, maps, or ","type":"text"},{"text":".out","type":"text","marks":[{"type":"code_inline"}]},{"text":" files.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Preserve ","type":"text"},{"text":".syscfg","type":"text","marks":[{"type":"code_inline"}]},{"text":" metadata such as ","type":"text"},{"text":"@cliArgs","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"@v2CliArgs","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"@versions","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"--device","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"--package","type":"text","marks":[{"type":"code_inline"}]},{"text":", and ","type":"text"},{"text":"--product","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Do not guess generated names. Read ","type":"text"},{"text":"ti_msp_dl_config.h","type":"text","marks":[{"type":"code_inline"}]},{"text":" and use the local macros and the local init function spelling, such as ","type":"text"},{"text":"SYSCFG_DL_init()","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Do not invent SysConfig fields, enum values, device metadata, board names, package names, or tool versions. Validate against local examples, SDK metadata, or SysConfig CLI.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"New SysConfig releases may explicitly recommend the CCS SysConfig MCP. This skill does not probe for or require that unverified backend by default: use it only when the user asks for MCP or the current session already exposes a confirmed SysConfig MCP tool. Otherwise use a minimal manual edit followed immediately by standalone CLI validation, and state that this does not provide the MCP's interactive mutation feedback.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Preserve unrelated user code, comments, copyright headers, project layout, and existing ","type":"text"},{"text":".syscfg","type":"text","marks":[{"type":"code_inline"}]},{"text":" settings. If a requested feature requires a larger rewrite, explain why before making it when possible.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Do not change device, package, SDK, compiler, CCS version, board, or debug probe without user confirmation.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"If the user asks only to \"flash\" or \"debug\", do not silently assume J-Link, XDS110, CMSIS-DAP/DAPLink, or ST-Link. Detect the connected probe first. If detection is unknown, multiple probes are connected, or the project configuration conflicts with the physical probe, stop and ask the user which backend to use.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Treat an empty probe-detector result as inconclusive, not proof that no probe is connected. Some DAPLink/CMSIS-DAP and XDS110 devices appear only as Windows ","type":"text"},{"text":"USBDevice","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"HIDClass","type":"text","marks":[{"type":"code_inline"}]},{"text":", or ","type":"text"},{"text":"Ports","type":"text","marks":[{"type":"code_inline"}]},{"text":" children. Inspect OS USB/PnP devices and serial ports (","type":"text"},{"text":"python scripts/serial_console.py --list","type":"text","marks":[{"type":"code_inline"}]},{"text":" on Windows), then try the intended backend's read-only probe/list command or ask the user before concluding the probe is absent.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"If SysConfig emits warnings, report them separately from build/flash success. Do not call a warning-producing generation \"clean\".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"If hardware behavior is not verified on a connected board, say that validation stopped at source, SysConfig, or build level.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Board-Specific Pin Caution","type":"text"}]},{"type":"paragraph","content":[{"text":"When the user explicitly says the board is LCKFB Tianmengxing MSPM0G3507:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Avoid choosing A21/PA21, A23/PA23, A02/PA02, and A18/PA18 for ordinary user-requested pin assignments unless the user asks for those pins or the local project already deliberately uses them.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"PA10 and PA11 are also marked as special, but Tianmengxing routes them as the default UART pins. When choosing pins for a UART, consider PA10 TX and PA11 RX first if they are free and match the requested UART instance. For GPIO, PWM, SPI, I2C, timer, or other non-UART uses, continue to treat PA10/PA11 as special pins and prefer other available pins.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"If the user asks to drive or reuse one of these special pins for a non-default purpose, remind them of the Tianmengxing board note. In particular, explain that repurposing PA10/PA11 can conflict with or remove the board's default UART connection.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Do not silently move an existing project away from these pins. Explain the board caveat first, then ask or proceed according to the user's intent.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Project Shape Checks","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Simple projects usually keep most logic in ","type":"text"},{"text":"main.c","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"empty.c","type":"text","marks":[{"type":"code_inline"}]},{"text":", or a small number of files. It is acceptable to make narrowly scoped edits there.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Framework projects often have multiple source directories such as ","type":"text"},{"text":"app/","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"bsp/","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"components/","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"core/","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"drivers/","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"hal/","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"middleware/","type":"text","marks":[{"type":"code_inline"}]},{"text":", or ","type":"text"},{"text":"tasks/","type":"text","marks":[{"type":"code_inline"}]},{"text":". First identify ownership boundaries before adding peripherals or changing control logic.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Do not assume every MSPM0 project is CCS-like or single-file. A framework project can still use CCS, Keil, or CMake/GCC/OpenOCD.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"For control code, confirm whether timing comes from a timer ISR, RTOS task delay, hardware PWM/ADC trigger chain, or a main-loop poll before changing periods or priorities.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Keil Project Checks","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Treat ","type":"text"},{"text":"system.syscfg","type":"text","marks":[{"type":"code_inline"}]},{"text":" and ","type":"text"},{"text":"ti_msp_dl_config.c","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"ti_msp_dl_config.h","type":"text","marks":[{"type":"code_inline"}]},{"text":" as the configuration source surface for Keil-based MSPM0 projects that keep SysConfig outputs at the project root.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Treat a Keil ","type":"text"},{"text":".uvprojx","type":"text","marks":[{"type":"code_inline"}]},{"text":" as the project entrypoint, the scatter file as the linker source of truth, and ","type":"text"},{"text":"Objects/","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"Listings/","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"*.uvoptx","type":"text","marks":[{"type":"code_inline"}]},{"text":", build logs, and generated outputs as inspection-only unless a request explicitly targets them.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"For a project's application code, follow its own source layout rather than assuming CCS defaults.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"CMake / GCC / OpenOCD Checks","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Treat ","type":"text"},{"text":"CMakeLists.txt","type":"text","marks":[{"type":"code_inline"}]},{"text":", toolchain files, and OpenOCD ","type":"text"},{"text":".cfg","type":"text","marks":[{"type":"code_inline"}]},{"text":" files as the project entrypoints for CMake/GCC/OpenOCD projects.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Build through the existing CMake build directory when present, for example ","type":"text"},{"text":"cmake --build cmake-build-debug --target \u003ctarget>","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"MSPM0 OpenOCD flashing usually requires a TI MSPM0-capable OpenOCD build or TI extension branch. If OpenOCD reports ","type":"text"},{"text":"unable to find a matching CMSIS-DAP device","type":"text","marks":[{"type":"code_inline"}]},{"text":", report that as probe discovery failure rather than firmware failure.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Do not require CCS ","type":"text"},{"text":"targetConfigs/*.ccxml","type":"text","marks":[{"type":"code_inline"}]},{"text":" when the active project uses OpenOCD instead of DSLite.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"FreeRTOS Checks","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"If ","type":"text"},{"text":"FreeRTOSConfig.h","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"FreeRTOS.h","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"task.h","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"xTaskCreate","type":"text","marks":[{"type":"code_inline"}]},{"text":", or ","type":"text"},{"text":"vTaskStartScheduler","type":"text","marks":[{"type":"code_inline"}]},{"text":" are present, treat the project as RTOS-aware.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Keep RTOS handling lightweight: respect existing task, queue, ISR, and blocking-call boundaries; do not impose a specific framework architecture unless the user asks.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Ambiguous Requests","type":"text"}]},{"type":"paragraph","content":[{"text":"If the user omits important hardware parameters, do not silently choose risky values.","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"For low-risk defaults, use this skill's ","type":"text"},{"text":"examples/","type":"text","marks":[{"type":"code_inline"}]},{"text":" or local TI SDK examples, then tell the user which defaults were applied.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"For important parameters, ask before editing and offer a concrete recommendation.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Important missing parameters include pin, peripheral instance, UART baud/data/parity/stop bits, Timer period, PWM frequency/duty/polarity, ADC channel/reference/sample time, DMA direction/source/destination, interrupt priority, and external-module power/logic levels.","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Example: if the user asks \"add a timer interrupt\", ask which timer and period they want, and recommend a starter such as TIMG at 1 ms or 10 ms if they are unsure.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"External Modules And Hardware Debugging","type":"text"}]},{"type":"paragraph","content":[{"text":"When asked to drive an external module, sensor, motor driver, servo, display, radio, or custom board:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Ask for the module datasheet, schematic, pin map, supply voltage, logic level, communication protocol, and key parameters when they are not available.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Verify wiring assumptions before blaming code: power, ground, pull-ups, level shifting, reset/enable pins, boot pins, chip select, UART TX/RX crossover, I2C address, SPI mode, PWM polarity, and shared pins.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"If repeated attempts fail and SysConfig, build, flash, and code logic look correct, explicitly raise the possibility of wiring, power, module mode, datasheet mismatch, damaged hardware, or wrong test procedure.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Separate \"firmware looks correct\" from \"hardware proved correct\".","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Reference Selection","type":"text"}]},{"type":"paragraph","content":[{"text":"Read references only when needed:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/project_workflows.md","type":"text","marks":[{"type":"code_inline"}]},{"text":": ","type":"text"},{"text":".syscfg","type":"text","marks":[{"type":"code_inline"}]},{"text":" editing, CCS / Keil / CMake project layout, SDK schema lookup, SysConfig CLI, builds, DSLite/J-Link, and OpenOCD.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/driverlib_runtime_rules.md","type":"text","marks":[{"type":"code_inline"}]},{"text":": DriverLib usage, interrupts, clock tree, delays, and common runtime mistakes.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/hardware_validation_notes.md","type":"text","marks":[{"type":"code_inline"}]},{"text":": verified Tianmengxing MSPM0G3507 lessons, HFXT warnings, flash/reset behavior, and real-board caveats.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/debug_backends.md","type":"text","marks":[{"type":"code_inline"}]},{"text":": CCS-DSS and OpenOCD/GDB probe, flash, breakpoint, retry, and manual-unlock workflows.","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"examples/","type":"text","marks":[{"type":"code_inline"}]},{"text":" as one source for reusable tested patterns. Prefer ","type":"text"},{"text":"scripts/list_examples.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" to inspect available examples before opening individual example files, but do not assume packaged examples outrank the user's existing project structure or official TI SDK examples.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Examples","type":"text"}]},{"type":"paragraph","content":[{"text":"Each reusable example should contain:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"text"},"content":[{"text":"examples/\u003cname>/\n├─ example.syscfg\n├─ README.md\n├─ manifest.json\n└─ src/\n └─ source files copied from the minimal relevant project surface","type":"text"}]},{"type":"paragraph","content":[{"text":"Do not require users to drop full CCS projects into ","type":"text"},{"text":"examples/","type":"text","marks":[{"type":"code_inline"}]},{"text":". Use ","type":"text"},{"text":"scripts/capture_example.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" to extract a compact example package from a real project.","type":"text"}]},{"type":"paragraph","content":[{"text":"When applying an example to a user project:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Treat skill examples as proven references, not mandatory project templates.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Copy only the needed ","type":"text"},{"text":".syscfg","type":"text","marks":[{"type":"code_inline"}]},{"text":" fields, generated-name expectations, code pattern, or debugging lesson.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Preserve the user's existing file layout and naming. If an example uses ","type":"text"},{"text":"BSP/","type":"text","marks":[{"type":"code_inline"}]},{"text":", do not create ","type":"text"},{"text":"BSP/","type":"text","marks":[{"type":"code_inline"}]},{"text":" in the user project unless the user asked for that structure or the project already follows it.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Prefer the user's local style when it conflicts with an example's directory names, wrapper names, or layering.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Consider official TI SDK examples and local SDK metadata at the same or higher priority when they better match the user's board, SDK version, peripheral, or toolchain.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"For DMA UART examples, keep TX buffers per UART instance, avoid shared static printf buffers, and choose RX handling per port: ISR callback for the one port that needs immediate line parsing, ","type":"text"},{"text":"UART_poll()","type":"text","marks":[{"type":"code_inline"}]},{"text":" for extra receive ports, or TX-only init for ports that do not receive.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"For periodic timer interrupts, configure the TIMER instance and interrupt in ","type":"text"},{"text":".syscfg","type":"text","marks":[{"type":"code_inline"}]},{"text":", confirm the generated load value against the generated CPU clock, enable the generated IRQ in application code, and keep the ISR short.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Tools","type":"text"}]},{"type":"paragraph","content":[{"text":"Run bundled scripts with Python 3.10 or newer. ","type":"text"},{"text":"serial_console.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" additionally requires ","type":"text"},{"text":"pyserial","type":"text","marks":[{"type":"code_inline"}]},{"text":"; if import fails, tell the user to run ","type":"text"},{"text":"python -m pip install pyserial","type":"text","marks":[{"type":"code_inline"}]},{"text":". TI SDK, SysConfig, CCS/UniFlash, OpenOCD, and GDB remain external workflow dependencies and are not installed by this skill.","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"python scripts/check_syscfg.py \u003cproject-dir>","type":"text","marks":[{"type":"code_inline"}]},{"text":": static project check for ","type":"text"},{"text":".syscfg","type":"text","marks":[{"type":"code_inline"}]},{"text":", generated files, pins, init spelling, project shape, CCS/Keil/CMake/OpenOCD clues, build output, target config, and validation hints.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"python scripts/run_sysconfig.py \u003cproject-dir>","type":"text","marks":[{"type":"code_inline"}]},{"text":": discover the project-declared SysConfig and MSPM0 SDK versions, then validate the selected ","type":"text"},{"text":".syscfg","type":"text","marks":[{"type":"code_inline"}]},{"text":" into an isolated temporary directory without overwriting project outputs. Use ","type":"text"},{"text":"--tool","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"--product","type":"text","marks":[{"type":"code_inline"}]},{"text":" only for an intentional explicit override.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"python scripts/detect_probe.py","type":"text","marks":[{"type":"code_inline"}]},{"text":": read-only connected-probe detection for common CMSIS-DAP/DAPLink, J-Link, XDS110, and ST-Link hardware; an empty result is explicitly inconclusive and requires OS/backend fallback checks.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"python scripts/check_syscfg.py \u003cproject-dir> --probe","type":"text","marks":[{"type":"code_inline"}]},{"text":": run the static check, detect connected probes, compare them with project hints, and suppress unsafe flash suggestions when a CCS ","type":"text"},{"text":".ccxml","type":"text","marks":[{"type":"code_inline"}]},{"text":" conflicts with the physical probe.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"python scripts/list_examples.py","type":"text","marks":[{"type":"code_inline"}]},{"text":": list packaged examples from ","type":"text"},{"text":"examples/*/manifest.json","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"python scripts/capture_example.py \u003cproject-dir> --name \u003cexample-name> --include \u003cglob>","type":"text","marks":[{"type":"code_inline"}]},{"text":": package selected source files and ","type":"text"},{"text":".syscfg","type":"text","marks":[{"type":"code_inline"}]},{"text":" from a user project into ","type":"text"},{"text":"examples/\u003cexample-name>/","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"python scripts/index_syscfg_examples.py \u003cmspm0-sdk-root> --board LP_MSPM0G3507 --module UART","type":"text","marks":[{"type":"code_inline"}]},{"text":": search local TI SDK examples and module metadata.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"python scripts/serial_console.py --list","type":"text","marks":[{"type":"code_inline"}]},{"text":": list serial ports.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"python scripts/ccs_dss_debug.py \u003cproject-dir> probe --leave-running","type":"text","marks":[{"type":"code_inline"}]},{"text":": connect through CCS Debug Server Scripting, read reset/register state, verify the configured ","type":"text"},{"text":".ccxml","type":"text","marks":[{"type":"code_inline"}]},{"text":" debug path, and continue the target before disconnecting.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"python scripts/ccs_dss_debug.py \u003cproject-dir> load-symbols --symbol main","type":"text","marks":[{"type":"code_inline"}]},{"text":": load debug symbols from ","type":"text"},{"text":".out","type":"text","marks":[{"type":"code_inline"}]},{"text":" without programming flash.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"python scripts/openocd_debug.py \u003cproject-dir> probe","type":"text","marks":[{"type":"code_inline"}]},{"text":": connect through OpenOCD, halt briefly, report target state, and resume.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"python scripts/openocd_debug.py \u003cproject-dir> flash","type":"text","marks":[{"type":"code_inline"}]},{"text":": flash, verify, and reset-run an auto-detected ","type":"text"},{"text":".out","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":".elf","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":".axf","type":"text","marks":[{"type":"code_inline"}]},{"text":", or ","type":"text"},{"text":".hex","type":"text","marks":[{"type":"code_inline"}]},{"text":" output through OpenOCD.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"python scripts/openocd_debug.py \u003cproject-dir> run-to-symbol --symbol main","type":"text","marks":[{"type":"code_inline"}]},{"text":": use OpenOCD + ","type":"text"},{"text":"arm-none-eabi-gdb","type":"text","marks":[{"type":"code_inline"}]},{"text":" to reset and run to a symbol breakpoint.","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"For the verified CH340 setup, use ","type":"text"},{"text":"python scripts/serial_console.py -p COM6 -b 115200 --timestamp --duration 10","type":"text","marks":[{"type":"code_inline"}]},{"text":" after closing other serial tools such as VOFA+. For line-based MCU parsers, send one test frame and wait for the echo with ","type":"text"},{"text":"python scripts/serial_console.py -p COM6 -b 115200 --send \"ping\" --send-line --timestamp --duration 3","type":"text","marks":[{"type":"code_inline"}]},{"text":". Use ","type":"text"},{"text":"--send-hex \"00 00 80 3F\"","type":"text","marks":[{"type":"code_inline"}]},{"text":" when testing binary payloads.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Flash Backends","type":"text"}]},{"type":"paragraph","content":[{"text":"Before selecting a flash backend for a vague request such as \"flash this project\", run:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"text"},"content":[{"text":"python scripts/detect_probe.py\npython scripts/check_syscfg.py \u003cproject-dir> --probe","type":"text"}]},{"type":"paragraph","content":[{"text":"Probe detection is read-only. Do not flash when multiple probes are connected, detection is unknown, or the physical probe conflicts with the project configuration until the user confirms the intended backend. On Windows, if no probe is identified, inspect ","type":"text"},{"text":"Get-PnpDevice -PresentOnly","type":"text","marks":[{"type":"code_inline"}]},{"text":" and ","type":"text"},{"text":"python scripts/serial_console.py --list","type":"text","marks":[{"type":"code_inline"}]},{"text":"; a debug probe may expose a CMSIS-DAP/XDS interface or virtual COM port outside the generic USB device class.","type":"text"}]},{"type":"paragraph","content":[{"text":"The verified CCS flash path is DSLite / UniFlash with J-Link. For automated flashing after clock-tree changes, prefer DSLite System Reset:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"text"},"content":[{"text":"dslite -c \u003ctarget.ccxml> -e -r 2 -u \u003cproject.out>","type":"text"}]},{"type":"paragraph","content":[{"text":"For CMake/GCC/OpenOCD projects, use the project's existing flash target or explicit OpenOCD config. The packaged ","type":"text"},{"text":"openocd_debug.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" helper can also flash an existing compatible output. Keep the backend explicit and report probe-discovery errors separately from build success.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Debug Backends","type":"text"}]},{"type":"paragraph","content":[{"text":"Keep CCS-DSS and OpenOCD/GDB as separate backends. Read ","type":"text"},{"text":"references/debug_backends.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" before debugging or diagnosing repeated probe failures.","type":"text"}]},{"type":"paragraph","content":[{"text":"For CCS / CCS Theia / UniFlash-style projects with a matching ","type":"text"},{"text":"targetConfigs/*.ccxml","type":"text","marks":[{"type":"code_inline"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"text"},"content":[{"text":"python scripts/ccs_dss_debug.py \u003cproject-dir> probe --leave-running","type":"text"}]},{"type":"paragraph","content":[{"text":"For OpenOCD-capable MSPM0 projects:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"text"},"content":[{"text":"python scripts/openocd_debug.py \u003cproject-dir> probe","type":"text"}]},{"type":"paragraph","content":[{"text":"The CCS-DSS physical probe is selected by ","type":"text"},{"text":".ccxml","type":"text","marks":[{"type":"code_inline"}]},{"text":"; it is not inherently J-Link-only. Use symbol-only loading when firmware is already flashed and rewriting flash is unnecessary. For OpenOCD, do not run concurrent operations against one probe. Neither backend should silently issue destructive recovery. If a target appears locked or protected, first separate probe/wiring/reset faults, application startup faults, SWD password or security policy, invalid NONMAIN configuration, and an interrupted-flash recovery state. On a Tianmengxing MSPM0G3507, a readable SWD DPIDR followed by repeated ","type":"text"},{"text":"Could not find MEM-AP to control the core","type":"text","marks":[{"type":"code_inline"}]},{"text":" errors was reproduced after programming was interrupted; follow the UART BSL recovery boundary in ","type":"text"},{"text":"references/debug_backends.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" instead of treating this as proof that the probe is absent. With CCS-DSS and a matching XDS target configuration, a read-only ","type":"text"},{"text":"CFGAP_BOOTDIAG","type":"text","marks":[{"type":"code_inline"}]},{"text":" check can work even when the Cortex-M0+ session cannot connect. Only use BSL Mass Erase, DSSM Mass Erase, or Factory Reset after the user explicitly authorizes data loss, and follow ","type":"text"},{"text":"references/debug_backends.md","type":"text","marks":[{"type":"code_inline"}]},{"text":"; never infer success from a reset pulse or a timed-out command. Debug actions can halt the CPU, so report that risk before using breakpoints or register inspection on real-time control hardware.","type":"text"}]}]},"metadata":{"date":"2026-11-02","name":"mspm0-ccs","author":"@skillopedia","source":{"stars":377,"repo_name":"mspm0-skill","origin_url":"https://github.com/mc3545dada/mspm0-skill/blob/HEAD/skills/mspm0-ccs/SKILL.md","repo_owner":"mc3545dada","body_sha256":"5ce6c256c17c02fd24aa3aa0bfe1521469d95a594b319e01da3edb0af8ae510b","cluster_key":"023aa0837f736b08c30d0f07a9cb475110669d7d9d98f90cc4cf14a85559ed63","clean_bundle":{"format":"clean-skill-bundle-v1","source":"mc3545dada/mspm0-skill/skills/mspm0-ccs/SKILL.md","text_bytes":251627,"source_commit":"0cea5a0b234fbd8f0d4a14c2a08e6a9b92147315","skills_sh_rank":19716,"attachment_count":39,"text_attachments":39,"attachment_storage":"skill_attachments","binary_attachments":0},"cluster_size":1,"skill_md_path":"skills/mspm0-ccs/SKILL.md","import_metadata":{"date":"2026-11-02","author":"@skillopedia","version":"v1","category":"software-engineering","category_label":"Engineering"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"software-engineering","import_tag":"skills-sh-top20k-2026-11","description":"Tool-neutral CLI agent rules for TI MSPM0 development with Code Composer Studio, Keil/uVision, CMake/GCC/OpenOCD, SysConfig, and DriverLib. Use when an agent needs to inspect or modify MSPM0 projects, edit .syscfg configuration, avoid generated SysConfig/build files, use DriverLib APIs, validate SysConfig output, package reusable MSPM0 examples, or work on NUEDC-style MSPM0 embedded firmware."}},"renderedAt":1793666414148}

MSPM0 Agent Skill Use this skill for TI MSPM0 firmware projects that use SysConfig and DriverLib through CCS / CCS Theia, Keil/uVision, or CMake + Arm GNU Toolchain + OpenOCD workflows. It is intended for Claude Code, OpenCode, OpenClaw, Continue, Cursor, Codex, and similar CLI/editor agents. Default Workflow 1. Locate the project or , editable source files, generated , and the active project entrypoint: for CCS, plus scatter file for Keil/uVision, or plus OpenOCD files for CMake/GCC/OpenOCD. 2. Run when this skill is available. 3. Read metadata: device, package, SDK product, SysConfig versio…