Skip to content

M0: firmware2 skeleton, DxCore CI, and Rev C pin map - #8

Merged
NT7S merged 1 commit into
masterfrom
cursor/firmware2-m0-a805
Oct 27, 2026
Merged

NT7S merged 1 commit into
masterfrom
cursor/firmware2-m0-a805

Conversation

@NT7S

@NT7S NT7S commented Oct 27, 2026 •

Copy link
Copy Markdown
Member

Milestone M0 of the OpenBeacon 2 Rev C firmware spec (draft 3.5). New tree only. The SAMD21 firmware under firmware/ is untouched, and this does not choose a project license. Not for merge until review.

What landed

  • firmware2/ sketch stub for the AVR128DA48, pin header, and a host test that locks the pin table.
  • CI (.github/workflows/firmware2.yml) builds with arduino-cli + DxCore and runs the host tests.

arduino-cli is the build tool because spec §4.1 names it, and §4.11 uploads with arduino-cli/avrdude over the CP2102N. The board options (chip, 24 MHz internal, millis on TCB2, Optiboot on USART0 PA0/PA1) are DxCore menu ids, passed as the FQBN. PlatformIO would wrap the same core through another package.

FQBN:

DxCore:megaavr:avrdaopti:chip=avr128da48,clock=24internal,millis=tcb2,bootloaderusart=ser0

Pinned to arduino-cli 1.5.1 and DxCore 1.6.2. drazzy.com's TLS certificate expired on 20 Oct 2026, so CI uses Spence Konde's GitHub copy of package_drazzy.com_index.json.

CI

Green. Both jobs passed on b9d9abb: https://github.com/etherkit/OpenBeacon2/actions/runs/40562158534

DxCore AVR128DA48 compile log:

OB2_FQBN DxCore:megaavr:avrdaopti:chip=avr128da48,clock=24internal,millis=tcb2,bootloaderusart=ser0
Sketch uses 1180 bytes (0%) of program storage space. Maximum is 130560 bytes.
Global variables use 168 bytes (1%) of dynamic memory, leaving 16216 bytes for local variables. Maximum is 16384 bytes.

The 130560 maximum is the Optiboot image (512 bytes reserved). The 168 bytes of SRAM are DxCore's digital_pin_to_* tables plus timingStruct. The pin-name strings are not linked into the image.

Host unit tests job (ctest):

1/1 Test #1: pins .............................   Passed    0.00 sec

100% tests passed, 0 tests failed out of 1

Total Test time (real) =   0.05 sec

ctest only prints the doctest summary on failure. The same binary run locally reports:

[doctest] doctest version is "2.4.11"
[doctest] test cases:   3 |   3 passed | 0 failed | 0 skipped
[doctest] assertions: 572 | 572 passed | 0 failed |
[doctest] Status: SUCCESS!

The three cases are the power-rework disclaimer, the 48-pin table against §2.1/§2.2, and the USART2/USART3/CLK4/SPI1 constraints. doctest 2.4.11 is vendored under firmware2/third_party/doctest/ with doctest's own MIT license. That is not a license for this repo.

Pin header vs spec §2.1 / §2.2

firmware2/OpenBeacon2/ob2_pins.h. DxCore numbers were checked against DxCore 1.6.2 variants/48pin-standard/pins_arduino.h and are static_asserted in ob2_pin_check.cpp. Every D-number the spec prints matches PIN_Pxx. Committed nets were read off U9 at pcb-layout 88e9a62 (pin endpoints to global labels). Where that commit and §2.2 differ, the header follows §2.2 and says the rework hardware is not in the repo.

