The RC-oscillator answer's device half (dev/tasks.md in libavr): OSCCAL joins pureboot_add_loader() as one optional byte, written at the top of run() before the WDRF bail so the watchdog hand-over inherits the corrected clock too. Orthogonal to the backend — an autobaud build may carry it purely for the application. No value, no code: the stock image differs from v5 in exactly the version's two bytes (the stamp and the 'b' immediate). Measured: +6 B where OSCCAL takes sts (328P, 404→410), +4 B in low I/O (t85, 402→406); the tightest image in the space (1284 autobaud on USART pins, 504) carries the sts form at 510 of 512. New gates: the OSCCAL size points on every chip, the wire-observed trim byte on both addressing classes (test/pbosccal.py, red-green), and the autobaud unit pinned to ram_start (test/check_unit.cmake, red-green) — the address --info's measured-clock read is about to rely on. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
47 lines
1.6 KiB
Python
47 lines
1.6 KiB
Python
#!/usr/bin/env python3
|
|
"""The build-time OSCCAL trim, observed through the wire: a loader built with
|
|
the OSCCAL axis holds the trim register at the built byte from its first
|
|
prompt on — the write sits at the top of run(), ahead of the WDRF bail, so
|
|
every path out of reset runs on the corrected clock. simavr's clock does not
|
|
follow OSCCAL, which is what makes the value assertable at all: the register
|
|
is plain state there, and the peek must return exactly what the build
|
|
declared rather than whatever the oscillator needed.
|
|
|
|
Usage: pbosccal.py <device_bin> <pureboot_elf> <mcu> <hz> <base_hex> <page>
|
|
<baud> <osccal_addr> <osccal_value> <tool_py> <workdir>
|
|
[link]
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
|
|
|
|
def fail(message):
|
|
print(f"FAIL: {message}")
|
|
sys.exit(1)
|
|
|
|
|
|
def main():
|
|
args = sys.argv[1:]
|
|
link = args.pop() if len(args) == 12 else None
|
|
(device_bin, elf, mcu, hz, base_hex, page, baud, addr, value, tool, workdir) = args
|
|
addr, value, baud = int(addr, 0), int(value, 0), int(baud)
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
import pbsim
|
|
|
|
os.makedirs(workdir, exist_ok=True)
|
|
dump = os.path.join(workdir, "flash_dump.bin")
|
|
device = pbsim.Device(device_bin, elf, mcu, hz, base_hex, page, baud, dump, link=link)
|
|
try:
|
|
out = pbsim.run_tool(tool, device.pty, baud, "--peek", f"{addr:#x}:1")
|
|
want = f"{addr:#06x} {value:02x}"
|
|
if want not in out:
|
|
fail(f"OSCCAL at {addr:#x} did not read back {value:#04x}:\n{out}")
|
|
finally:
|
|
device.stop()
|
|
print("OK")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|