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:
@@ -270,6 +270,12 @@ if(PROJECT_IS_TOP_LEVEL)
|
||||
add_test(NAME pureboot_autobaud.size
|
||||
COMMAND ${CMAKE_COMMAND} -DSIZE_TOOL=${CMAKE_SIZE} -DELF=$<TARGET_FILE:pureboot_autobaud>
|
||||
-DLIMIT=${PUREBOOT_LIMIT} -P ${CMAKE_CURRENT_SOURCE_DIR}/test/check_size.cmake)
|
||||
# The measured unit is the loader's only RAM object and sits at the very
|
||||
# start of SRAM — where the host reads the bit period from (--info's
|
||||
# measured clock), so the address is wire contract, not layout accident.
|
||||
add_test(NAME pureboot_autobaud.unit
|
||||
COMMAND ${CMAKE_COMMAND} -DOBJDUMP=${CMAKE_OBJDUMP} -DELF=$<TARGET_FILE:pureboot_autobaud>
|
||||
-DRAM_START=${PUREBOOT_RAM_START} -P ${CMAKE_CURRENT_SOURCE_DIR}/test/check_unit.cmake)
|
||||
|
||||
# One point of the exhaustive matrix, named from its resolved parameters
|
||||
# so the enumeration cannot collide with itself. `pins` is empty for the
|
||||
@@ -390,6 +396,38 @@ if(PROJECT_IS_TOP_LEVEL)
|
||||
RX ${PUREBOOT_USART1_RX} TX ${PUREBOOT_USART1_TX})
|
||||
endif()
|
||||
|
||||
# The OSCCAL axis at its fixed points: the stock shape, and the tightest
|
||||
# image in the space with the trim on top — the axis adds one register
|
||||
# write, and these points hold both of its addressing encodings to every
|
||||
# chip's budget.
|
||||
pureboot_size_variant(pureboot_osccal OSCCAL 0x9c)
|
||||
pureboot_size_variant(pureboot_autobaud_osccal SERIAL autobaud OSCCAL 0x9c)
|
||||
if(PUREBOOT_HAS_USART)
|
||||
pureboot_size_variant(pureboot_autobaud_osccal_on_usart0 SERIAL autobaud OSCCAL 0x9c
|
||||
RX ${PUREBOOT_USART0_RX} TX ${PUREBOOT_USART0_TX})
|
||||
endif()
|
||||
|
||||
# The trim byte, observed through the wire from the first prompt — one
|
||||
# chip per OSCCAL addressing class: extended I/O on the 328P (data 0x66,
|
||||
# an sts — DS40002061B §36), plain I/O on the 85 (data 0x51, an out —
|
||||
# Atmel-2586 §21).
|
||||
if(LIBAVR_MCU MATCHES "^(atmega328p|attiny85)$" AND DEFINED PB_DEVICE)
|
||||
if(LIBAVR_MCU STREQUAL "atmega328p")
|
||||
set(_osccal_addr 0x66)
|
||||
else()
|
||||
set(_osccal_addr 0x51)
|
||||
endif()
|
||||
get_target_property(_osccal_hz pureboot_osccal PUREBOOT_HZ)
|
||||
get_target_property(_osccal_baud pureboot_osccal PUREBOOT_BAUD)
|
||||
add_test(NAME pureboot.osccal
|
||||
COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/pbosccal.py
|
||||
${PB_DEVICE} $<TARGET_FILE:pureboot_osccal> ${PUREBOOT_SIM_MCU}
|
||||
${_osccal_hz} ${PUREBOOT_BASE_HEX} ${PUREBOOT_PAGE} ${_osccal_baud}
|
||||
${_osccal_addr} 0x9c ${CMAKE_CURRENT_SOURCE_DIR}/pureboot/pureboot.py
|
||||
${CMAKE_BINARY_DIR}/pbosccal-work)
|
||||
set_tests_properties(pureboot.osccal PROPERTIES TIMEOUT 120)
|
||||
endif()
|
||||
|
||||
# One configured deployment end to end — a real board's shape rather
|
||||
# than the stock assumption: the ATmega328P on its shipped 1 MHz fuses,
|
||||
# the software UART on hand-picked pins (TX = PB1, RX = PB5), the ladder
|
||||
|
||||
Reference in New Issue
Block a user