project
Adom Custom Electronic Load
Public Made by Adomby adom
Two-layer digitally controlled electronic-load prototype. Compact R11 is under active electrical, cooling and probe-access review; not a manufacturing release.
← Commit history
Add reproducible output-locked STM32 USB bring-up build; retain hardware qualification gates
20 files changed
+1427−11
design/mcu-pinmap.json+7−7design/stm32-bringup-build.json+57design/stm32-bringup-build.log+8docs/completion-plan.md+1−1docs/status.md+4firmware/stm32/README.md+30firmware/stm32/clock.c+90firmware/stm32/dependencies.json+18firmware/stm32/licenses/CMSIS_5-LICENSE.txt+201firmware/stm32/licenses/cmsis_device_g0-LICENSE.txt+201firmware/stm32/licenses/stm32g0xx_hal_driver-LICENSE.txt+27firmware/stm32/licenses/tinyusb-LICENSE.txt+21firmware/stm32/main.c+103firmware/stm32/stm32g0b1kc.ld+180firmware/stm32/stm32g0xx_hal_conf.h+351firmware/stm32/syscalls.c+26firmware/stm32/tusb_config.h+16firmware/stm32/usb_descriptors.c+27tools/audit_mcu_pinmap.py+3−3tools/build_stm32_bringup.py+56design/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>© 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.')