Skip to content

Add SAMD51 port with the Intech Studio Grid bootloader boards - #7

Open
SukuWc wants to merge 27 commits into
masterfrom
samd51-intech-grid
Open

SukuWc wants to merge 27 commits into
masterfrom
samd51-intech-grid

Conversation

@SukuWc

@SukuWc SukuWc commented Oct 19, 2026

Copy link
Copy Markdown
Member

Summary

  • New ports/samd51 for SAMD51N20A, CMake only (like stm32h5 and maxim), with the boards intech_grid and intech_wrid (same hardware and USB IDs, different volume label so the two bootloaders can be told apart).
  • 16 KB bootloader, application at 0x4000. DFU on the PC11 button (through board_app_valid2()) or an invalid application. NeoPixel indicator on PB30, BOD33 at 2.7 V, DFLL in USB clock recovery mode (no crystal).
  • UF2 writes are limited to whole 256 byte rows of the application area. Rows already holding their data are skipped; a block is erased only when a differing row needs it, keeping the rows already written.
  • Bootloader protection uses TINYUF2_PROTECT_BOOTLOADER (BOOTPROT in the user page, re-armed at boot). The self-update app lifts it with SBPDIS, rewrites the bootloader area and erases its own first block from RAM.
  • Apps: update-tinyuf2 and blinky. A Debug build raises the boot size to 64 KB like stm32h5.
  • CI: samd51 in the arm-cmake job, check_build.py backends and representatives, README table, supported_boards.md, tools/get_deps.py (microchip_driver, same commit as TinyUSB).

Not included

  • Double tap, reboot from application and erase_firmware (it needs TINYUF2_DBL_TAP_DFU).
  • SAM-BA/CDC, HID and WebUSB transports of uf2-samdx1.

