Skip to content

S19j Pro PIC variant support: handshake, heartbeat, temps, overtemp gate#3

Closed
Schnitzel wants to merge 1 commit into
skot:amlogic-s19jprofrom
Schnitzel:amlogic-s19jpro-pic-support
Closed

S19j Pro PIC variant support: handshake, heartbeat, temps, overtemp gate#3
Schnitzel wants to merge 1 commit into
skot:amlogic-s19jprofrom
Schnitzel:amlogic-s19jpro-pic-support

Conversation

@Schnitzel

Copy link
Copy Markdown

Summary

Extends the existing s19j_pro_amlogic board path to also drive PIC-variant Bitmain hashboards (BHB42601 / S19j Pro, BHB42611 / S19j Pro+) in addition to the noPIC variants (BHB42603 / BHB42631) already supported.

Background on the variant split is in the Braiins "PIC vs noPIC Bitmain Miners" blog. Short version: PIC variants gate per-domain DC-DC regulators behind an on-hashboard PIC16F1704 microcontroller. Without telling the PIC to enable DC-DC, the BM1362 chips stay unpowered even when the APW12 rail is up at spec voltage.

Changes

  • PIC handshake on init. PicChain::handshake() + enable_dc_dc() runs after PSU enable, before the chain UART comes up. Failure is warn! so noPIC boards still go through the existing code path.
  • PIC heartbeat from telemetry task (opcode 0x16 ~every 2 s, matching LuxOS' ~1.5 s cadence). Without it the PIC's watchdog disables DC-DC and chips drop mid-ramp.
  • PIC-mediated temperatures (opcode 0x3c at registers 0x48..0x4b) surfaced as HB{n}-PIC{0..3} in the API's temperatures field. The legacy TMP75 path still works as a fallback for noPIC boards.
  • 75 °C overtemp gate in the telemetry task. On trip: disable_dc_dc(), PSU output-off, cancel telemetry. Conservative for bench setups; long-term should be a config field.
  • disable_dc_dc() on shutdown before cutting the rail.
  • APW12 NAK retry in set_voltage with readback comparison. The firmware variant in our control board (fw=0x0010 hw=0x0071) intermittently NAKs response frames even when the DAC write actually succeeded; without retry the chain ramp stalls.
  • Voltage clamp to 13.2 V min (voltage_range and target_voltage). The generic voltage_for_frequency_stacked() formula is calibrated for 12-chip stacked regulators (emberone) and returns ~12.6 V on the 42-domain S19j Pro chain — 0.6 V under EEPROM spec, causes chips to fall off the chain at high frequency. See inline comment for the long-term fix (per-chip-family voltage tables in chip_config.rs).
  • disable-watchdog NAK softened to warn: this APW12 firmware variant rejects opcode 0x81 entirely; LuxOS uses periodic heartbeats instead.

Net diff: 1 file changed, +260 / -22 (most of which is the new PIC bring-up block + the retry logic + thoroughly-sourced comments).

Sources / methods

Per the maintainer's request, every non-obvious decision in the diff has an inline comment with its source. Brief recap:

  • PIC opcodes (0x06 start_app, 0x07 reset, 0x15 set_dc_dc, 0x16 heartbeat, 0x17 get_sw_ver, 0x3c read_reg) — extracted from HashSource/bitmain_antminer_binaries S21 single_board_test (functions reset_pic, start_app, get_pic_version, enable_dc_dc, disable_dc_dc, send_pic_heart_beat, read_reg).
  • Verified byte-for-byte against ftrace events/i2c/* captures of LuxOS doing a clean restart on the BHB42601. Frame format 0x55 0xAA <len> <opcode> <payload> <crc>, responses streamed one byte at a time with ~30 ms gaps (single block reads return bus-floating garbage on this hardware — that pacing is in PicChain::exchange()).
  • Voltage spec comes from the EEPROM voltage_v field decoded by eeprom_antminer::decode_antminer_eeprom. BHB42601 reports 13.20 V at 525 MHz factory test setpoint.
  • Overtemp threshold (75 °C) chosen below stock Bitmain's ~85–95 °C policy specifically because bench/dev setups have limited cooling.

Hardware test results

Tested on an Antminer S19j Pro (BHB42601 hashboards, AMLogic A113D control board, LuxOS as base, musl static cross-build from macOS):

  • PIC handshake succeeds at i2c addresses 0x20 (HB0) and 0x21 (HB1), firmware version 0x89.
  • Chain verification: 125/126 chips on HB1 (one chip dead, min_viable_chip_count correctly tolerates).
  • Frequency ramp completes to 500 MHz target at 13.2 V — no "Chips lost during frequency ramp".
  • Sustained mining: 18 TH/s on a single hashboard, 10+ minutes runtime, 601 valid shares accepted.
  • Plateau temps 31–47 °C with external AC Infinity fan; overtemp gate never tripped.
  • PIC temps visible in API:
    \"temperatures\": [
      {\"name\":\"HB1-PIC0\",\"temperature_c\":35.0},
      {\"name\":\"HB1-PIC1\",\"temperature_c\":31.0},
      {\"name\":\"HB1-PIC2\",\"temperature_c\":42.0},
      {\"name\":\"HB1-PIC3\",\"temperature_c\":46.0}
    ]
  • Clean shutdown via SIGTERM: disable_dc_dc() → PSU output-off; PIC + EEPROM still readable on standby afterwards.

Depends on

The matching PicChain library + pic-tool binary needs to land in amlogic-cb-tools first: skot/amlogic-cb-tools#2. This PR consumes amlogic_cb_tools::pic::{PicChain, pic_address_for_slot} and won't compile until that one is merged.

Open questions / known limitations

  • Single hashboard at a time. The existing select_hashboard() picks the first present board; multi-board mining (with shared PSU) would be a follow-up that touches the daemon and backplane registration, not this PR.
  • Overtemp threshold is hardcoded. Should be a field on AmlogicStartupConfig. Left out to keep this PR focused on the bring-up path.
  • voltage_for_frequency_stacked() is shared with emberone. The 13.2 V clamp here is a workaround; the cleaner fix is per-chip-family voltage tables in chip_config.rs. Discussed in inline comment.
  • Opcode 0x3a (no payload, sent before/after enable_dc_dc and in the heartbeat loop in LuxOS) is captured but not used — bring-up works without it. Left as future investigation.
  • HB2 hardware seems flaky in our test rig: PIC handshake works, DC-DC enables (chips draw current confirmed by temp rise), but 0/126 chips respond on UART. Almost certainly a head-of-chain failure on the physical board, not a software issue — same code drives HB1 fine.

The original `s19j_pro_amlogic` path drives noPIC-variant Bitmain
hashboards (BHB42603 / BHB42631 / S19j Pro 104T) where the BM1362
chips are powered directly from the APW12 rail. This change extends
that path to also drive PIC-variant boards (BHB42601 / S19j Pro,
BHB42611 / S19j Pro+, etc.), where per-domain DC-DC regulators are
gated by an on-hashboard PIC16F1704 microcontroller.

Background on the variant split:
  https://braiins.com/blog/pic-vs-nopic-bitmain-miners-...

Without telling the PIC to enable DC-DC, the BM1362s stay unpowered
even when the rail is at the spec voltage; naive `output-on` causes
the rail to sag as the closed-by-default regulator inputs draw
inrush through their input caps. With the PIC handshake in place, the
existing chain UART / ramp / hash-thread code wakes up cleanly and
mines.

The `PicChain` library (`amlogic_cb_tools::pic`) is the matching
piece; opcodes were derived from HashSource's decompiled S21
single_board_test
  https://github.com/HashSource/bitmain_antminer_binaries
and verified byte-for-byte against ftrace captures of LuxOS on a
real BHB42601 (i2c-0 events at startup). See `pic-tool` and the
`amlogic-cb-tools` PR for the standalone diagnostic.

Changes in this commit:

- Run `PicChain::handshake()` + `enable_dc_dc()` after PSU enable
  and before the chain comes up. Failure is a `warn!` so noPIC
  hardware still bring up via the existing path (handshake will fail
  on a board with no PIC at the expected address; enable_dc_dc has
  no effect on a noPIC board because there's no PIC to talk to).

- Periodic PIC heartbeat (opcode 0x16) from the telemetry task. LuxOS
  sends one ~every 1.5 s; without it the PIC disables DC-DC after a
  watchdog timeout and chips drop mid-ramp.

- PIC-mediated temperature reads (opcode 0x3c at registers 0x48..0x4b)
  via the same handle. These show up in the `temperatures` field of
  the API as `HB{slot}-PIC{0..3}` and match what LuxOS reports.

- Conservative 75 °C overtemp gate in the telemetry task. On trip:
  disable DC-DC, output-off the PSU, cancel telemetry. Stock Bitmain
  firmware uses ~85–95 °C for throttle/shutdown; this is more aggressive
  because bench setups have limited cooling and the failure mode of
  hot-running a hashboard is severe (the BHB42601 we used to bring
  this up arced its 12 V input plane the first time).

- `disable_dc_dc()` on shutdown before cutting the rail.

- Make `set_voltage` resilient against the APW12 firmware variant
  (fw 0x0010 / hw 0x0071 here) that intermittently NAKs response
  frames even when the underlying DAC write succeeded. Retry up to
  4× with readback comparison; without this the chain ramp stalls on
  the first NAK and the scheduler refuses to assign jobs.

- Voltage range / target: BHB42601 EEPROM specifies 13.20 V at
  525 MHz. The generic `voltage_for_frequency_stacked()` formula in
  `bm13xx::thread_v2` is calibrated for emberone-style 12-chip
  stacked regulators (per-chip 0.3 V × 12 chips = 3.6 V) and returns
  ~12.6 V when applied to the 42-domain series chain on S19j Pro
  (0.3 V × 42). 0.6 V under spec causes chips to fall off the chain
  mid-ramp. Clamp `voltage_range` min to 13.2 V so the ramp always
  programs at least spec voltage. Long-term fix is per-chip-family
  voltage-frequency tables in `chip_config.rs`; left for later.

- `disable-watchdog` rejected by this APW12 firmware (NAK on opcode
  0x81); downgraded from fatal to warn since LuxOS uses periodic
  heartbeats instead and works fine.

Tested end-to-end on an Antminer S19j Pro (BHB42601, kernel aarch64,
userspace armhf, musl static binary). Sustained 18 TH/s on a single
hashboard for 10+ minutes, 601 valid shares accepted, peak temp 47 °C
(75 °C cutoff never tripped), zero chips lost during ramp. PIC
firmware version 0x89 on both PICs at i2c addresses 0x20 and 0x21.

Depends on the matching `PicChain` library landing in
amlogic-cb-tools (PR skot/amlogic-cb-tools#2).
@Schnitzel

Copy link
Copy Markdown
Author

Superseded by #6, which has been refreshed to our current integration branch and now carries the complete, current board-support stack (this PR's code had diverged as development continued). Consolidating into #6 rather than maintaining diverged branches. Closing in its favor.

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.

1 participant