Pkg Port D Header net 88e9a62 label Flag
1 PA5 5 BAND_A BAND_A
2 PA6 6 BAND_B BAND_B §2.1 role still says Q7 drives K2/K3/K5/K6. §2.2 assigns K2/K5 to BAND_B and K3/K6 to BAND_C. Header follows §2.2 and quotes the §2.1 text in the role.
3 PA7 7 D7_PA7 D7_PA7 J4.1 spare. DxCore LED_BUILTIN is this pin, not SYNC and not the TX LED. Stub does not use it.
4 PB0 8 GPS_RXD GPS_RXD USART3 TX to the GPS.
5 PB1 9 BAND_C no-connect Rework. Not in the repo. USART3 RXEN stays off.
6 PB2 10 CAL_CLK CAL_CLK Si5351C CLK4.
7 PB3 11 SI_INTR SI_INTR
8 PB4 12 OLED_DC OLED_DC
9 PB5 13 OLED_RES OLED_RES
10 PC0 14 UART_TX UART_TX USART1 TX, J10.
11 PC1 15 UART_RX UART_RX USART1 RX, J10.
12 PC2 16 SYNC_LED SYNC_LED
13 PC3 17 J4.3 D17_PC3 Same pin. Spec net is the jack position; committed label is D17_PC3.
14 — — VDD power Footnote pin, not a numbered §2.1 row.
15 — — GND power Footnote.
16 PC4 18 OLED_MOSI OLED_MOSI SPI1 ALT1 MOSI.
17 PC5 19 J4.5 D19_PC5 Same pin. SPI1 ALT1 MISO, input while SPI1 is master.
18 PC6 20 OLED_SCK OLED_SCK SPI1 ALT1 SCK.
19 PC7 21 OLED_CS OLED_CS SPI1 ALT1 SS driven as GPIO.
20 PD0 22 J5 D22_A0_PD0 Spec groups PD0–PD2 as one "J5" row. Header is one pin per row, net J5, AIN0. Stays on J5 after the rework.
21 PD1 23 J5 D23_A1_PD1 AIN1. Same naming note.
22 PD2 24 J5 D24_A2_PD2 AIN2. Same naming note.
23 PD3 25 BTN_UP BTN_UP
24 PD4 26 BTN_DOWN BTN_DOWN
25 PD5 27 BTN_LEFT BTN_LEFT
26 PD6 28 BTN_RIGHT BTN_RIGHT
27 PD7 29 BTN_BACK BTN_BACK Spec: do not select VREFA. DxCore also calls this AIN7/A7. Header does not add that channel.
28 — — AVDD power Footnote.
29 — — GND power Footnote.
30 PE0 30 BTN_DSP_1 BTN_DSP_1
31 PE1 31 TX_ISENSE D31_A9_PE1 Rework, AIN9. 88e9a62 still has this on J5.
32 PE2 32 CC1_SENSE D32_A10_PE2 Rework, AIN10. 88e9a62 still has this on J5.
33 PE3 33 CC2_SENSE D33_A11_PE3 Rework, AIN11. 88e9a62 still has this on J5.
34 PF0 blank (DxCore 34) Y1 no label (crystal) Spec DxCore column is "-". Not a firmware GPIO.
35 PF1 blank (DxCore 35) Y1 no label (crystal) Same. Default USART2 TX/RX are these pins.
36 PF2 36 GPS_PPS GPS_PPS
37 PF3 37 BTN_DSP_2 BTN_DSP_2
38 PF4 38 J4.7 D38_A20_PF4 Must not become USART2 TX. Spec net is the jack; committed label is D38_A20_PF4.
39 PF5 39 GPS_TXD GPS_TXD USART2 ALT1, RX only. J4.9 is NC.
40 PF6 blank (DxCore 40) RESET ~{RESET} DTR auto-reset. Not a firmware GPIO.
41 UPDI — J13 UPDI No Arduino number.
42 — — VDD power Footnote.
43 — — GND power Footnote.
44 PA0 0 MCU_TX MCU_TX USART0 TX to the CP2102N.
45 PA1 1 MCU_RX MCU_RX USART0 RX.
46 PA2 2 SDA SDA TWI0.
47 PA3 3 SCL SCL TWI0.
48 PA4 4 TX TX 12 V PA supply and TX LED.

Nothing in that table was renumbered to hide a mismatch. The four rework nets are the §2.2 change the header was asked to carry.

Other flags (not edited into the pin numbers)

  • OSCHF autotune. §4.1 says 24 MHz internal, auto-tuned to the 32.768 kHz crystal. DxCore clock=24internal writes FREQSEL only (CLKCTRL_OSCHFCTRLA = 0x09 << 2 in wiring.c) and has no autotune menu. The stub does not set AUTOTUNE. That needs the crystal running and belongs with the timebase.
  • SPI defaults. Display is SPI1 ALT1, as the spec says. SPI0's default pins are PA4–PA7 (TX, BAND_A, BAND_B, J4.1). SPI1's default mux uses PC0, PC2, and PA3 (UART_TX, SYNC_LED, SCL). Called out in the header so a later SPI.begin() does not take those pins.
  • DxCore comment bugs, left alone. In pins_arduino.h, digital_pin_to_bit_mask[] comments call PF2–PF5 AIN12–AIN15. The macros PIN_A18–PIN_A21 are PF2–PF5, and digitalPinToAnalogInput(PF2) returns 18. analogChannelToDigitalPin(18) returns NOT_A_PIN (channels 18–21 fall through a < 22 hole). AIN9/10/11, which the spec names, round-trip. digital_pin_to_timer[] comments number PC0 as pin 16; the slot is index 14 (D14).
Open in Web Open in Cursor 

The AVR128DA48 stub builds with arduino-cli and DxCore 1.6.2. Host tests lock the pin header to spec sections 2.1 and 2.2, including the uncommitted power-rework nets.

Co-authored-by: Jason Milldrum <NT7S@users.noreply.github.com>
@NT7S
NT7S merged commit 06902c1 into master Oct 27, 2026
2 checks passed
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.

2 participants