Test plan

  • check_build.py for intech_grid and intech_wrid; the 13 non-ESP-IDF boards of the contract build pass
  • .claude/test (277 tests) and pre-commit run --all-files
  • On an Intech Grid (SAMD51N20A rev D) with a CMSIS-DAP probe: enumeration and INFO_UF2.TXT, boot of the application, button entry, LED states during flash writes
  • Invalid UF2 blocks (bootloader area, user page, past the flash end, wrong size, unaligned) are rejected and change nothing
  • Shuffled UF2 with a mix of identical and changed rows, repeated copies in one session, original contents restored byte for byte
  • Self-update both ways between intech_grid and intech_wrid: bootloader matches the build, BOOTPROT re-armed, user page unchanged
  • blinky.uf2 runs; tinyuf2-openocd target flashes a protected chip
  • ESP-IDF boards of the contract build (need CI's docker image)
  • Power cut during a self-update (same exposure as uf2-samdx1)
  • SAMD51 errata check of the NVM cache workaround (kept from uf2-samdx1, written for Rev A; the tested chip is Rev D)

🤖 Generated with Claude Code

hathach and others added 14 commits October 15, 2026 18:46
…#550)

STM32CubeProgrammer drives the ST-LINK sessions; stm32h563_nucleo re-enters DFU through the retained register.
Upstream now builds on IDF 6.1 without local patches; the sources, manifest and provenance files are the registry release's, unmodified. 3.1.0 also changes the WS2812 default bit timings (espressif/idf-extra-components#816).
adafruit#557)

* espressif_esp32s3_devkitc_1: note the v1.0 NeoPixel pin

* espressif_esp32s3_devkitc_1: report board ID v1.1
Route OTG FS to the USB-C Serial/JTAG pins (GPIO24/25) and restore ROM USB
routing on reset. Detect double reset with a calibrated ADC charge marker on
BAT_SENSE, which needs CBATRAW changed to 2.2 uF, and drive the bootloader
NeoPixel with RMT.

Co-authored-by: Limor Fried <ladyada@users.noreply.github.com>
IDF 6.1's usb_new_phy() moves a P4 device with undefined speed onto the HS
UTMI PHY, so dfu_runtime on the Metro needs the same FS speed and GPIO24/25
swap as TinyUF2. Key FS speed on rhport 0, build the ADC and RMT bootloader
sources only for P4, and reuse usb_persist_shutdown_handler() for Touch1200.
…e-reset

Add Metro ESP32-P4 support with ADC double-reset detection
…mechanics (adafruit#521)

* hil: rename the HIL contract to hil-contract and keep only TinyUF2's mechanics

agentrc's hil skill now holds the rules every project shares (locks,
running, reporting, verdicts, retries); this page keeps the roster,
selection, build record, battery, reservation, results, recovery and
limits under its eight sections. Requires hathach/agentrc#83.

* hil-contract: state completion, the port cycle's scope and the shared host after the co-review

* hil-contract: record the port cycle's reach in Limits and point the lock rules at hil

* hil-contract: skip the port restore only when a cycle child survives SIGKILL

* hil-contract: restore port power from the off write on
The runner loaded tinyusb's lock helper from whatever checkout TINYUSB_DIR named. The lib/agentrc
submodule now pins agentrc's shared hil_lock.py (hathach/agentrc#117); hil_test.py refuses before any
hardware access when the submodule is missing, at another commit or modified; check_build requires it.
Folds adafruit#568 (contract page repairs). Closes adafruit#564.

Hardware: metro_m7_1011 battery pass, hold/install/restore/release pass, exclusion both ways with
tinyusb's helper. Tests: .claude/test 301 OK.
Adds a ci.lan HIL job that runs the battery on the rig's self-hosted runner,
the ci.lan roster with the RT1064 EVK, a bounded lock wait, and report rows
for refused, signalled and failed-probe runs.
New ports/samd51 for SAMD51N20A, built with CMake like stm32h5 and maxim.

- Boards intech_grid and intech_wrid (same hardware and USB IDs, different
  volume label), application at 0x4000 behind a 16 KB bootloader.
- Bootloader enters DFU on the PC11 button or an invalid application, through
  board_app_valid2(). Neopixel indicator on PB30, BOD33 set to 2.7V, DFLL in
  USB clock recovery mode (no crystal).
- UF2 writes are limited to whole 256 byte rows of the application area. Rows
  already holding their data are skipped and a block is erased only when a
  differing row needs it, keeping the rows already written.
- The bootloader protects itself with BOOTPROT (TINYUF2_PROTECT_BOOTLOADER).
  The self-update app lifts it with SBPDIS, rewrites the bootloader area and
  erases its own first block from RAM.
- The blinky and self-update apps are built. A Debug build increases the boot
  size to 64 KB like stm32h5.
- CI: samd51 in the arm-cmake job, check_build.py backends and representatives.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Name the level that switches the neopixel supply on instead of hard coding
it, as NEOPIXEL_POWER_PIN and NEOPIXEL_POWER_STATE do in the espressif boards.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@SukuWc
SukuWc force-pushed the samd51-intech-grid branch from 64464e1 to 3c69663 Compare October 19, 2026 12:53
SukuWc and others added 13 commits October 19, 2026 15:05
The UF2 spec describes Board-ID as dash-separated tokens: CPU type, board type
and board revision. Add the revision token, as the other boards do:
SAMD51N20A-GRID-v0 and SAMD51N20A-WRID-v0.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The _NS constants did not match the measured pulse widths because the
PORT writes and cycle counter reads add a fixed cost. Count in cycles
instead, so the names say what is programmed. The bit period now measures
about 1.2us, close to the nominal 1.25us.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The application linker script capped the flash at 256 KB although the
boards have 1 MB. Pass the flash size from board.cmake like the boot and
RAM sizes, so a board with another SAMD51 variant only sets its own values.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A Cortex-M reset handler address must have the Thumb bit set. An image
with an even or zero vector passed the self-update validation, replaced
the bootloader and could not start. Also document that a power cut while
the BOOTPROT fuse is rewritten leaves the user page blank.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The boards are not part of the SAMD51 port.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The change is not part of the SAMD51 port.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants