pureboot.py: --scan walks a silent loader's rate; --info decodes the clock
The RC-oscillator answer's host half. --scan probes ±10 % around the built rate in 2 % steps, nearest first, one activation window (one reset) per probe: a fixed-baud loader whose oscillator drifted answers at the ratio, and the report gives the session workaround (--baud), the offset, the OSCCAL direction at ~1 %/step, and the autobaud way out. The walk and the advice are logic-tested (test_scan.py, red-proven on the trim direction) — a pty carries bytes at any rate, so the wire cannot arbitrate them. On an autobaud session --info now reads the measured bit period from ram_start — the geometry table gains that column — and undoes the unit's encoding ((cycles − 8) / 4, floored: libavr's spin granule and per-bit overhead), so the printed clock is the true one within a granule; --clock turns it into a stated drift. The autobaud end-to-end asserts the figure inside exactly that envelope at both clock points. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,7 @@ baked in.
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
|
||||
@@ -58,11 +59,23 @@ def main():
|
||||
try:
|
||||
# The host tool, in autobaud mode, sends the 0xC0 calibration pulse
|
||||
# and a single knock at `baud`; the loader locks to it.
|
||||
out = pbsim.run_tool(tool, device.pty, baud, "--autobaud", "--info", "--fuses",
|
||||
"--flash", app_bin, "--eeprom", ee_path, "--stay")
|
||||
out = pbsim.run_tool(tool, device.pty, baud, "--autobaud", "--info", "--clock", str(hz),
|
||||
"--fuses", "--flash", app_bin, "--eeprom", ee_path, "--stay")
|
||||
for needed in ("version", "signature", "fuses", "verify:", "stays"):
|
||||
if needed not in out:
|
||||
fail(f"{label}: session output lacks {needed!r}\n{out}")
|
||||
# The measured clock, decoded from the unit at ram_start. The
|
||||
# runner's clock is exact, so the figure must land inside the
|
||||
# encoding's own envelope: the loader floors the bit period to
|
||||
# 4-cycle spin granules after an 8-cycle discount, and the edge
|
||||
# poll can shave a few cycles more — one granule of slack below
|
||||
# the true clock, none above (in cycles per bit, times the rate).
|
||||
measured = re.search(r"measured\s+(\d+) Hz", out)
|
||||
if not measured:
|
||||
fail(f"{label}: --info lacks the measured clock\n{out}")
|
||||
measured = int(measured.group(1))
|
||||
if not hz - 19 * baud <= measured <= hz + 4 * baud:
|
||||
fail(f"{label}: measured clock {measured} Hz is {measured - hz:+d} off the true {hz}")
|
||||
# Read both memories back over the locked link and check them.
|
||||
read_flash = os.path.join(workdir, f"rf_{label}.bin")
|
||||
read_eeprom = os.path.join(workdir, f"re_{label}.bin")
|
||||
|
||||
Reference in New Issue
Block a user