pureboot 6: a build-time OSCCAL trim, applied ahead of every reset path
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>
This commit is contained in:
46
test/pbosccal.py
Normal file
46
test/pbosccal.py
Normal file
@@ -0,0 +1,46 @@
|
||||
#!/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()
|
||||
Reference in New Issue
Block a user