← Commit history
design/mcu-pinmap.json+7−7
@@ -1,4 +1,8 @@ {+  "inputSha256": {+    "design/netlist.json": "de7b88e327356a7d269f0a043e2bfc56a6760d00868564b0740bea3f79dc3bfd",+    "kicad/adom-custom-electronic-load.kicad_pcb": "b2a4d8321f24af5d3f95f9df6fab570b96abb298b4cc70b3f932037d2fec9f8d"+  },   "part": "STM32G0B1KCT6",   "package": "LQFP32 GP, not the N-suffix variant",   "source": "https://www.st.com/resource/en/datasheet/stm32g0b1kc.pdf",@@ -112,7 +116,7 @@       "packagePin": 27,       "gpio": "PB3",       "net": "FAULT_CLEAR",-      "plannedFunction": "GPIO output; polarity requires latch-chain audit"+      "plannedFunction": "GPIO open-drain, LOW asserts fault clear through D2; never push-pull HIGH"     },     {       "packagePin": 30,@@ -129,12 +133,8 @@   ],   "limits": [     "Static assignment audit only; HAL and option-byte validation pending",-    "USB clock recovery, VBUS detection and self-powered descriptors pending",+    "USB bring-up adapter compiled; clock recovery, VBUS detection and enumeration physically unverified",     "Tach EXTI timestamps require a 32-bit microsecond timebase and measured ISR latency",     "Boot identity must be unique on every reset; no fixed production boot nonce"-  ],-  "inputSha256": {-    "design/netlist.json": "de7b88e327356a7d269f0a043e2bfc56a6760d00868564b0740bea3f79dc3bfd",-    "kicad/adom-custom-electronic-load.kicad_pcb": "b2a4d8321f24af5d3f95f9df6fab570b96abb298b4cc70b3f932037d2fec9f8d"-  }+  ] }
design/stm32-bringup-build.jsonadded+57
@@ -0,0 +1,57 @@+{+  "status": "compiled-only-output-locked",+  "flashed": false,+  "physical_usb_verified": false,+  "load_enable_supported": false,+  "production_boot_freshness": false,+  "lab_boot_id": "lab20261009bringup",+  "vid": 51966,+  "pid": 16385,+  "toolchain": "arm-none-eabi-gcc (15:13.2.rel1-2) 13.2.1 20231009",+  "dependencies": {+    "tinyusb": {+      "commit": "5f3d88cdbe87ede4fcaddc6a095dcf2edb100f65",+      "url": "https://github.com/hathach/tinyusb.git"+    },+    "cmsis_device_g0": {+      "commit": "f484fe852535f913a02ee79787eafa74dd7f9488",+      "url": "https://github.com/STMicroelectronics/cmsis_device_g0.git"+    },+    "stm32g0xx_hal_driver": {+      "commit": "a248a9e484d58943b46c68f6c49b4b276778bd59",+      "url": "https://github.com/STMicroelectronics/stm32g0xx_hal_driver.git"+    },+    "CMSIS_5": {+      "commit": "2b7495b8535bdcb306dac29b9ded4cfb679d7e5c",+      "url": "https://github.com/ARM-software/CMSIS_5.git"+    }+  },+  "sources": {+    "firmware/fan_tach.h": "028b3525480ba81a935167297f33b190eee7836a82ae41cca520043bd430543d",+    "firmware/instruments.h": "1bcd895abf8fe74c5a96028b8b559eafdff0919e970244d4445ccbd72b7a6ee6",+    "firmware/load_core.c": "c7d70b9d095a54821b92bff8097c89cfb80b3d7f17f7e44e10bb7e254c9a2a3e",+    "firmware/load_core.h": "408263af21e6c15e82f4118343a2b7d0dd2db61808754c0b91021acd1146fadf",+    "firmware/load_protocol.c": "208d7e7fb9a05da31c3c200b018f5b188e53ac3d95ac2288a61f683b4f3df1af",+    "firmware/load_protocol.h": "f64f6b689d57501031515e8ee9f8c8349a2cea63738e73db16f95e747caf91fb",+    "firmware/stm32/README.md": "0d3c5c029a73e98f22d1f9520c367b3740a26d00c2fbaab70ed06a2307758972",+    "firmware/stm32/clock.c": "f42f5c1ff229b065a048218ecc575624276aaa229e0bc340d80c80eec35416d2",+    "firmware/stm32/dependencies.json": "7e8f3c17a59c856371a9f411dce6a9dadafbb8c8edd5ede5e4e5cf46b1567e92",+    "firmware/stm32/licenses/CMSIS_5-LICENSE.txt": "b40930bbcf80744c86c46a12bc9da056641d722716c378f5659b9e555ef833e1",+    "firmware/stm32/licenses/cmsis_device_g0-LICENSE.txt": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",+    "firmware/stm32/licenses/stm32g0xx_hal_driver-LICENSE.txt": "3564c849dfd5e628732afb7933ccb1c983b53f7ac6bb237b6177691339082671",+    "firmware/stm32/licenses/tinyusb-LICENSE.txt": "b01185698f530f4f61b28f42d5a4d6bbe7834bde6a63f00773235628a7bdce22",+    "firmware/stm32/main.c": "c089315fab9ffc3315508f44132039dfbf5b51e3c089260adf7d4e009963881a",+    "firmware/stm32/stm32g0b1kc.ld": "1c938076e760300379115ee955589434dba7b84d1bb945dd41cf39abd342fd13",+    "firmware/stm32/stm32g0xx_hal_conf.h": "2e2a3aed4bf01ce3f890df69061e740369ed8839bb53d5b1be745be4de185b6f",+    "firmware/stm32/syscalls.c": "bbfcedecfe5f33380424ab90cdb89c842c6a5717e01298a29ec43aef24c1524d",+    "firmware/stm32/tusb_config.h": "dfbb343cc609aa2693058b7d7e6e6c487524222cbe3eab5296568eca0b7d3970",+    "firmware/stm32/usb_descriptors.c": "ed2666d7115f05a07088dd92ebf35a600aadd8d9878fae2eb7635201b8f0b2a9",+    "tools/build_stm32_bringup.py": "2a199449eb8c9f5d51a9ab9250f7ca988b19b736b5fb843a347c6cdcceca9077"+  },+  "artifacts": {+    "adom-load-bringup.hex": "789ab63e515857a23c11f17d343ca44ddd4f80f948631453c282b378b445db6f",+    "adom-load-bringup.bin": "a4da063939102f26ba5bcb18514f17c2c21526f9edc84de3740a7f8e67f8f0c4",+    "adom-load-bringup.map": "8fc7fea88c187a2c20728b33ad4821837a97da215d3dae228b67fbfda4b2d749",+    "adom-load-bringup.elf": "9d8ce4ce939c4dea734d0b39af6d80012086d6f1749877882f67f78204d10f09"+  }+}
design/stm32-bringup-build.logadded+8
@@ -0,0 +1,8 @@+Memory region         Used Size  Region Size  %age Used+             RAM:       23912 B       144 KB     16.22%+           FLASH:       63108 B       256 KB     24.07%+   text	   data	    bss	    dec	    hex	filename+  61352	   1752	  22160	  85264	  14d10	/home/adom/project/adom-custom-electronic-load/build/stm32-bringup/adom-load-bringup.elf+COMPILED ONLY: output permanently locked OFF; no flash or hardware validation performed.+OK: external command completed; its running time is in this session+Hint: Use exec for build, browser automation and other work outside AI Flow. Do not start an idle heartbeat; only actual work counts.
docs/completion-plan.md+1−1
@@ -4,7 +4,7 @@ The active objective is to finish this electronic-load design through AIFlow, th  ## Latest accepted board -AIFlow aiflow/run/board-14.kicad_pcb, native-saved SHA-256 `b2a4d8321f24af5d3f95f9df6fab570b96abb298b4cc70b3f932037d2fec9f8d`. Cooling-clearance changes and five verified vias are landed. Native candidate DRC: zero errors/opens, fifteen library lookup warnings; saved physical copper matches. Current step: thermal-vias, with unacknowledged shortfalls. Three 3 A current-neck flags and the external case-cooling model remain unresolved. Portable device protocol and host interoperability checks pass.+AIFlow aiflow/run/board-14.kicad_pcb, native-saved SHA-256 `b2a4d8321f24af5d3f95f9df6fab570b96abb298b4cc70b3f932037d2fec9f8d`. Cooling-clearance changes and five verified vias are landed. Native candidate DRC: zero errors/opens, fifteen library lookup warnings; saved physical copper matches. Current step: thermal-vias, with unacknowledged shortfalls. Three 3 A current-neck flags and the external case-cooling model remain unresolved. Portable device protocol and host interoperability checks pass. A pinned, output-locked STM32 USB bring-up image compiles; it has not been flashed and the functional HAL is incomplete.  ## Resume here 
docs/status.md+4
@@ -1,3 +1,7 @@+# STM32 compile checkpoint — 2026-10-09++The output-locked STM32G0B1KCT6 USB bring-up adapter now builds with pinned TinyUSB/CMSIS/HAL sources and GNU Arm 13.2.1. The link uses 63,108 bytes of flash and 23,912 bytes of RAM including the reserved stack/heap sections. ELF, HEX and BIN artifacts exist locally with hashes. The board-specific initialization keeps PA5 enable LOW and PB3 fault-clear open drain; no Nucleo LED code is linked. No image was flashed. USB enumeration, actual sensors, tach capture, actuator control and reset-fresh boot identity remain unfinished. The example USB identity is lab-only. See [build instructions](../firmware/stm32/README.md), [build evidence](../design/stm32-bringup-build.json), and [compiler output](../design/stm32-bringup-build.log).+ # Thermal-via and protocol checkpoint — 2026-10-09  AIFlow adopted aiflow/run/board-14.kicad_pcb (native SHA-256 `b2a4d8321f24af5d3f95f9df6fab570b96abb298b4cc70b3f932037d2fec9f8d`). Five vias were added after isolated native DRC: two SHUNT_P thermal vias, two LOAD_POS diode vias and one GND stitch that prevents an isolated ground region. Saved native copper matches the checked candidate; its native DRC has zero errors/opens and fifteen existing library lookup warnings. The thermal-via heuristic still reports D1 6/10, Q1 0/16 and RSH1 2/6; no shortfall was acknowledged.
firmware/stm32/README.mdadded+30
@@ -0,0 +1,30 @@+# STM32G0B1KCT6 USB bring-up image++This adapter compiles for the routed LQFP32 GP package. **Output is permanently locked OFF.** It is not a released load controller and has not been flashed or tested on hardware. The lab identity below is TinyUSB's example identity, not an Adom-assigned commercial USB identity.++The adapter sets PA5 (MCU_ENABLE), PA4 (ARM_CLK), and PA6 (WDI) low before clock setup. PB3 (FAULT_CLEAR) is open drain and held low. It does not import the Nucleo LED code, because that example toggles our enable pin. Hard-fault and fatal initialization paths deassert enable. USB disconnect/suspend/DTR loss drops protocol ownership. USB attachment follows PB0 VBUS detection. The image never releases the hardware latch or writes a nonzero DAC command.++Telemetry is unavailable (`null` measurements, invalid sensors), and assembly qualification is false. The portable protocol and ownership/replay checks run over CDC, with bounded input work and bounded reply buffering. This proves a linkable implementation, not boot timing, interrupt latency, USB compliance, or operation of the board's interlocks. Reset-time pulldowns and physical faults still require bench verification.++## Reproduce++Fetch the repositories in [dependencies.json](dependencies.json) at their exact commits. The expected arrangement is the TinyUSB tree with `hw/mcu/st/cmsis_device_g0`, `hw/mcu/st/stm32g0xx_hal_driver`, and `lib/CMSIS_5`. `python3 tools/get_deps.py stm32g0` in the pinned TinyUSB checkout fetches these dependencies. The build refuses a different commit or modified tracked dependency files. Upstream licenses are retained in [licenses](licenses).++The checked compiler is GNU Arm Embedded 13.2.1 from Ubuntu's `gcc-arm-none-eabi` package version `15:13.2.rel1-2`, with `binutils-arm-none-eabi` `2.42-1ubuntu1+23`, `libnewlib-arm-none-eabi` and `libnewlib-dev` `4.4.0.20231231-2`. Download with `apt-get download` and extract with `dpkg-deb -x` into an isolated directory; no system installation is required.++From the project root:++```sh+python3 tools/build_stm32_bringup.py \+  --tinyusb /path/to/tinyusb \+  --toolchain-root /path/to/extracted-packages \+  --vid 0xcafe --pid 0x4001 --lab-boot-id lab20261009bringup+```++Outputs are ELF, HEX, BIN, map, stack-usage files and a hash/command manifest under `build/stm32-bringup`. The script never flashes a device. Newlib's heap is capped at 8 KB; the linker reserves an 8 KB stack. Measured stack high-water and worst-case execution time are still needed.++The explicitly supplied lab boot ID is **not fresh across resets**. Production firmware requires an allocation-backed USB VID/PID and verified per-boot identity persistence before enabling any load. Do not deploy this example identity or treat its same-boot sequence counter as reset-safe replay protection.++## Remaining adapter work++ADC calibration and temperature conversion; INA226/DAC60501 I2C integration and readback; 32-bit tach timestamp capture and ISR latency; physical watchdog/latch handshake; reset/brownout and auxiliary/USB power sequencing; production boot identity; integration of qualified assembly configuration; fault injection and USB reconnect tests on the actual PCB. Only then can a separately reviewed functional adapter enable the load.
firmware/stm32/clock.cadded+90
@@ -0,0 +1,90 @@+/*+ * The MIT License (MIT)+ *+ * Copyright (c) 2020, Ha Thach (tinyusb.org)+ * Copyright (c) 2023, HiFiPhile+ *+ * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ *+ * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ *+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+ * THE SOFTWARE.+ *+ * This file is part of the TinyUSB stack.+ */++/* metadata:+   name: STM32 G0B1 Nucleo+   url: https://www.st.com/en/evaluation-tools/nucleo-g0b1re.html+*/+++#include "stm32g0xx_hal.h"+#include <stdbool.h>+bool load_clock_init(void)+{+  RCC_OscInitTypeDef RCC_OscInitStruct = {0};+  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};++  /** Configure the main internal regulator output voltage */+  if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK) return false;++  /** Initializes the RCC Oscillators according to the specified parameters+  * in the RCC_OscInitTypeDef structure. */+  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;+  RCC_OscInitStruct.HSIState = RCC_HSI_ON;+  RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;+  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;+  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;+  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;+  RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV1;+  RCC_OscInitStruct.PLL.PLLN = 8;+  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;+  RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;+  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;+  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) return false;++  /** Initializes the CPU, AHB and APB buses clocks */+  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1;+  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;+  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;+  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;+  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) return false;++  // Configure CRS clock source+  __HAL_RCC_CRS_CLK_ENABLE();+  RCC_CRSInitTypeDef RCC_CRSInitStruct = {0};+  RCC_CRSInitStruct.Prescaler = RCC_CRS_SYNC_DIV1;+  RCC_CRSInitStruct.Source = RCC_CRS_SYNC_SOURCE_USB;+  RCC_CRSInitStruct.Polarity = RCC_CRS_SYNC_POLARITY_RISING;+  RCC_CRSInitStruct.ReloadValue = __HAL_RCC_CRS_RELOADVALUE_CALCULATE(48000000,1000);+  RCC_CRSInitStruct.ErrorLimitValue = 34;+  RCC_CRSInitStruct.HSI48CalibrationValue = 32;++  HAL_RCCEx_CRSConfig(&RCC_CRSInitStruct);++  /* Select HSI48 as USB clock source */+  RCC_PeriphCLKInitTypeDef usb_clk = {0 };+  usb_clk.PeriphClockSelection = RCC_PERIPHCLK_USB;+  usb_clk.UsbClockSelection = RCC_USBCLKSOURCE_HSI48;+  if (HAL_RCCEx_PeriphCLKConfig(&usb_clk) != HAL_OK) return false;++  // Enable HSI48+  RCC_OscInitTypeDef osc_hsi48 = {0};+  osc_hsi48.OscillatorType = RCC_OSCILLATORTYPE_HSI48;+  osc_hsi48.HSI48State = RCC_HSI48_ON;+  if (HAL_RCC_OscConfig(&osc_hsi48) != HAL_OK) return false;+  return true;+}
firmware/stm32/dependencies.jsonadded+18
@@ -0,0 +1,18 @@+{+  "tinyusb": {+    "commit": "5f3d88cdbe87ede4fcaddc6a095dcf2edb100f65",+    "url": "https://github.com/hathach/tinyusb.git"+  },+  "cmsis_device_g0": {+    "commit": "f484fe852535f913a02ee79787eafa74dd7f9488",+    "url": "https://github.com/STMicroelectronics/cmsis_device_g0.git"+  },+  "stm32g0xx_hal_driver": {+    "commit": "a248a9e484d58943b46c68f6c49b4b276778bd59",+    "url": "https://github.com/STMicroelectronics/stm32g0xx_hal_driver.git"+  },+  "CMSIS_5": {+    "commit": "2b7495b8535bdcb306dac29b9ded4cfb679d7e5c",+    "url": "https://github.com/ARM-software/CMSIS_5.git"+  }+}
firmware/stm32/licenses/CMSIS_5-LICENSE.txtadded+201
@@ -0,0 +1,201 @@+                                 Apache License+                           Version 2.0, January 2004+                        http://www.apache.org/licenses/++   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION++   1. Definitions.++      "License" shall mean the terms and conditions for use, reproduction,+      and distribution as defined by Sections 1 through 9 of this document.++      "Licensor" shall mean the copyright owner or entity authorized by+      the copyright owner that is granting the License.++      "Legal Entity" shall mean the union of the acting entity and all+      other entities that control, are controlled by, or are under common+      control with that entity. For the purposes of this definition,+      "control" means (i) the power, direct or indirect, to cause the+      direction or management of such entity, whether by contract or+      otherwise, or (ii) ownership of fifty percent (50%) or more of the+      outstanding shares, or (iii) beneficial ownership of such entity.++      "You" (or "Your") shall mean an individual or Legal Entity+      exercising permissions granted by this License.++      "Source" form shall mean the preferred form for making modifications,+      including but not limited to software source code, documentation+      source, and configuration files.++      "Object" form shall mean any form resulting from mechanical+      transformation or translation of a Source form, including but+      not limited to compiled object code, generated documentation,+      and conversions to other media types.++      "Work" shall mean the work of authorship, whether in Source or+      Object form, made available under the License, as indicated by a+      copyright notice that is included in or attached to the work+      (an example is provided in the Appendix below).++      "Derivative Works" shall mean any work, whether in Source or Object+      form, that is based on (or derived from) the Work and for which the+      editorial revisions, annotations, elaborations, or other modifications+      represent, as a whole, an original work of authorship. For the purposes+      of this License, Derivative Works shall not include works that remain+      separable from, or merely link (or bind by name) to the interfaces of,+      the Work and Derivative Works thereof.++      "Contribution" shall mean any work of authorship, including+      the original version of the Work and any modifications or additions+      to that Work or Derivative Works thereof, that is intentionally+      submitted to Licensor for inclusion in the Work by the copyright owner+      or by an individual or Legal Entity authorized to submit on behalf of+      the copyright owner. For the purposes of this definition, "submitted"+      means any form of electronic, verbal, or written communication sent+      to the Licensor or its representatives, including but not limited to+      communication on electronic mailing lists, source code control systems,+      and issue tracking systems that are managed by, or on behalf of, the+      Licensor for the purpose of discussing and improving the Work, but+      excluding communication that is conspicuously marked or otherwise+      designated in writing by the copyright owner as "Not a Contribution."++      "Contributor" shall mean Licensor and any individual or Legal Entity+      on behalf of whom a Contribution has been received by Licensor and+      subsequently incorporated within the Work.++   2. Grant of Copyright License. Subject to the terms and conditions of+      this License, each Contributor hereby grants to You a perpetual,+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable+      copyright license to reproduce, prepare Derivative Works of,+      publicly display, publicly perform, sublicense, and distribute the+      Work and such Derivative Works in Source or Object form.++   3. Grant of Patent License. Subject to the terms and conditions of+      this License, each Contributor hereby grants to You a perpetual,+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable+      (except as stated in this section) patent license to make, have made,+      use, offer to sell, sell, import, and otherwise transfer the Work,+      where such license applies only to those patent claims licensable+      by such Contributor that are necessarily infringed by their+      Contribution(s) alone or by combination of their Contribution(s)+      with the Work to which such Contribution(s) was submitted. If You+      institute patent litigation against any entity (including a+      cross-claim or counterclaim in a lawsuit) alleging that the Work+      or a Contribution incorporated within the Work constitutes direct+      or contributory patent infringement, then any patent licenses+      granted to You under this License for that Work shall terminate+      as of the date such litigation is filed.++   4. Redistribution. You may reproduce and distribute copies of the+      Work or Derivative Works thereof in any medium, with or without+      modifications, and in Source or Object form, provided that You+      meet the following conditions:++      (a) You must give any other recipients of the Work or+          Derivative Works a copy of this License; and++      (b) You must cause any modified files to carry prominent notices+          stating that You changed the files; and++      (c) You must retain, in the Source form of any Derivative Works+          that You distribute, all copyright, patent, trademark, and+          attribution notices from the Source form of the Work,+          excluding those notices that do not pertain to any part of+          the Derivative Works; and++      (d) If the Work includes a "NOTICE" text file as part of its+          distribution, then any Derivative Works that You distribute must+          include a readable copy of the attribution notices contained+          within such NOTICE file, excluding those notices that do not+          pertain to any part of the Derivative Works, in at least one+          of the following places: within a NOTICE text file distributed+          as part of the Derivative Works; within the Source form or+          documentation, if provided along with the Derivative Works; or,+          within a display generated by the Derivative Works, if and+          wherever such third-party notices normally appear. The contents+          of the NOTICE file are for informational purposes only and+          do not modify the License. You may add Your own attribution+          notices within Derivative Works that You distribute, alongside+          or as an addendum to the NOTICE text from the Work, provided+          that such additional attribution notices cannot be construed+          as modifying the License.++      You may add Your own copyright statement to Your modifications and+      may provide additional or different license terms and conditions+      for use, reproduction, or distribution of Your modifications, or+      for any such Derivative Works as a whole, provided Your use,+      reproduction, and distribution of the Work otherwise complies with+      the conditions stated in this License.++   5. Submission of Contributions. Unless You explicitly state otherwise,+      any Contribution intentionally submitted for inclusion in the Work+      by You to the Licensor shall be under the terms and conditions of+      this License, without any additional terms or conditions.+      Notwithstanding the above, nothing herein shall supersede or modify+      the terms of any separate license agreement you may have executed+      with Licensor regarding such Contributions.++   6. Trademarks. This License does not grant permission to use the trade+      names, trademarks, service marks, or product names of the Licensor,+      except as required for reasonable and customary use in describing the+      origin of the Work and reproducing the content of the NOTICE file.++   7. Disclaimer of Warranty. Unless required by applicable law or+      agreed to in writing, Licensor provides the Work (and each+      Contributor provides its Contributions) on an "AS IS" BASIS,+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or+      implied, including, without limitation, any warranties or conditions+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A+      PARTICULAR PURPOSE. You are solely responsible for determining the+      appropriateness of using or redistributing the Work and assume any+      risks associated with Your exercise of permissions under this License.++   8. Limitation of Liability. In no event and under no legal theory,+      whether in tort (including negligence), contract, or otherwise,+      unless required by applicable law (such as deliberate and grossly+      negligent acts) or agreed to in writing, shall any Contributor be+      liable to You for damages, including any direct, indirect, special,+      incidental, or consequential damages of any character arising as a+      result of this License or out of the use or inability to use the+      Work (including but not limited to damages for loss of goodwill,+      work stoppage, computer failure or malfunction, or any and all+      other commercial damages or losses), even if such Contributor+      has been advised of the possibility of such damages.++   9. Accepting Warranty or Additional Liability. While redistributing+      the Work or Derivative Works thereof, You may choose to offer,+      and charge a fee for, acceptance of support, warranty, indemnity,+      or other liability obligations and/or rights consistent with this+      License. However, in accepting such obligations, You may act only+      on Your own behalf and on Your sole responsibility, not on behalf+      of any other Contributor, and only if You agree to indemnify,+      defend, and hold each Contributor harmless for any liability+      incurred by, or claims asserted against, such Contributor by reason+      of your accepting any such warranty or additional liability.++   END OF TERMS AND CONDITIONS++   APPENDIX: How to apply the Apache License to your work.++      To apply the Apache License to your work, attach the following+      boilerplate notice, with the fields enclosed by brackets "{}"+      replaced with your own identifying information. (Don't include+      the brackets!)  The text should be enclosed in the appropriate+      comment syntax for the file format. We also recommend that a+      file or class name and description of purpose be included on the+      same "printed page" as the copyright notice for easier+      identification within third-party archives.++   Copyright {yyyy} {name of copyright owner}++   Licensed under the Apache License, Version 2.0 (the "License");+   you may not use this file except in compliance with the License.+   You may obtain a copy of the License at++       http://www.apache.org/licenses/LICENSE-2.0++   Unless required by applicable law or agreed to in writing, software+   distributed under the License is distributed on an "AS IS" BASIS,+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+   See the License for the specific language governing permissions and+   limitations under the License.
firmware/stm32/licenses/cmsis_device_g0-LICENSE.txtadded+201
@@ -0,0 +1,201 @@+                                 Apache License+                           Version 2.0, January 2004+                        http://www.apache.org/licenses/++   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION++   1. Definitions.++      "License" shall mean the terms and conditions for use, reproduction,+      and distribution as defined by Sections 1 through 9 of this document.++      "Licensor" shall mean the copyright owner or entity authorized by+      the copyright owner that is granting the License.++      "Legal Entity" shall mean the union of the acting entity and all+      other entities that control, are controlled by, or are under common+      control with that entity. For the purposes of this definition,+      "control" means (i) the power, direct or indirect, to cause the+      direction or management of such entity, whether by contract or+      otherwise, or (ii) ownership of fifty percent (50%) or more of the+      outstanding shares, or (iii) beneficial ownership of such entity.++      "You" (or "Your") shall mean an individual or Legal Entity+      exercising permissions granted by this License.++      "Source" form shall mean the preferred form for making modifications,+      including but not limited to software source code, documentation+      source, and configuration files.++      "Object" form shall mean any form resulting from mechanical+      transformation or translation of a Source form, including but+      not limited to compiled object code, generated documentation,+      and conversions to other media types.++      "Work" shall mean the work of authorship, whether in Source or+      Object form, made available under the License, as indicated by a+      copyright notice that is included in or attached to the work+      (an example is provided in the Appendix below).++      "Derivative Works" shall mean any work, whether in Source or Object+      form, that is based on (or derived from) the Work and for which the+      editorial revisions, annotations, elaborations, or other modifications+      represent, as a whole, an original work of authorship. For the purposes+      of this License, Derivative Works shall not include works that remain+      separable from, or merely link (or bind by name) to the interfaces of,+      the Work and Derivative Works thereof.++      "Contribution" shall mean any work of authorship, including+      the original version of the Work and any modifications or additions+      to that Work or Derivative Works thereof, that is intentionally+      submitted to Licensor for inclusion in the Work by the copyright owner+      or by an individual or Legal Entity authorized to submit on behalf of+      the copyright owner. For the purposes of this definition, "submitted"+      means any form of electronic, verbal, or written communication sent+      to the Licensor or its representatives, including but not limited to+      communication on electronic mailing lists, source code control systems,+      and issue tracking systems that are managed by, or on behalf of, the+      Licensor for the purpose of discussing and improving the Work, but+      excluding communication that is conspicuously marked or otherwise+      designated in writing by the copyright owner as "Not a Contribution."++      "Contributor" shall mean Licensor and any individual or Legal Entity+      on behalf of whom a Contribution has been received by Licensor and+      subsequently incorporated within the Work.++   2. Grant of Copyright License. Subject to the terms and conditions of+      this License, each Contributor hereby grants to You a perpetual,+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable+      copyright license to reproduce, prepare Derivative Works of,+      publicly display, publicly perform, sublicense, and distribute the+      Work and such Derivative Works in Source or Object form.++   3. Grant of Patent License. Subject to the terms and conditions of+      this License, each Contributor hereby grants to You a perpetual,+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable+      (except as stated in this section) patent license to make, have made,+      use, offer to sell, sell, import, and otherwise transfer the Work,+      where such license applies only to those patent claims licensable+      by such Contributor that are necessarily infringed by their+      Contribution(s) alone or by combination of their Contribution(s)+      with the Work to which such Contribution(s) was submitted. If You+      institute patent litigation against any entity (including a+      cross-claim or counterclaim in a lawsuit) alleging that the Work+      or a Contribution incorporated within the Work constitutes direct+      or contributory patent infringement, then any patent licenses+      granted to You under this License for that Work shall terminate+      as of the date such litigation is filed.++   4. Redistribution. You may reproduce and distribute copies of the+      Work or Derivative Works thereof in any medium, with or without+      modifications, and in Source or Object form, provided that You+      meet the following conditions:++      (a) You must give any other recipients of the Work or+          Derivative Works a copy of this License; and++      (b) You must cause any modified files to carry prominent notices+          stating that You changed the files; and++      (c) You must retain, in the Source form of any Derivative Works+          that You distribute, all copyright, patent, trademark, and+          attribution notices from the Source form of the Work,+          excluding those notices that do not pertain to any part of+          the Derivative Works; and++      (d) If the Work includes a "NOTICE" text file as part of its+          distribution, then any Derivative Works that You distribute must+          include a readable copy of the attribution notices contained+          within such NOTICE file, excluding those notices that do not+          pertain to any part of the Derivative Works, in at least one+          of the following places: within a NOTICE text file distributed+          as part of the Derivative Works; within the Source form or+          documentation, if provided along with the Derivative Works; or,+          within a display generated by the Derivative Works, if and+          wherever such third-party notices normally appear. The contents+          of the NOTICE file are for informational purposes only and+          do not modify the License. You may add Your own attribution+          notices within Derivative Works that You distribute, alongside+          or as an addendum to the NOTICE text from the Work, provided+          that such additional attribution notices cannot be construed+          as modifying the License.++      You may add Your own copyright statement to Your modifications and+      may provide additional or different license terms and conditions+      for use, reproduction, or distribution of Your modifications, or+      for any such Derivative Works as a whole, provided Your use,+      reproduction, and distribution of the Work otherwise complies with+      the conditions stated in this License.++   5. Submission of Contributions. Unless You explicitly state otherwise,+      any Contribution intentionally submitted for inclusion in the Work+      by You to the Licensor shall be under the terms and conditions of+      this License, without any additional terms or conditions.+      Notwithstanding the above, nothing herein shall supersede or modify+      the terms of any separate license agreement you may have executed+      with Licensor regarding such Contributions.++   6. Trademarks. This License does not grant permission to use the trade+      names, trademarks, service marks, or product names of the Licensor,+      except as required for reasonable and customary use in describing the+      origin of the Work and reproducing the content of the NOTICE file.++   7. Disclaimer of Warranty. Unless required by applicable law or+      agreed to in writing, Licensor provides the Work (and each+      Contributor provides its Contributions) on an "AS IS" BASIS,+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or+      implied, including, without limitation, any warranties or conditions+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A+      PARTICULAR PURPOSE. You are solely responsible for determining the+      appropriateness of using or redistributing the Work and assume any+      risks associated with Your exercise of permissions under this License.++   8. Limitation of Liability. In no event and under no legal theory,+      whether in tort (including negligence), contract, or otherwise,+      unless required by applicable law (such as deliberate and grossly+      negligent acts) or agreed to in writing, shall any Contributor be+      liable to You for damages, including any direct, indirect, special,+      incidental, or consequential damages of any character arising as a+      result of this License or out of the use or inability to use the+      Work (including but not limited to damages for loss of goodwill,+      work stoppage, computer failure or malfunction, or any and all+      other commercial damages or losses), even if such Contributor+      has been advised of the possibility of such damages.++   9. Accepting Warranty or Additional Liability. While redistributing+      the Work or Derivative Works thereof, You may choose to offer,+      and charge a fee for, acceptance of support, warranty, indemnity,+      or other liability obligations and/or rights consistent with this+      License. However, in accepting such obligations, You may act only+      on Your own behalf and on Your sole responsibility, not on behalf+      of any other Contributor, and only if You agree to indemnify,+      defend, and hold each Contributor harmless for any liability+      incurred by, or claims asserted against, such Contributor by reason+      of your accepting any such warranty or additional liability.++   END OF TERMS AND CONDITIONS++   APPENDIX: How to apply the Apache License to your work.++      To apply the Apache License to your work, attach the following+      boilerplate notice, with the fields enclosed by brackets "[]"+      replaced with your own identifying information. (Don't include+      the brackets!)  The text should be enclosed in the appropriate+      comment syntax for the file format. We also recommend that a+      file or class name and description of purpose be included on the+      same "printed page" as the copyright notice for easier+      identification within third-party archives.++   Copyright [yyyy] [name of copyright owner]++   Licensed under the Apache License, Version 2.0 (the "License");+   you may not use this file except in compliance with the License.+   You may obtain a copy of the License at++       http://www.apache.org/licenses/LICENSE-2.0++   Unless required by applicable law or agreed to in writing, software+   distributed under the License is distributed on an "AS IS" BASIS,+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+   See the License for the specific language governing permissions and+   limitations under the License.
firmware/stm32/licenses/stm32g0xx_hal_driver-LICENSE.txtadded+27
@@ -0,0 +1,27 @@+Copyright 2018 STMicroelectronics.+All rights reserved.++Redistribution and use in source and binary forms, with or without modification,+are permitted provided that the following conditions are met:++1. Redistributions of source code must retain the above copyright notice, this+list of conditions and the following disclaimer.++2. Redistributions in binary form must reproduce the above copyright notice,+this list of conditions and the following disclaimer in the documentation and/or+other materials provided with the distribution.++3. Neither the name of the copyright holder nor the names of its contributors+may be used to endorse or promote products derived from this software without+specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
firmware/stm32/licenses/tinyusb-LICENSE.txtadded+21
@@ -0,0 +1,21 @@+The MIT License (MIT)++Copyright (c) 2012-2026, Ha Thach (tinyusb.org)++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in+all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+THE SOFTWARE.
firmware/stm32/main.cadded+103
@@ -0,0 +1,103 @@+/* Output-locked USB bring-up image. This is NOT the production hardware adapter.+ * Never link the Nucleo board.c: its LED is our PA5 load-enable output. */+#include "stm32g0xx_hal.h"+#include "tusb.h"+#include "load_protocol.h"+#include <stdio.h>+#include <math.h>+#if !defined(ADOM_BRINGUP_OUTPUT_LOCK) || ADOM_BRINGUP_OUTPUT_LOCK != 1+#error This bring-up adapter must remain output locked+#endif+#ifndef ADOM_LAB_BOOT_ID+#error Supply a lab-session boot identity; this is not production replay protection+#endif+bool load_clock_init(void);+char load_device_serial[33];+static load_core core;+static load_protocol protocol;+static char response[LOAD_REPLY_BYTES];+static bool initialized, connected;+/* Raw BSRR writes avoid HAL dependencies on the emergency path. */+static void hard_off(void *unused) {+  (void)unused;+  GPIOA->BSRR = (uint32_t)(GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6) << 16;+  GPIOB->BSRR = (uint32_t)GPIO_PIN_3 << 16; /* assert clear: OPEN DRAIN */+}+static void safe_gpio_init(void) {+  __HAL_RCC_GPIOA_CLK_ENABLE();+  __HAL_RCC_GPIOB_CLK_ENABLE();+  hard_off(NULL); /* preload LOW before switching modes */+  GPIO_InitTypeDef gpio = {0};+  gpio.Pin = GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6;+  gpio.Mode = GPIO_MODE_OUTPUT_PP; gpio.Pull = GPIO_NOPULL;+  gpio.Speed = GPIO_SPEED_FREQ_LOW;+  HAL_GPIO_Init(GPIOA, &gpio);+  gpio.Pin = GPIO_PIN_3; gpio.Mode = GPIO_MODE_OUTPUT_OD;+  HAL_GPIO_Init(GPIOB, &gpio); /* never drive the fault-clear net high */+  gpio.Pin = GPIO_PIN_0; gpio.Mode = GPIO_MODE_INPUT;+  HAL_GPIO_Init(GPIOB, &gpio); /* divided USB VBUS, external divider */+}+void load_fatal(void) {+  __disable_irq(); hard_off(NULL);+  for (;;) { __WFI(); }+}+void HardFault_Handler(void) { load_fatal(); }+void NMI_Handler(void) { load_fatal(); }+void SysTick_Handler(void) { HAL_IncTick(); }+uint32_t tusb_time_millis_api(void) { return HAL_GetTick(); }+void USB_UCPD1_2_IRQHandler(void) { tusb_int_handler(0, true); }+void _init(void) {}+static void disconnect(void) {+  hard_off(NULL);+  if (initialized) load_protocol_disconnect(&protocol);+  connected = false;+}+void tud_umount_cb(void) { disconnect(); }+void tud_suspend_cb(bool remote_wakeup_en) { (void)remote_wakeup_en; disconnect(); }+void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) {+  (void)itf; (void)rts; if (!dtr) disconnect();+}+int main(void) {+  safe_gpio_init(); /* do not wait for oscillator or USB setup to deassert enable */+  if (HAL_Init() != HAL_OK || !load_clock_init()) load_fatal();+  __HAL_RCC_SYSCFG_CLK_ENABLE(); __HAL_RCC_PWR_CLK_ENABLE();+  GPIO_InitTypeDef gpio = {0};+  gpio.Pin = GPIO_PIN_11 | GPIO_PIN_12;+  gpio.Mode = GPIO_MODE_INPUT; gpio.Pull = GPIO_NOPULL;+  HAL_GPIO_Init(GPIOA, &gpio);+  __HAL_RCC_USB_CLK_ENABLE(); HAL_PWREx_EnableVddUSB();+  snprintf(load_device_serial, sizeof(load_device_serial), "ADOM%08lX%08lX%08lX",+    (unsigned long)HAL_GetUIDw0(), (unsigned long)HAL_GetUIDw1(), (unsigned long)HAL_GetUIDw2());+  load_init(&core, HAL_GetTick());+  if (!load_protocol_init(&protocol, &core, load_device_serial, ADOM_LAB_BOOT_ID, hard_off, NULL)) load_fatal();+  initialized = true;+  tusb_rhport_init_t init = {.role = TUSB_ROLE_DEVICE, .speed = TUSB_SPEED_FULL};+  if (!tusb_init(0, &init)) load_fatal();+  bool attached = false;+  tud_disconnect();+  for (;;) {+    hard_off(NULL); /* unconditional: no path in this image can enable load */+    bool vbus = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_SET;+    if (vbus != attached) {+      attached = vbus;+      if (vbus) tud_connect(); else { tud_disconnect(); disconnect(); }+    }+    tud_task();+    bool online = vbus && tud_cdc_connected();+    if (!online && connected) disconnect();+    connected = online;+    load_sample sample = {.now_ms = HAL_GetTick(), .volts = NAN, .amps = NAN,+      .case_c = NAN, .fan_rpm = NAN, .assembly_qualified = false,+      .sensors_valid = false, .hw_ok = false, .latch_q = false};+    load_protocol_poll(&protocol, &sample);+    /* Bounded ingress; never consume a request without room for its full reply. */+    for (unsigned n = 0; online && n < 64 && tud_cdc_available() &&+         tud_cdc_write_available() >= LOAD_REPLY_BYTES; ++n) {+      uint8_t byte;+      if (tud_cdc_read(&byte, 1) != 1) break;+      size_t len = load_protocol_byte(&protocol, byte, &sample, response, sizeof(response));+      if (len && tud_cdc_write(response, (uint32_t)len) != len) disconnect();+    }+    tud_cdc_write_flush();+  }+}
firmware/stm32/stm32g0b1kc.ldadded+180
@@ -0,0 +1,180 @@+/*+******************************************************************************+**++**  File        : LinkerScript.ld+**+**  Author		: STM32CubeMX+**+**  Abstract    : Linker script for STM32G0B1KCT6 series+**                256Kbytes FLASH and 144Kbytes RAM+**+**                Set heap size, stack size and stack location according+**                to application requirements.+**+**                Set memory bank area and size if external memory is used.+**+**  Target      : STMicroelectronics STM32+**+**  Distribution: The file is distributed “as is,” without any warranty+**                of any kind.+**+*****************************************************************************+** @attention+**+** <h2><center>&copy; COPYRIGHT(c) 2019 STMicroelectronics</center></h2>+**+** Redistribution and use in source and binary forms, with or without modification,+** are permitted provided that the following conditions are met:+**   1. Redistributions of source code must retain the above copyright notice,+**      this list of conditions and the following disclaimer.+**   2. Redistributions in binary form must reproduce the above copyright notice,+**      this list of conditions and the following disclaimer in the documentation+**      and/or other materials provided with the distribution.+**   3. Neither the name of STMicroelectronics nor the names of its contributors+**      may be used to endorse or promote products derived from this software+**      without specific prior written permission.+**+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"+** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR+** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER+** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,+** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+**+*****************************************************************************+*/++/* Entry Point */+ENTRY(Reset_Handler)++/* Specify the memory areas */+MEMORY+{+RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 144K+FLASH (rx)      : ORIGIN = 0x8000000, LENGTH = 256K+}++/* Highest address of the user mode stack */+_estack = ORIGIN(RAM) + LENGTH(RAM);    /* end of RAM */++/* Generate a link error if heap and stack don't fit into RAM */+_Min_Heap_Size = 0x200;      /* required amount of heap  */+_Min_Stack_Size = 0x2000; /* required amount of stack */++/* Define output sections */+SECTIONS+{+  /* The startup code goes first into FLASH */+  .isr_vector :+  {+    . = ALIGN(4);+    KEEP(*(.isr_vector)) /* Startup code */+    . = ALIGN(4);+  } >FLASH++  /* The program code and other data goes into FLASH */+  .text :+  {+    . = ALIGN(4);+    *(.text)           /* .text sections (code) */+    *(.text*)          /* .text* sections (code) */+    *(.glue_7)         /* glue arm to thumb code */+    *(.glue_7t)        /* glue thumb to arm code */+    *(.eh_frame)++    KEEP (*(.init))+    KEEP (*(.fini))++    . = ALIGN(4);+    _etext = .;        /* define a global symbols at end of code */+  } >FLASH++  /* Constant data goes into FLASH */+  .rodata :+  {+    . = ALIGN(4);+    *(.rodata)         /* .rodata sections (constants, strings, etc.) */+    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */+    . = ALIGN(4);+  } >FLASH++  .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH+  .ARM : {+    __exidx_start = .;+    *(.ARM.exidx*)+    __exidx_end = .;+  } >FLASH++  .preinit_array     :+  {+    PROVIDE_HIDDEN (__preinit_array_start = .);+    KEEP (*(.preinit_array*))+    PROVIDE_HIDDEN (__preinit_array_end = .);+  } >FLASH+  .init_array :+  {+    PROVIDE_HIDDEN (__init_array_start = .);+    KEEP (*(SORT(.init_array.*)))+    KEEP (*(.init_array*))+    PROVIDE_HIDDEN (__init_array_end = .);+  } >FLASH+  .fini_array :+  {+    PROVIDE_HIDDEN (__fini_array_start = .);+    KEEP (*(SORT(.fini_array.*)))+    KEEP (*(.fini_array*))+    PROVIDE_HIDDEN (__fini_array_end = .);+  } >FLASH++  /* used by the startup to initialize data */+  _sidata = LOADADDR(.data);++  /* Initialized data sections goes into RAM, load LMA copy after code */+  .data :+  {+    . = ALIGN(4);+    _sdata = .;        /* create a global symbol at data start */+    *(.data)           /* .data sections */+    *(.data*)          /* .data* sections */++    . = ALIGN(4);+    _edata = .;        /* define a global symbol at data end */+  } >RAM AT> FLASH+++  /* Uninitialized data section */+  . = ALIGN(4);+  .bss :+  {+    /* This is used by the startup in order to initialize the .bss section */+    _sbss = .;         /* define a global symbol at bss start */+    __bss_start__ = _sbss;+    *(.bss)+    *(.bss*)+    *(COMMON)++    . = ALIGN(4);+    _ebss = .;         /* define a global symbol at bss end */+    __bss_end__ = _ebss;+  } >RAM++  /* User_heap_stack section, used to check that there is enough RAM left */+  ._user_heap_stack :+  {+    . = ALIGN(8);+    PROVIDE ( end = . );+    PROVIDE ( _end = . );+    . = . + _Min_Heap_Size;+    . = . + _Min_Stack_Size;+    . = ALIGN(8);+  } >RAM++++  .ARM.attributes 0 : { *(.ARM.attributes) }+}
firmware/stm32/stm32g0xx_hal_conf.hadded+351
@@ -0,0 +1,351 @@+/* USER CODE BEGIN Header */+/**+  ******************************************************************************+  * @file    stm32g0xx_hal_conf.h+  * @author  MCD Application Team+  * @brief   HAL configuration file.+  ******************************************************************************+  * @attention+  *+  * Copyright (c) 2018-2021 STMicroelectronics.+  * All rights reserved.+  *+  * This software is licensed under terms that can be found in the LICENSE file+  * in the root directory of this software component.+  * If no LICENSE file comes with this software, it is provided AS-IS.+  *+  ******************************************************************************+  */+/* USER CODE END Header */++/* Define to prevent recursive inclusion -------------------------------------*/+#ifndef STM32G0xx_HAL_CONF_H+#define STM32G0xx_HAL_CONF_H++#ifdef __cplusplus+extern "C" {+#endif++/* Exported types ------------------------------------------------------------*/+/* Exported constants --------------------------------------------------------*/++/* ########################## Module Selection ############################## */+/**+  * @brief This is the list of modules to be used in the HAL driver+  */+#define HAL_MODULE_ENABLED+/* #define HAL_ADC_MODULE_ENABLED   */+/* #define HAL_CEC_MODULE_ENABLED   */+/* #define HAL_COMP_MODULE_ENABLED   */+/* #define HAL_CRC_MODULE_ENABLED   */+/* #define HAL_CRYP_MODULE_ENABLED   */+/* #define HAL_DAC_MODULE_ENABLED   */+/* #define HAL_EXTI_MODULE_ENABLED   */+/* #define HAL_FDCAN_MODULE_ENABLED   */+/* #define HAL_HCD_MODULE_ENABLED   */+#define HAL_I2C_MODULE_ENABLED+/* #define HAL_I2S_MODULE_ENABLED   */+/* #define HAL_IWDG_MODULE_ENABLED   */+/* #define HAL_IRDA_MODULE_ENABLED   */+/* #define HAL_LPTIM_MODULE_ENABLED   */+/* #define HAL_PCD_MODULE_ENABLED   */+/* #define HAL_RNG_MODULE_ENABLED   */+/* #define HAL_RTC_MODULE_ENABLED   */+/* #define HAL_SMARTCARD_MODULE_ENABLED   */+/* #define HAL_SMBUS_MODULE_ENABLED   */+/* #define HAL_SPI_MODULE_ENABLED   */+/* #define HAL_TIM_MODULE_ENABLED   */+/* #define HAL_USART_MODULE_ENABLED   */+/* #define HAL_WWDG_MODULE_ENABLED   */+#define HAL_GPIO_MODULE_ENABLED+#define HAL_EXTI_MODULE_ENABLED+#define HAL_DMA_MODULE_ENABLED+#define HAL_RCC_MODULE_ENABLED+#define HAL_FLASH_MODULE_ENABLED+#define HAL_PWR_MODULE_ENABLED+#define HAL_CORTEX_MODULE_ENABLED+#define HAL_UART_MODULE_ENABLED++/* ########################## Register Callbacks selection ############################## */+/**+  * @brief This is the list of modules where register callback can be used+  */+#define USE_HAL_ADC_REGISTER_CALLBACKS    0u+#define USE_HAL_CEC_REGISTER_CALLBACKS    0u+#define USE_HAL_COMP_REGISTER_CALLBACKS   0u+#define USE_HAL_CRYP_REGISTER_CALLBACKS   0u+#define USE_HAL_DAC_REGISTER_CALLBACKS    0u+#define USE_HAL_FDCAN_REGISTER_CALLBACKS  0u+#define USE_HAL_HCD_REGISTER_CALLBACKS    0u+#define USE_HAL_I2C_REGISTER_CALLBACKS    0u+#define USE_HAL_I2S_REGISTER_CALLBACKS    0u+#define USE_HAL_IRDA_REGISTER_CALLBACKS   0u+#define USE_HAL_LPTIM_REGISTER_CALLBACKS  0u+#define USE_HAL_PCD_REGISTER_CALLBACKS    0u+#define USE_HAL_RNG_REGISTER_CALLBACKS    0u+#define USE_HAL_RTC_REGISTER_CALLBACKS    0u+#define USE_HAL_SMBUS_REGISTER_CALLBACKS  0u+#define USE_HAL_SPI_REGISTER_CALLBACKS    0u+#define USE_HAL_TIM_REGISTER_CALLBACKS    0u+#define USE_HAL_UART_REGISTER_CALLBACKS   0u+#define USE_HAL_USART_REGISTER_CALLBACKS  0u+#define USE_HAL_WWDG_REGISTER_CALLBACKS   0u++/* ########################## Oscillator Values adaptation ####################*/+/**+  * @brief Adjust the value of External High Speed oscillator (HSE) used in your application.+  *        This value is used by the RCC HAL module to compute the system frequency+  *        (when HSE is used as system clock source, directly or through the PLL).+  */+#if !defined  (HSE_VALUE)+#define HSE_VALUE    (8000000UL)         /*!< Value of the External oscillator in Hz */+#endif /* HSE_VALUE */++#if !defined  (HSE_STARTUP_TIMEOUT)+#define HSE_STARTUP_TIMEOUT    (100UL)         /*!< Time out for HSE start up, in ms */+#endif /* HSE_STARTUP_TIMEOUT */++/**+  * @brief Internal High Speed oscillator (HSI) value.+  *        This value is used by the RCC HAL module to compute the system frequency+  *        (when HSI is used as system clock source, directly or through the PLL).+  */+#if !defined  (HSI_VALUE)+#define HSI_VALUE    (16000000UL)            /*!< Value of the Internal oscillator in Hz*/+#endif /* HSI_VALUE */++#if defined(STM32G0C1xx) || defined(STM32G0B1xx) || defined(STM32G0B0xx)+/**+  * @brief Internal High Speed oscillator (HSI48) value for USB FS, SDMMC and RNG.+  *        This internal oscillator is mainly dedicated to provide a high precision clock to+  *        the USB peripheral by means of a special Clock Recovery System (CRS) circuitry.+  *        When the CRS is not used, the HSI48 RC oscillator runs on it default frequency+  *        which is subject to manufacturing process variations.+  */+#if !defined  (HSI48_VALUE)+  #define HSI48_VALUE   48000000U             /*!< Value of the Internal High Speed oscillator for USB FS/SDMMC/RNG in Hz.+                                               The real value my vary depending on manufacturing process variations.*/+#endif /* HSI48_VALUE */+#endif++/**+  * @brief Internal Low Speed oscillator (LSI) value.+  */+#if !defined  (LSI_VALUE)+#define LSI_VALUE  (32000UL)                /*!< LSI Typical Value in Hz*/+#endif /* LSI_VALUE */                      /*!< Value of the Internal Low Speed oscillator in Hz+The real value may vary depending on the variations+in voltage and temperature.*/+/**+  * @brief External Low Speed oscillator (LSE) value.+  *        This value is used by the UART, RTC HAL module to compute the system frequency+  */+#if !defined  (LSE_VALUE)+#define LSE_VALUE    (32768UL)               /*!< Value of the External oscillator in Hz*/+#endif /* LSE_VALUE */++#if !defined  (LSE_STARTUP_TIMEOUT)+#define LSE_STARTUP_TIMEOUT    (5000UL)      /*!< Time out for LSE start up, in ms */+#endif /* LSE_STARTUP_TIMEOUT */++/**+  * @brief External clock source for I2S1 peripheral+  *        This value is used by the RCC HAL module to compute the I2S1 clock source+  *        frequency.+  */+#if !defined  (EXTERNAL_I2S1_CLOCK_VALUE)+#define EXTERNAL_I2S1_CLOCK_VALUE    (48000UL) /*!< Value of the I2S1 External clock source in Hz*/+#endif /* EXTERNAL_I2S1_CLOCK_VALUE */++#if defined(STM32G0C1xx) || defined(STM32G0B1xx) || defined(STM32G0B0xx)+/**+  * @brief External clock source for I2S2 peripheral+  *        This value is used by the RCC HAL module to compute the I2S2 clock source+  *        frequency.+  */+#if !defined  (EXTERNAL_I2S2_CLOCK_VALUE)+  #define EXTERNAL_I2S2_CLOCK_VALUE    48000U /*!< Value of the I2S2 External clock source in Hz*/+#endif /* EXTERNAL_I2S2_CLOCK_VALUE */+#endif++/* Tip: To avoid modifying this file each time you need to use different HSE,+   ===  you can define the HSE value in your toolchain compiler preprocessor. */++/* ########################### System Configuration ######################### */+/**+  * @brief This is the HAL system configuration section+  */+#define  VDD_VALUE                    (3300UL)                                        /*!< Value of VDD in mv */+#define  TICK_INT_PRIORITY            0U /*!< tick interrupt priority */+#define  USE_RTOS                     0U+#define  PREFETCH_ENABLE              1U+#define  INSTRUCTION_CACHE_ENABLE     1U++/* ################## SPI peripheral configuration ########################## */++/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver+* Activated: CRC code is present inside driver+* Deactivated: CRC code cleaned from driver+*/++#define USE_SPI_CRC                     0U++/* ################## CRYP peripheral configuration ########################## */++#define USE_HAL_CRYP_SUSPEND_RESUME     1U++/* ########################## Assert Selection ############################## */+/**+  * @brief Uncomment the line below to expanse the "assert_param" macro in the+  *        HAL drivers code+  */+/* #define USE_FULL_ASSERT    1U */++/* Includes ------------------------------------------------------------------*/+/**+  * @brief Include modules header file+  */++#ifdef HAL_RCC_MODULE_ENABLED+#include "stm32g0xx_hal_rcc.h"+#endif /* HAL_RCC_MODULE_ENABLED */++#ifdef HAL_GPIO_MODULE_ENABLED+#include "stm32g0xx_hal_gpio.h"+#endif /* HAL_GPIO_MODULE_ENABLED */++#ifdef HAL_DMA_MODULE_ENABLED+#include "stm32g0xx_hal_dma.h"+#endif /* HAL_DMA_MODULE_ENABLED */++#ifdef HAL_CORTEX_MODULE_ENABLED+#include "stm32g0xx_hal_cortex.h"+#endif /* HAL_CORTEX_MODULE_ENABLED */++#ifdef HAL_ADC_MODULE_ENABLED+#include "stm32g0xx_hal_adc.h"+#include "stm32g0xx_hal_adc_ex.h"+#endif /* HAL_ADC_MODULE_ENABLED */++#ifdef HAL_CEC_MODULE_ENABLED+#include "stm32g0xx_hal_cec.h"+#endif /* HAL_CEC_MODULE_ENABLED */++#ifdef HAL_COMP_MODULE_ENABLED+#include "stm32g0xx_hal_comp.h"+#endif /* HAL_COMP_MODULE_ENABLED */++#ifdef HAL_CRC_MODULE_ENABLED+#include "stm32g0xx_hal_crc.h"+#endif /* HAL_CRC_MODULE_ENABLED */++#ifdef HAL_CRYP_MODULE_ENABLED+#include "stm32g0xx_hal_cryp.h"+#endif /* HAL_CRYP_MODULE_ENABLED */++#ifdef HAL_DAC_MODULE_ENABLED+#include "stm32g0xx_hal_dac.h"+#endif /* HAL_DAC_MODULE_ENABLED */++#ifdef HAL_EXTI_MODULE_ENABLED+#include "stm32g0xx_hal_exti.h"+#endif /* HAL_EXTI_MODULE_ENABLED */++#ifdef HAL_FLASH_MODULE_ENABLED+#include "stm32g0xx_hal_flash.h"+#endif /* HAL_FLASH_MODULE_ENABLED */++#ifdef HAL_FDCAN_MODULE_ENABLED+#include "stm32g0xx_hal_fdcan.h"+#endif /* HAL_FDCAN_MODULE_ENABLED */++#ifdef HAL_HCD_MODULE_ENABLED+#include "stm32g0xx_hal_hcd.h"+#endif /* HAL_HCD_MODULE_ENABLED */++#ifdef HAL_I2C_MODULE_ENABLED+#include "stm32g0xx_hal_i2c.h"+#endif /* HAL_I2C_MODULE_ENABLED */++#ifdef HAL_I2S_MODULE_ENABLED+#include "stm32g0xx_hal_i2s.h"+#endif /* HAL_I2S_MODULE_ENABLED */++#ifdef HAL_IRDA_MODULE_ENABLED+#include "stm32g0xx_hal_irda.h"+#endif /* HAL_IRDA_MODULE_ENABLED */++#ifdef HAL_IWDG_MODULE_ENABLED+#include "stm32g0xx_hal_iwdg.h"+#endif /* HAL_IWDG_MODULE_ENABLED */++#ifdef HAL_LPTIM_MODULE_ENABLED+#include "stm32g0xx_hal_lptim.h"+#endif /* HAL_LPTIM_MODULE_ENABLED */++#ifdef HAL_PCD_MODULE_ENABLED+#include "stm32g0xx_hal_pcd.h"+#endif /* HAL_PCD_MODULE_ENABLED */++#ifdef HAL_PWR_MODULE_ENABLED+#include "stm32g0xx_hal_pwr.h"+#endif /* HAL_PWR_MODULE_ENABLED */++#ifdef HAL_RNG_MODULE_ENABLED+#include "stm32g0xx_hal_rng.h"+#endif /* HAL_RNG_MODULE_ENABLED */++#ifdef HAL_RTC_MODULE_ENABLED+#include "stm32g0xx_hal_rtc.h"+#endif /* HAL_RTC_MODULE_ENABLED */++#ifdef HAL_SMARTCARD_MODULE_ENABLED+#include "stm32g0xx_hal_smartcard.h"+#endif /* HAL_SMARTCARD_MODULE_ENABLED */++#ifdef HAL_SMBUS_MODULE_ENABLED+#include "stm32g0xx_hal_smbus.h"+#endif /* HAL_SMBUS_MODULE_ENABLED */++#ifdef HAL_SPI_MODULE_ENABLED+#include "stm32g0xx_hal_spi.h"+#endif /* HAL_SPI_MODULE_ENABLED */++#ifdef HAL_TIM_MODULE_ENABLED+#include "stm32g0xx_hal_tim.h"+#endif /* HAL_TIM_MODULE_ENABLED */++#ifdef HAL_UART_MODULE_ENABLED+#include "stm32g0xx_hal_uart.h"+#endif /* HAL_UART_MODULE_ENABLED */++#ifdef HAL_USART_MODULE_ENABLED+#include "stm32g0xx_hal_usart.h"+#endif /* HAL_USART_MODULE_ENABLED */++#ifdef HAL_WWDG_MODULE_ENABLED+#include "stm32g0xx_hal_wwdg.h"+#endif /* HAL_WWDG_MODULE_ENABLED */++/* Exported macro ------------------------------------------------------------*/+#ifdef  USE_FULL_ASSERT+/**+  * @brief  The assert_param macro is used for functions parameters check.+  * @param  expr If expr is false, it calls assert_failed function+  *         which reports the name of the source file and the source+  *         line number of the call that failed.+  *         If expr is true, it returns no value.+  * @retval None+  */+#define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__))+/* Exported functions ------------------------------------------------------- */+void assert_failed(uint8_t *file, uint32_t line);+#else+#define assert_param(expr) ((void)0U)+#endif /* USE_FULL_ASSERT */++#ifdef __cplusplus+}+#endif++#endif /* STM32G0xx_HAL_CONF_H */
firmware/stm32/syscalls.cadded+26
@@ -0,0 +1,26 @@+/* Newlib formatting may allocate. Bound its heap independently of the stack. */+#include <sys/types.h>+#include <errno.h>+#include <stddef.h>+#include <stdint.h>+static union { max_align_t alignment; unsigned char bytes[8192]; } heap;+void *_sbrk(ptrdiff_t delta) {+  static size_t used;+  if (delta < 0 || (size_t)delta > sizeof(heap.bytes) - used) {+    errno = ENOMEM; return (void *)-1;+  }+  void *old = heap.bytes + used; used += (size_t)delta; return old;+}+/* No console/file-system backend is connected. Fail explicitly, never route+ * printf through GPIO/UART pins without the board adapter owning them. */+#include <sys/stat.h>+int _close(int fd) { (void)fd; errno=EBADF; return -1; }+int _fstat(int fd, struct stat *st) { (void)fd; (void)st; errno=EBADF; return -1; }+int _isatty(int fd) { (void)fd; return 0; }+off_t _lseek(int fd, off_t offset, int whence) { (void)fd; (void)offset; (void)whence; errno=EBADF; return -1; }+ssize_t _read(int fd, void *buf, size_t len) { (void)fd; (void)buf; (void)len; errno=EBADF; return -1; }+ssize_t _write(int fd, const void *buf, size_t len) { (void)fd; (void)buf; (void)len; errno=EBADF; return -1; }+int _getpid(void) { return 1; }+int _kill(int pid, int sig) { (void)pid; (void)sig; errno=EINVAL; return -1; }+extern void load_fatal(void);+void _exit(int status) { (void)status; load_fatal(); for (;;) {} }
firmware/stm32/tusb_config.hadded+16
@@ -0,0 +1,16 @@+#ifndef ADOM_LOAD_TUSB_CONFIG_H+#define ADOM_LOAD_TUSB_CONFIG_H+#define CFG_TUSB_MCU OPT_MCU_STM32G0+#define CFG_TUSB_OS OPT_OS_NONE+#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | OPT_MODE_FULL_SPEED)+#define CFG_TUD_ENABLED 1+#define CFG_TUD_ENDPOINT0_SIZE 64+#define CFG_TUD_CDC 1+#define CFG_TUD_MSC 0+#define CFG_TUD_HID 0+#define CFG_TUD_MIDI 0+#define CFG_TUD_VENDOR 0+#define CFG_TUD_CDC_RX_BUFSIZE 512+#define CFG_TUD_CDC_TX_BUFSIZE 2048+#define CFG_TUD_CDC_EP_BUFSIZE 64+#endif
firmware/stm32/usb_descriptors.cadded+27
@@ -0,0 +1,27 @@+/* Lab bring-up identity only. Replace with Adom's allocated VID/PID before release.+ * Descriptor structures/macros are provided by TinyUSB (MIT; see licenses). */+#include "tusb.h"+#include <string.h>+#ifndef ADOM_USB_VID+#error An explicit USB VID is required+#endif+#ifndef ADOM_USB_PID+#error An explicit USB PID is required+#endif+extern char load_device_serial[33];+static const tusb_desc_device_t device={+ .bLength=sizeof(tusb_desc_device_t),.bDescriptorType=TUSB_DESC_DEVICE,.bcdUSB=0x0200,+ .bDeviceClass=TUSB_CLASS_MISC,.bDeviceSubClass=MISC_SUBCLASS_COMMON,.bDeviceProtocol=MISC_PROTOCOL_IAD,+ .bMaxPacketSize0=64,.idVendor=ADOM_USB_VID,.idProduct=ADOM_USB_PID,.bcdDevice=0x0001,+ .iManufacturer=1,.iProduct=2,.iSerialNumber=3,.bNumConfigurations=1};+static const uint8_t config[]={+ TUD_CONFIG_DESCRIPTOR(1,2,0,TUD_CONFIG_DESC_LEN+TUD_CDC_DESC_LEN,TUSB_DESC_CONFIG_ATT_SELF_POWERED,0),+ TUD_CDC_DESCRIPTOR(0,4,0x81,8,0x02,0x82,64)};+const uint8_t *tud_descriptor_device_cb(void){return (const uint8_t *)&device;}+const uint8_t *tud_descriptor_configuration_cb(uint8_t index){(void)index;return config;}+const uint16_t *tud_descriptor_string_cb(uint8_t index,uint16_t langid){+ (void)langid;static uint16_t out[64];const char *s;+ if(index==0){out[0]=(TUSB_DESC_STRING<<8)|4;out[1]=0x0409;return out;}+ switch(index){case 1:s="Adom prototype";break;case 2:s="Electronic load USB bring-up - output locked OFF";break;case 3:s=load_device_serial;break;case 4:s="Load protocol";break;default:return NULL;}+ size_t n=strlen(s);if(n>63)n=63;for(size_t i=0;i<n;i++)out[i+1]=(uint8_t)s[i];out[0]=(uint16_t)((TUSB_DESC_STRING<<8)|(2*n+2));return out;+}
tools/audit_mcu_pinmap.py+3−3
@@ -3,14 +3,14 @@ Source: ST DS13560 Rev 6, LQFP32 GP pinout and alternate-function tables. This does not validate option bytes, register setup, electrical limits or hardware. """ from pathlib import Path-import json,sys+import json,sys,hashlib import sexp p=Path(__file__).resolve().parents[1]-map_by_pin={6:('PF2','NRST','reset'),7:('PA0','TEMP_SENSE','ADC_IN0'),8:('PA1','DUT_ADC','ADC_IN1'),9:('PA2','UART_TX','USART2_TX AF1'),10:('PA3','UART_RX','USART2_RX AF1'),11:('PA4','ARM_CLK','GPIO output, initialize LOW'),12:('PA5','MCU_ENABLE','GPIO output, initialize LOW'),13:('PA6','WDI','GPIO output, healthy-cycle toggle only'),14:('PA7','FAN_TACH','GPIO EXTI7 rising; timestamp from 32-bit timer'),15:('PB0','USB_DETECT','GPIO input'),17:('PB2','HW_OK','GPIO input'),20:('PC6','ALERT','GPIO input'),22:('PA11','USB_DM','USB_DM, default pin remap'),23:('PA12','USB_DP','USB_DP, default pin remap'),24:('PA13','SWDIO','SWDIO AF0'),25:('PA14','SWCLK','SWCLK AF0'),26:('PA15','LATCH_Q','GPIO input'),27:('PB3','FAULT_CLEAR','GPIO output; polarity requires latch-chain audit'),30:('PB6','I2C_SCL','I2C1_SCL AF6 open-drain'),31:('PB7','I2C_SDA','I2C1_SDA AF6 open-drain')}+map_by_pin={6:('PF2','NRST','reset'),7:('PA0','TEMP_SENSE','ADC_IN0'),8:('PA1','DUT_ADC','ADC_IN1'),9:('PA2','UART_TX','USART2_TX AF1'),10:('PA3','UART_RX','USART2_RX AF1'),11:('PA4','ARM_CLK','GPIO output, initialize LOW'),12:('PA5','MCU_ENABLE','GPIO output, initialize LOW'),13:('PA6','WDI','GPIO output, healthy-cycle toggle only'),14:('PA7','FAN_TACH','GPIO EXTI7 rising; timestamp from 32-bit timer'),15:('PB0','USB_DETECT','GPIO input'),17:('PB2','HW_OK','GPIO input'),20:('PC6','ALERT','GPIO input'),22:('PA11','USB_DM','USB_DM, default pin remap'),23:('PA12','USB_DP','USB_DP, default pin remap'),24:('PA13','SWDIO','SWDIO AF0'),25:('PA14','SWCLK','SWCLK AF0'),26:('PA15','LATCH_Q','GPIO input'),27:('PB3','FAULT_CLEAR','GPIO open-drain, LOW asserts fault clear through D2; never push-pull HIGH'),30:('PB6','I2C_SCL','I2C1_SCL AF6 open-drain'),31:('PB7','I2C_SDA','I2C1_SDA AF6 open-drain')} n=json.load(open(p/'design/netlist.json'));c=next(c for c in n['components']if c['ref']=='U1');assert c['mpn']=='STM32G0B1KCT6' b=sexp.parse((p/'kicad/adom-custom-electronic-load.kicad_pcb').read_text());f=next(f for f in sexp.find(b,'footprint')if any(v[1:3]==['Reference','U1']for v in sexp.find(f,'property')));boardpins={x[1]:(sexp.first(x,'net')[-1]if sexp.first(x,'net')else None)for x in sexp.find(f,'pad')};rows=[] for pin,(gpio,net,function)in map_by_pin.items():  assert c['pins'][str(pin)]==net and boardpins[str(pin)]==net,(pin,net)  rows.append({'packagePin':pin,'gpio':gpio,'net':net,'plannedFunction':function}) for pin,net in [(4,'3V3'),(5,'GND')]:assert c['pins'][str(pin)]==net and boardpins[str(pin)]==net-out={'part':c['mpn'],'package':'LQFP32 GP, not the N-suffix variant','source':'https://www.st.com/resource/en/datasheet/stm32g0b1kc.pdf','sourceRevision':'DS13560 Rev 6','matchedSignalPins':len(rows),'matchedSupplyPins':2,'pins':rows,'limits':['Static assignment audit only; HAL and option-byte validation pending','USB clock recovery, VBUS detection and self-powered descriptors pending','Tach EXTI timestamps require a 32-bit microsecond timebase and measured ISR latency','Boot identity must be unique on every reset; no fixed production boot nonce']};(p/'design/mcu-pinmap.json').write_text(json.dumps(out,indent=2)+'\n');print('MCU map: 20 signal pins and 2 supply pins agree between design netlist, PCB and selected package assignments.')+out={'inputSha256':{str(f.relative_to(p)):hashlib.sha256(f.read_bytes()).hexdigest()for f in [p/'design/netlist.json',p/'kicad/adom-custom-electronic-load.kicad_pcb']},'part':c['mpn'],'package':'LQFP32 GP, not the N-suffix variant','source':'https://www.st.com/resource/en/datasheet/stm32g0b1kc.pdf','sourceRevision':'DS13560 Rev 6','matchedSignalPins':len(rows),'matchedSupplyPins':2,'pins':rows,'limits':['Static assignment audit only; HAL and option-byte validation pending','USB bring-up adapter compiled; clock recovery, VBUS detection and enumeration physically unverified','Tach EXTI timestamps require a 32-bit microsecond timebase and measured ISR latency','Boot identity must be unique on every reset; no fixed production boot nonce']};(p/'design/mcu-pinmap.json').write_text(json.dumps(out,indent=2)+'\n');print('MCU map: 20 signal pins and 2 supply pins agree between design netlist, PCB and selected package assignments.')
tools/build_stm32_bringup.pyadded+56
@@ -0,0 +1,56 @@+#!/usr/bin/env python3+"""Build the output-locked STM32 image from exact pinned dependencies. Never flash."""+import argparse, hashlib, json, os, subprocess+from pathlib import Path+P = Path(__file__).resolve().parents[1]+a = argparse.ArgumentParser(description=__doc__)+a.add_argument('--tinyusb', type=Path, required=True)+a.add_argument('--toolchain-root', type=Path, required=True, help='Relocated Debian package root')+a.add_argument('--vid', type=lambda s:int(s,0), required=True)+a.add_argument('--pid', type=lambda s:int(s,0), required=True)+a.add_argument('--lab-boot-id', required=True, help='Lab session only; no reset freshness guarantee')+a.add_argument('--out', type=Path, default=P/'build/stm32-bringup')+r = a.parse_args()+assert 0 < r.vid <= 65535 and 0 < r.pid <= 65535+assert 8 <= len(r.lab_boot_id) <= 32 and all(c.isascii() and (c.isalnum() or c in '_-') for c in r.lab_boot_id)+t = r.tinyusb.resolve(); root = r.toolchain_root.resolve(); out = r.out.resolve(); out.mkdir(parents=True, exist_ok=True)+paths = {'tinyusb':t,'cmsis_device_g0':t/'hw/mcu/st/cmsis_device_g0',+ 'stm32g0xx_hal_driver':t/'hw/mcu/st/stm32g0xx_hal_driver','CMSIS_5':t/'lib/CMSIS_5'}+pins=json.loads((P/'firmware/stm32/dependencies.json').read_text())+for name,path in paths.items():+ head=subprocess.check_output(['git','-C',str(path),'rev-parse','HEAD'],text=True).strip()+ assert head==pins[name]['commit'], f'{name}: dependency commit mismatch'+ assert not subprocess.check_output(['git','-C',str(path),'status','--porcelain','--untracked-files=no'],text=True).strip(), f'{name}: modified tracked files'+cc=root/'usr/bin/arm-none-eabi-gcc'; prefix=root/'usr/bin/arm-none-eabi-'+newlib=root/'usr/lib/arm-none-eabi/newlib/thumb/v6-m/nofp'+h=paths['stm32g0xx_hal_driver']; c=paths['cmsis_device_g0']+sources=[P/'firmware'/s for s in ['load_core.c','load_protocol.c','stm32/main.c','stm32/clock.c','stm32/usb_descriptors.c','stm32/syscalls.c']]+sources += [t/'src'/s for s in ['tusb.c','common/tusb_fifo.c','device/usbd.c','class/cdc/cdc_device.c','portable/st/stm32_fsdev/dcd_stm32_fsdev.c','portable/st/stm32_fsdev/fsdev_common.c']]+sources += [h/'Src'/('stm32g0xx_hal'+s+'.c') for s in ['', '_cortex','_pwr','_pwr_ex','_rcc','_rcc_ex','_gpio']]+sources += [c/'Source/Templates/system_stm32g0xx.c',c/'Source/Templates/gcc/startup_stm32g0b1xx.s']+includes=[P/'firmware',P/'firmware/stm32',t/'src',paths['CMSIS_5']/'CMSIS/Core/Include',c/'Include',h/'Inc',root/'usr/include/newlib']+flags=['-mcpu=cortex-m0plus','-mthumb','-Os','-g3','-ffunction-sections','-fdata-sections','-fno-common','-fstack-usage','-Wall','-Wextra',+ '-DSTM32G0B1xx','-DUSE_HAL_DRIVER','-DADOM_BRINGUP_OUTPUT_LOCK=1',f'-DADOM_USB_VID={r.vid}',f'-DADOM_USB_PID={r.pid}',f'-DADOM_LAB_BOOT_ID="{r.lab_boot_id}"']+flags += ['-I'+str(i) for i in includes]+commands=[]+def run(cmd):+ commands.append([str(s) for s in cmd]); subprocess.run(cmd,check=True)+objects=[]+for i,src in enumerate(sources):+ obj=out/f'{i:02d}-{src.stem}.o'; objects.append(obj)+ extra=['-std=c11','-Werror'] if src.is_relative_to(P) else []+ run([cc,*flags,*extra,'-c',src,'-o',obj])+elf=out/'adom-load-bringup.elf'+run([cc,'-mcpu=cortex-m0plus','-mthumb','-nostartfiles',*objects,'-T',P/'firmware/stm32/stm32g0b1kc.ld',+ '-Wl,--gc-sections,--print-memory-usage',f'-Wl,-Map={out}/adom-load-bringup.map','-L'+str(newlib),+ '-Wl,--start-group','-lc','-lm','-lnosys','-lgcc','-Wl,--end-group','-o',elf])+for fmt,ext in [('ihex','hex'),('binary','bin')]: run([str(prefix)+'objcopy','-O',fmt,elf,out/f'adom-load-bringup.{ext}'])+run([str(prefix)+'size',elf])+sha=lambda p:hashlib.sha256(p.read_bytes()).hexdigest()+manifest={'status':'compiled-only-output-locked','flashed':False,'physical_usb_verified':False,'load_enable_supported':False,+ 'production_boot_freshness':False,'lab_boot_id':r.lab_boot_id,'vid':r.vid,'pid':r.pid,+ 'toolchain':subprocess.check_output([cc,'--version'],text=True).splitlines()[0], 'dependencies':pins,+ 'sources':{str(p.relative_to(P)):sha(p) for p in sorted(set([s for s in sources if s.is_relative_to(P)] + list((P/'firmware').glob('*.h')) + [s for s in (P/'firmware/stm32').rglob('*') if s.is_file()] + [Path(__file__).resolve()]))},+ 'artifacts':{p.name:sha(p) for p in out.glob('adom-load-bringup.*')},'commands':commands}+(out/'build-manifest.json').write_text(json.dumps(manifest,indent=2)+'\n')+print('COMPILED ONLY: output permanently locked OFF; no flash or hardware validation performed.')