From 9dcdd2ff951123b5efb8b177899cb8e8d45fa2d9 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 8 Nov 2026 02:35:29 +0000 Subject: [PATCH 1/3] Add an opt-in SI5351_NO_CLK67 gate for the CLK6/CLK7 planner Defining SI5351_NO_CLK67 leaves out multisynth67_calc and the CLK6/CLK7 branches in set_freq, set_freq_manual, set_ms, pll_update, and ms_div. Without the macro the public API and behavior stay the same. The Uno flash check compiles the gated runtime sketch alongside the existing ones and locks it at 10442 bytes. Co-authored-by: Jason Milldrum --- .github/workflows/flash-budget.yml | 12 +++++---- README.md | 9 +++++++ src/si5351.cpp | 26 +++++++++++++++++++ src/si5351.h | 5 ++++ tests/regression/README.md | 2 +- tests/regression/flash/budgets.txt | 4 +++ tests/regression/flash/check_flash_budget.sh | 23 ++++++++++------ .../sketches/min_runtime_no_clk67.ino.txt | 19 ++++++++++++++ 8 files changed, 86 insertions(+), 14 deletions(-) create mode 100644 tests/regression/flash/sketches/min_runtime_no_clk67.ino.txt diff --git a/.github/workflows/flash-budget.yml b/.github/workflows/flash-budget.yml index 148e1a3..19ff175 100644 --- a/.github/workflows/flash-budget.yml +++ b/.github/workflows/flash-budget.yml @@ -1,8 +1,10 @@ -# Uno flash ceilings for the two minimal sketches. A missing tool, a failed -# compile, an unparsed size line, or a sketch over its budget fails the job. -# The numbers are the measured text+data sizes of the fixtures in -# tests/regression/flash/sketches. Each fixture is its own baseline. -# min_runtime is a new sketch; the audit runtime sketch was not saved. +# Uno flash ceilings for the minimal sketches, including min_runtime compiled +# with -DSI5351_NO_CLK67. A missing tool, a failed compile, an unparsed size +# line, or a sketch over its budget fails the job. The numbers are the +# measured text+data sizes of the fixtures in tests/regression/flash/sketches. +# Each fixture is its own baseline. min_runtime is a new sketch; the audit +# runtime sketch was not saved. The gated build is this same job, not a +# separate workflow. name: Uno flash budget on: diff --git a/README.md b/README.md index 3cd6dbe..ed46ecc 100644 --- a/README.md +++ b/README.md @@ -294,6 +294,15 @@ Constraints * The frequency range of Multisynth 6 and 7 is ~18.45 kHz to 150 MHz. The library assigns PLLB to these two multisynths, so if you choose to use both, then both frequencies must be an even divisor of the PLL frequency (between 6 and 254), so plan accordingly. You can see the current PLLB frequency by accessing the _pllb_freq_ public member. * VCXO pull range can be ±30 to ±240 ppm +Leaving out CLK6 and CLK7 +------------------------- +CLK6 and CLK7 use a separate even-integer planner (`multisynth67_calc`, `ms67_div`, and the CLK6/CLK7 branches in `set_freq()`, `set_freq_manual()`, `set_ms()`, `pll_update()`, and `ms_div()`). Define `SI5351_NO_CLK67` when the library is compiled to leave that code out. The public methods and the `si5351_clock` enumerators stay. With the macro defined, `set_freq()` and `set_freq_manual()` return 1 for CLK6 and CLK7 and do not write those multisynths. `reset()` still initializes all eight clock-control registers. Without the macro, behavior is unchanged. + +A `#define` in a sketch is not visible to `si5351.cpp`. Pass the macro as a compiler definition so every translation unit that builds the library sees it: + +* Arduino CLI: `--build-property compiler.cpp.extra_flags=-DSI5351_NO_CLK67` +* PlatformIO: `build_flags = -DSI5351_NO_CLK67` + Frequency Limits ---------------- Numbers below are what v2.4.1 programs, checked against `src/si5351.cpp`, `src/si5351.h`, AN619 rev. 0.8, and the Si5351A/B/C-B datasheet rev. 1.3. Frequencies passed to `set_freq()` are in units of 0.01 Hz. diff --git a/src/si5351.cpp b/src/si5351.cpp index f1fbb42..edb74a4 100644 --- a/src/si5351.cpp +++ b/src/si5351.cpp @@ -61,6 +61,8 @@ static uint8_t recalc_force; // Even-integer MS6/7 ratio (6..254) of pll_freq for an output freq, using the // smallest R divider that brings the ratio down to 254. Returns the ratio and // sets *r_div, or returns 0 if no valid ratio/R pair exists. +// Left out of the build when SI5351_NO_CLK67 is defined (see the README). +#ifndef SI5351_NO_CLK67 static uint8_t ms67_div(uint64_t pll_freq, uint64_t freq, uint8_t *r_div) { uint64_t n; @@ -92,6 +94,7 @@ static uint8_t ms67_div(uint64_t pll_freq, uint64_t freq, uint8_t *r_div) return 0; } +#endif // AN619: feedback ratio 15..90 and VCO 600..900 MHz. A reference outside // 6.67..60 MHz (e.g. 5 MHz) has no valid setting; such PLLs are not written. @@ -488,6 +491,7 @@ uint8_t Si5351::set_freq(uint64_t freq, enum si5351_clock clk) } else { +#ifndef SI5351_NO_CLK67 // MS6 and MS7 logic // ----------------- uint8_t peer = (clk == SI5351_CLK6) ? (uint8_t)SI5351_CLK7 : (uint8_t)SI5351_CLK6; @@ -572,6 +576,10 @@ uint8_t Si5351::set_freq(uint64_t freq, enum si5351_clock clk) } return 0; +#else + // CLK6/CLK7 planner is compiled out. Do not write. + return 1; +#endif } } @@ -615,6 +623,7 @@ uint8_t Si5351::set_freq_manual(uint64_t freq, uint64_t pll_freq, enum si5351_cl // R divider, or refuse before writing anything if there is none if((uint8_t)clk >= (uint8_t)SI5351_CLK6) { +#ifndef SI5351_NO_CLK67 ms_reg.p1 = ms67_div(pll_freq, freq, &r_div); if(ms_reg.p1 == 0) { @@ -622,6 +631,9 @@ uint8_t Si5351::set_freq_manual(uint64_t freq, uint64_t pll_freq, enum si5351_cl } ms_reg.p2 = 0; ms_reg.p3 = 0; +#else + return 1; +#endif } else if(freq >= SI5351_MULTISYNTH_DIVBY4_FREQ * SI5351_FREQ_MULT) @@ -759,6 +771,7 @@ void Si5351::pll_update(enum si5351_pll pll, uint64_t pll_freq) r_div = 0; if(i >= 6) { +#ifndef SI5351_NO_CLK67 reg.p1 = ms67_div(pll_freq, f, &r_div); if(reg.p1 == 0) { @@ -767,6 +780,9 @@ void Si5351::pll_update(enum si5351_pll pll, uint64_t pll_freq) reg.p2 = 0; reg.p3 = 0; div_by_4 = 0; +#else + continue; +#endif } else { @@ -831,6 +847,7 @@ void Si5351::set_ms(enum si5351_clock clk, struct Si5351RegSet ms_reg, uint8_t i pll_reset(pll_assignment[clk]); } } +#ifndef SI5351_NO_CLK67 else if((uint8_t)clk <= (uint8_t)SI5351_CLK7) { // MS6 and MS7 only use one register (90 / 91). @@ -840,6 +857,7 @@ void Si5351::set_ms(enum si5351_clock clk, struct Si5351RegSet ms_reg, uint8_t i (uint8_t)ms_reg.p1); ms_div(clk, r_div, div_by_4); } +#endif } /* @@ -1722,6 +1740,7 @@ uint64_t Si5351::multisynth_calc(uint64_t freq, uint64_t pll_freq, struct Si5351 } } +#ifndef SI5351_NO_CLK67 uint64_t Si5351::multisynth67_calc(uint64_t freq, uint64_t pll_freq, struct Si5351RegSet *reg) { //uint8_t p1; @@ -1810,6 +1829,7 @@ uint64_t Si5351::multisynth67_calc(uint64_t freq, uint64_t pll_freq, struct Si53 } } } +#endif void Si5351::update_sys_status(struct Si5351Status *status) { @@ -1856,7 +1876,11 @@ void Si5351::ms_div(enum si5351_clock clk, uint8_t r_div, uint8_t div_by_4) } else { +#ifndef SI5351_NO_CLK67 reg_addr = SI5351_CLK6_7_OUTPUT_DIVIDER; +#else + return; +#endif } reg_val = si5351_read(reg_addr); @@ -1877,6 +1901,7 @@ void Si5351::ms_div(enum si5351_clock clk, uint8_t r_div, uint8_t div_by_4) reg_val |= (r_div << SI5351_OUTPUT_CLK_DIV_SHIFT); } +#ifndef SI5351_NO_CLK67 else if(clk == SI5351_CLK6) { // Clear the relevant bits @@ -1891,6 +1916,7 @@ void Si5351::ms_div(enum si5351_clock clk, uint8_t r_div, uint8_t div_by_4) reg_val |= (r_div << SI5351_OUTPUT_CLK_DIV_SHIFT); } +#endif si5351_write(reg_addr, reg_val); } diff --git a/src/si5351.h b/src/si5351.h index b7552d0..239271a 100644 --- a/src/si5351.h +++ b/src/si5351.h @@ -355,7 +355,12 @@ class Si5351 void pll_update(enum si5351_pll, uint64_t); uint64_t pll_calc(enum si5351_pll, uint64_t, struct Si5351RegSet *, int32_t, uint8_t); uint64_t multisynth_calc(uint64_t, uint64_t, struct Si5351RegSet *); + /* Omitted when SI5351_NO_CLK67 is defined. See the README. The macro has + * to be a compiler definition; a #define in a sketch does not reach + * si5351.cpp. Without it, this declaration is always present. */ +#ifndef SI5351_NO_CLK67 uint64_t multisynth67_calc(uint64_t, uint64_t, struct Si5351RegSet *); +#endif void update_sys_status(struct Si5351Status *); void update_int_status(struct Si5351IntStatus *); void ms_div(enum si5351_clock, uint8_t, uint8_t); diff --git a/tests/regression/README.md b/tests/regression/README.md index 5045400..d4f3389 100644 --- a/tests/regression/README.md +++ b/tests/regression/README.md @@ -53,6 +53,6 @@ Exit code: 0 = every check PASS/XFAIL/SKIP/INFO; 1 = at least one unexpected FAI ## Layout `v231/` acceptance runner, scenarios, oracle, locks, and reports · `stubs/` Arduino/Wire host stubs · `issue106/` t106 and its multi-bus stubs · `reset_freq/` `reset_freq()` regression · `equiv/` harness, goldens snapshot, compare.py · `reference/v242_f885fca/` pinned v2.4.2 source (the hard gate) · `reference/master_1ddd43e/` historical source, not the gate · -`ctrl/` `plan/` branch locks · `flash/check_flash_budget.sh` Uno byte ceilings (separate CI workflow) · `python/` golden/spec suites and refs · +`ctrl/` `plan/` branch locks · `flash/check_flash_budget.sh` Uno byte ceilings, including the `SI5351_NO_CLK67` sketch (separate CI workflow) · `python/` golden/spec suites and refs · `sketches/` Ctor106 · `boards.txt` board set and Boards Manager URLs · `tools/summarize.py`. `v231/Makefile` is the original manual build, kept for reference only; the script does not use it. diff --git a/tests/regression/flash/budgets.txt b/tests/regression/flash/budgets.txt index 98b91a2..b7a172f 100644 --- a/tests/regression/flash/budgets.txt +++ b/tests/regression/flash/budgets.txt @@ -20,5 +20,9 @@ # fixture's measurement. # min_runtime is a new fixture: global volatile uint8_t clock index, constant # 14 MHz. Its own baseline on this pin is 11558. +# min_runtime_no_clk67 is that same program compiled with -DSI5351_NO_CLK67 +# (compiler.cpp.extra_flags). Measured 10442 on this pin. min_const and +# min_runtime stay at the ungated sizes: the macro is opt-in. min_const 10830 min_runtime 11558 +min_runtime_no_clk67 10442 diff --git a/tests/regression/flash/check_flash_budget.sh b/tests/regression/flash/check_flash_budget.sh index 92161cc..b22a210 100755 --- a/tests/regression/flash/check_flash_budget.sh +++ b/tests/regression/flash/check_flash_budget.sh @@ -1,5 +1,6 @@ #!/usr/bin/env bash -# Fail-closed Uno flash budget for the two minimal v2.4.2 sketches. +# Fail-closed Uno flash budget for the minimal sketches, including the +# SI5351_NO_CLK67 build of the runtime-clock sketch. # Missing CLI, core, compiler, map, or a "Sketch uses" line is a failure. # This measures program bytes. It is not a timing benchmark. set -euo pipefail @@ -66,6 +67,7 @@ gate_log() { build_one() { local name="$1" + local extra="${2:-}" local src="$CI_DIR/flash/sketches/${name}.ino.txt" [[ -f "$src" ]] || fail "missing sketch $src" [[ -n "${BUDGET[$name]:-}" ]] || fail "no budget for $name (refusing to skip)" @@ -73,10 +75,15 @@ build_one() { mkdir -p "$sk" "$OUT/build/$name" cp "$src" "$sk/${name}.ino" local log="$OUT/logs/${name}.log" - if ! "$CLI" compile --fqbn "$FQBN" --library "$ROOT" \ - --build-path "$OUT/build/$name" \ - --build-property "compiler.c.elf.extra_flags=-Wl,-Map,$OUT/build/$name/flash.map" \ - "$sk" > "$log" 2>&1; then + local -a cmd=("$CLI" compile --fqbn "$FQBN" --library "$ROOT" + --build-path "$OUT/build/$name" + --build-property "compiler.c.elf.extra_flags=-Wl,-Map,$OUT/build/$name/flash.map") + # Optional second property, used to pass -DSI5351_NO_CLK67 into si5351.cpp. + # A #define in the .ino does not reach the library translation unit. + if [[ -n "$extra" ]]; then + cmd+=(--build-property "$extra") + fi + if ! "${cmd[@]}" "$sk" > "$log" 2>&1; then fail "$name did not compile (see $log)" fi local elf="$OUT/build/$name/${name}.ino.elf" @@ -100,9 +107,9 @@ build_one() { echo "$name $sketch_bytes ${BUDGET[$name]} $text $data $bss" >> "$OUT/measured.tsv" } -for name in min_const min_runtime; do - build_one "$name" -done +build_one min_const +build_one min_runtime +build_one min_runtime_no_clk67 "compiler.cpp.extra_flags=-DSI5351_NO_CLK67" # Negative control: the same parser must reject an over-budget line and a # real log scored against a 1-byte ceiling. Success of this script requires diff --git a/tests/regression/flash/sketches/min_runtime_no_clk67.ino.txt b/tests/regression/flash/sketches/min_runtime_no_clk67.ino.txt new file mode 100644 index 0000000..acede7c --- /dev/null +++ b/tests/regression/flash/sketches/min_runtime_no_clk67.ino.txt @@ -0,0 +1,19 @@ +#include "si5351.h" +#include "Wire.h" + +Si5351 si5351; + +/* Same program as min_runtime.ino.txt. The flash budget checker compiles + * this sketch with -DSI5351_NO_CLK67 so multisynth67_calc and the CLK6/CLK7 + * branches are left out of si5351.cpp. A #define in this file would not + * reach the library translation unit, so the flag is a build property. + */ +volatile uint8_t clk_index = 0; + +void setup() +{ + si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0); + si5351.set_freq(1400000000ULL, (si5351_clock)clk_index); +} + +void loop() {} From b4a6c3b6321766d1b129a2b47d7152da4e6cf538 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 8 Nov 2026 02:40:55 +0000 Subject: [PATCH 2/3] Share one PLL program path and the inlined init/reset loops set_pll() is now the only copy of pll_calc, the parameter write, and pll_update, including the VCXO parameter bytes. pll_calc uses one feedback division for the normal and VCXO paths, both of which divide by 1000000. init() and reset() walk the two references, both PLLs, and the eight clocks in single loops, and set_correction() is noinline so that sequence is not duplicated when init() is inlined into main. Uno ceilings are now min_const 10202, min_runtime 10930, and the gated runtime sketch 9836. Co-authored-by: Jason Milldrum --- src/si5351.cpp | 187 ++++++++++++----------------- tests/regression/flash/budgets.txt | 24 ++-- 2 files changed, 89 insertions(+), 122 deletions(-) diff --git a/src/si5351.cpp b/src/si5351.cpp index edb74a4..d2c07ec 100644 --- a/src/si5351.cpp +++ b/src/si5351.cpp @@ -199,22 +199,21 @@ bool Si5351::init(uint8_t xtal_load_c, uint32_t xo_freq, int32_t corr) } si5351_write(SI5351_CRYSTAL_LOAD, xtal_load_c | 0b00010010); - // Set up the XO and CLKIN reference frequencies - if (xo_freq != 0) + // Set up the XO and CLKIN reference frequencies, then the + // calibrations. Both references are stored before either + // correction replans a PLL. One loop so this stays a single + // copy when init() is inlined into main. + uint32_t ref = xo_freq != 0 ? xo_freq : (uint32_t)SI5351_XTAL_FREQ; + uint8_t r; + for(r = 0; r < 2; r++) { - set_ref_freq(xo_freq, SI5351_PLL_INPUT_XO); - set_ref_freq(xo_freq, SI5351_PLL_INPUT_CLKIN); //Also CLKIN + set_ref_freq(ref, (enum si5351_pll_input)r); } - else + for(r = 0; r < 2; r++) { - set_ref_freq(SI5351_XTAL_FREQ, SI5351_PLL_INPUT_XO); - set_ref_freq(SI5351_XTAL_FREQ, SI5351_PLL_INPUT_CLKIN); //Also CLKIN + set_correction(corr, (enum si5351_pll_input)r); } - // Set the frequency calibrations for the XO and CLKIN - set_correction(corr, SI5351_PLL_INPUT_XO); - set_correction(corr, SI5351_PLL_INPUT_CLKIN); - reset(); return true; @@ -239,34 +238,30 @@ void Si5351::reset(void) // VCXO is cleared below vcxo_pull = 0; - // Initialize the CLK outputs according to flowchart in datasheet - // First, turn them off (and forget them, so set_pll() below does not - // recalculate their dividers) + // Initialize the CLK outputs according to flowchart in datasheet. + // First turn them off (and forget them, so set_pll() below does not + // recalculate their dividers), then turn them back on. for(i = 0; i < 8; i++) { clk_freq[i] = 0; si5351_write(SI5351_CLK0_CTRL + i, 0x80); } - - // Turn the clocks back on... for(i = 0; i < 8; i++) { si5351_write(SI5351_CLK0_CTRL + i, 0x0c); } // Set PLLA and PLLB to 800 MHz for automatic tuning - set_pll(SI5351_PLL_FIXED, SI5351_PLLA); - set_pll(SI5351_PLL_FIXED, SI5351_PLLB); - - // Make PLL to CLK assignments for automatic tuning - // set_ms_source also updates pll_assignment[] - for(i = 0; i < 6; i++) + for(i = 0; i < 2; i++) { - set_ms_source((enum si5351_clock)i, SI5351_PLLA); + set_pll(SI5351_PLL_FIXED, (enum si5351_pll)i); } - for(i = 6; i < 8; i++) + + // Make PLL to CLK assignments for automatic tuning. + // CLK0-5 on PLLA, CLK6-7 on PLLB. set_ms_source updates pll_assignment[]. + for(i = 0; i < 8; i++) { - set_ms_source((enum si5351_clock)i, SI5351_PLLB); + set_ms_source((enum si5351_clock)i, (i < 6) ? SI5351_PLLA : SI5351_PLLB); } // Turn off spread spectrum (SSC_EN, reg 149 bit 7). Some chips power up @@ -275,14 +270,17 @@ void Si5351::reset(void) uint8_t ssc = si5351_read(SI5351_SSC_PARAM0); si5351_write(SI5351_SSC_PARAM0, ssc & ~SI5351_SSC_EN); - // Reset the VCXO param - si5351_write(SI5351_VXCO_PARAMETERS_LOW, 0); - si5351_write(SI5351_VXCO_PARAMETERS_MID, 0); - si5351_write(SI5351_VXCO_PARAMETERS_HIGH, 0); + // Reset the VCXO param (registers 162..164) + for(i = 0; i < 3; i++) + { + si5351_write(SI5351_VXCO_PARAMETERS_LOW + i, 0); + } // Then reset the PLLs - pll_reset(SI5351_PLLA); - pll_reset(SI5351_PLLB); + for(i = 0; i < 2; i++) + { + pll_reset((enum si5351_pll)i); + } // Set initial frequencies for(i = 0; i < 8; i++) @@ -704,27 +702,18 @@ void Si5351::set_pll(uint64_t pll_freq, enum si5351_pll target_pll) { struct Si5351RegSet pll_reg; uint8_t params[SI5351_PARAMETERS_LENGTH]; + // PLLB keeps c = 10^6 while the VCXO is in use (AN619 sec. 3.2, 7). + // set_vcxo() stores the pull range and calls back here, so this path + // is the only copy of pll_calc / pack / write / pll_update. + uint8_t vcxo = (target_pll == SI5351_PLLB && vcxo_pull) ? 1 : 0; + enum si5351_pll_input ref = (target_pll == SI5351_PLLA) ? plla_ref_osc : pllb_ref_osc; - // While the VCXO is in use, PLLB must keep c = 10^6 (AN619 sec. 3.2, 7) - if(target_pll == SI5351_PLLB && vcxo_pull) + if(!ref_ok(xtal_freq[(uint8_t)ref])) { - set_vcxo(pll_freq, vcxo_pull); return; } - if(!ref_ok(xtal_freq[(uint8_t)((target_pll == SI5351_PLLA) ? plla_ref_osc : pllb_ref_osc)])) - { - return; - } - - if(target_pll == SI5351_PLLA) - { - pll_calc(SI5351_PLLA, pll_freq, &pll_reg, ref_correction[plla_ref_osc], 0); - } - else - { - pll_calc(SI5351_PLLB, pll_freq, &pll_reg, ref_correction[pllb_ref_osc], 0); - } + uint64_t vcxo_param = pll_calc(target_pll, pll_freq, &pll_reg, ref_correction[ref], vcxo); // Derive the register values to write pack_reg_set(&pll_reg, params, 0); @@ -732,6 +721,22 @@ void Si5351::set_pll(uint64_t pll_freq, enum si5351_pll target_pll) // Write the parameters si5351_write_bulk((target_pll == SI5351_PLLA) ? SI5351_PLLA_PARAMETERS : SI5351_PLLB_PARAMETERS, SI5351_PARAMETERS_LENGTH, params); + + if(vcxo) + { + uint8_t temp; + uint8_t ppm = vcxo_pull; + + vcxo_param = ((vcxo_param * ppm * SI5351_VCXO_MARGIN) / 100ULL) / 1000000ULL; + + temp = (uint8_t)(vcxo_param & 0xFF); + si5351_write(SI5351_VXCO_PARAMETERS_LOW, temp); + temp = (uint8_t)((vcxo_param >> 8) & 0xFF); + si5351_write(SI5351_VXCO_PARAMETERS_MID, temp); + temp = (uint8_t)((vcxo_param >> 16) & 0x3F); + si5351_write(SI5351_VXCO_PARAMETERS_HIGH, temp); + } + pll_update(target_pll, pll_freq); } @@ -975,13 +980,19 @@ void Si5351::update_status(void) * should not have to be done again for the same Si5351 and * crystal. */ +__attribute__((noinline)) void Si5351::set_correction(int32_t corr, enum si5351_pll_input ref_osc) { + uint8_t p; + ref_correction[(uint8_t)ref_osc] = corr; - // Recalculate and set PLL freqs based on correction value - set_pll(plla_freq, SI5351_PLLA); - set_pll(pllb_freq, SI5351_PLLB); + // Recalculate and set PLL freqs based on correction value. + // PLLA then PLLB, same order as the two direct calls. + for(p = 0; p < 2; p++) + { + set_pll(p ? pllb_freq : plla_freq, (enum si5351_pll)p); + } } /* @@ -1389,9 +1400,6 @@ void Si5351::set_pll_input(enum si5351_pll pll, enum si5351_pll_input input) */ void Si5351::set_vcxo(uint64_t pll_freq, uint8_t ppm) { - struct Si5351RegSet pll_reg; - uint64_t vcxo_param; - // Bounds check if(ppm < SI5351_VCXO_PULL_MIN) { @@ -1408,34 +1416,10 @@ void Si5351::set_vcxo(uint64_t pll_freq, uint8_t ppm) return; } - // Remember the VCXO setting so later PLLB updates keep c = 10^6 + // Remember the VCXO setting so later PLLB updates keep c = 10^6. + // set_pll() writes the PLL and the VCXO parameter registers. vcxo_pull = ppm; - - // Set PLLB params - vcxo_param = pll_calc(SI5351_PLLB, pll_freq, &pll_reg, ref_correction[pllb_ref_osc], 1); - - // Derive the register values to write - uint8_t params[SI5351_PARAMETERS_LENGTH]; - uint8_t temp; - - pack_reg_set(&pll_reg, params, 0); - - // Write the parameters - si5351_write_bulk(SI5351_PLLB_PARAMETERS, SI5351_PARAMETERS_LENGTH, params); - - // Write the VCXO parameters - vcxo_param = ((vcxo_param * ppm * SI5351_VCXO_MARGIN) / 100ULL) / 1000000ULL; - - temp = (uint8_t)(vcxo_param & 0xFF); - si5351_write(SI5351_VXCO_PARAMETERS_LOW, temp); - - temp = (uint8_t)((vcxo_param >> 8) & 0xFF); - si5351_write(SI5351_VXCO_PARAMETERS_MID, temp); - - temp = (uint8_t)((vcxo_param >> 16) & 0x3F); - si5351_write(SI5351_VXCO_PARAMETERS_HIGH, temp); - - pll_update(SI5351_PLLB, pll_freq); + set_pll(pll_freq, SI5351_PLLB); } /* @@ -1566,15 +1550,10 @@ uint8_t Si5351::get_i2c_error(void) uint64_t Si5351::pll_calc(enum si5351_pll pll, uint64_t freq, struct Si5351RegSet *reg, int32_t correction, uint8_t vcxo) { - uint64_t ref_freq; - if(pll == SI5351_PLLA) - { - ref_freq = xtal_freq[(uint8_t)plla_ref_osc] * SI5351_FREQ_MULT; - } - else - { - ref_freq = xtal_freq[(uint8_t)pllb_ref_osc] * SI5351_FREQ_MULT; - } + // One reference selection for both PLLs. The two arms used to each carry + // their own copy of the feedback math once this function was inlined. + enum si5351_pll_input ref_osc = (pll == SI5351_PLLA) ? plla_ref_osc : pllb_ref_osc; + uint64_t ref_freq = xtal_freq[(uint8_t)ref_osc] * SI5351_FREQ_MULT; //ref_freq = 15974400ULL * SI5351_FREQ_MULT; uint32_t a, b, c; uint64_t lltmp; //, denom; @@ -1608,42 +1587,34 @@ uint64_t Si5351::pll_calc(enum si5351_pll pll, uint64_t freq, struct Si5351RegSe freq = ref_freq * SI5351_PLL_A_MAX; } - // Find best approximation for b/c = fVCO mod fIN - // denom = 1000ULL * 1000ULL; - // lltmp = freq % ref_freq; - // lltmp *= denom; - // do_div(lltmp, ref_freq); - - //b = (((uint64_t)(freq % ref_freq)) * RFRAC_DENOM) / ref_freq; + // Find best approximation for b/c = fVCO mod fIN. + // RFRAC_DENOM is 1000000, the same denominator set_vcxo() needs so + // PLLB keeps c = 10^6 (AN619 sec. 3.2). One division serves both. + b = (((uint64_t)(freq % ref_freq)) * RFRAC_DENOM) / ref_freq; if(vcxo) { - b = (((uint64_t)(freq % ref_freq)) * 1000000ULL) / ref_freq; - c = 1000000ULL; + c = RFRAC_DENOM; } else { - b = (((uint64_t)(freq % ref_freq)) * RFRAC_DENOM) / ref_freq; c = b ? RFRAC_DENOM : 1; } // Calculate parameters frac_to_reg(a, b, c, reg); + if(vcxo) + { + return (uint64_t)(128 * a * RFRAC_DENOM + b); + } + // Recalculate frequency as fIN * (a + b/c) lltmp = ref_freq; lltmp *= b; do_div(lltmp, c); freq = lltmp; freq += ref_freq * a; - - if(vcxo) - { - return (uint64_t)(128 * a * 1000000ULL + b); - } - else - { - return freq; - } + return freq; } uint64_t Si5351::multisynth_calc(uint64_t freq, uint64_t pll_freq, struct Si5351RegSet *reg) diff --git a/tests/regression/flash/budgets.txt b/tests/regression/flash/budgets.txt index b7a172f..96965d9 100644 --- a/tests/regression/flash/budgets.txt +++ b/tests/regression/flash/budgets.txt @@ -12,17 +12,13 @@ # Size method: arduino-cli "Sketch uses N bytes", which is avr-size text+data. # The checker also requires avr-size text+data == N. A parse miss is a FAIL. # -# Both numbers below are baselines of the fixtures in sketches/. The audit -# runtime-clock sketch was not saved (REPORT only, no .ino), so its reported -# 12604 bytes cannot be compared with min_runtime and is not a target. -# min_const measures 10830 on this pin. The audit reported 10830 for a sketch -# described the same way; that .ino was not saved either, so 10830 is this -# fixture's measurement. -# min_runtime is a new fixture: global volatile uint8_t clock index, constant -# 14 MHz. Its own baseline on this pin is 11558. -# min_runtime_no_clk67 is that same program compiled with -DSI5351_NO_CLK67 -# (compiler.cpp.extra_flags). Measured 10442 on this pin. min_const and -# min_runtime stay at the ungated sizes: the macro is opt-in. -min_const 10830 -min_runtime 11558 -min_runtime_no_clk67 10442 +# v2.4.2 baselines on this pin: min_const 10830, min_runtime 11558. +# The audit runtime-clock sketch was not saved (REPORT only, no .ino), so its +# reported 12604 bytes cannot be compared with min_runtime and is not a target. +# min_runtime is a global volatile uint8_t clock index and a constant 14 MHz. +# min_runtime_no_clk67 is that program compiled with -DSI5351_NO_CLK67. +# Ceilings below are the sizes after the PLL and init/reset merge, so a +# later edit cannot grow back to the v2.4.2 baseline. +min_const 10202 +min_runtime 10930 +min_runtime_no_clk67 9836 From e7dfd34f4af668ac32acbd9562a769969a58c89f Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 7 Nov 2026 21:45:38 -0800 Subject: [PATCH 3/3] Let a sketch #define SI5351_NO_CLK67 leave out the CLK6/7 code Arduino IDE users cannot pass per-sketch compiler flags, and a #define in the sketch did not reach si5351.cpp. The CLK6/7-only code now lives in weak member functions (set_freq67, ms67_div, set_ms67). When a sketch defines SI5351_NO_CLK67 before #include , the header adds stubs that replace them, and the linker drops the originals. The compiler-flag opt-out still works. No public API or constructor change. Opt-out behavior is identical to the compiler-flag build (native harness, 1386 runs, byte-identical transcripts). Default builds keep 0 differing runs vs v2.4.2 and get 62 bytes smaller on the Uno (CLK6/7 R-divider handling moved out of ms_div). Uno flash (arduino-cli 1.5.1, arduino:avr 1.8.6): min_runtime 10868 default, 9870 with the sketch #define, 9836 with the flag. Adds a min_runtime_sketch_no_clk67 budget (9870) that fails at 10930 when the define is ignored, tightens min_const/min_runtime to 10140/10868, and documents the opt-out in the README. --- README.md | 22 +- src/si5351.cpp | 242 +++++++++--------- src/si5351.h | 25 +- tests/regression/README.md | 2 +- tests/regression/flash/budgets.txt | 7 +- tests/regression/flash/check_flash_budget.sh | 2 + .../sketches/min_runtime_no_clk67.ino.txt | 4 +- .../min_runtime_sketch_no_clk67.ino.txt | 23 ++ .../__pycache__/si5351_math.cpython-313.pyc | Bin 0 -> 55580 bytes .../spec_crosscheck.cpython-313.pyc | Bin 0 -> 35317 bytes .../__pycache__/spec_oracle.cpython-313.pyc | Bin 0 -> 15579 bytes 11 files changed, 191 insertions(+), 136 deletions(-) create mode 100644 tests/regression/flash/sketches/min_runtime_sketch_no_clk67.ino.txt create mode 100644 tests/regression/python/__pycache__/si5351_math.cpython-313.pyc create mode 100644 tests/regression/python/__pycache__/spec_crosscheck.cpython-313.pyc create mode 100644 tests/regression/python/__pycache__/spec_oracle.cpython-313.pyc diff --git a/README.md b/README.md index ed46ecc..9663e02 100644 --- a/README.md +++ b/README.md @@ -296,13 +296,31 @@ Constraints Leaving out CLK6 and CLK7 ------------------------- -CLK6 and CLK7 use a separate even-integer planner (`multisynth67_calc`, `ms67_div`, and the CLK6/CLK7 branches in `set_freq()`, `set_freq_manual()`, `set_ms()`, `pll_update()`, and `ms_div()`). Define `SI5351_NO_CLK67` when the library is compiled to leave that code out. The public methods and the `si5351_clock` enumerators stay. With the macro defined, `set_freq()` and `set_freq_manual()` return 1 for CLK6 and CLK7 and do not write those multisynths. `reset()` still initializes all eight clock-control registers. Without the macro, behavior is unchanged. +If your sketch never uses CLK6 or CLK7, you can leave their code out and save about 1 KB of flash on an AVR board. In the Arduino IDE, put the define above the include in your sketch's .ino file: -A `#define` in a sketch is not visible to `si5351.cpp`. Pass the macro as a compiler definition so every translation unit that builds the library sees it: +```cpp +#define SI5351_NO_CLK67 +#include +``` + +Put it in the .ino file only. If more than one file in the sketch defines it before including `si5351.h`, the link fails with a duplicate definition. The define has to come before the `#include`. + +With the opt-out, `set_freq()` and `set_freq_manual()` return 1 for CLK6 and CLK7 and write nothing, and `set_ms()` writes nothing for CLK6 and CLK7. The public methods and the `si5351_clock` enumerators stay, and `reset()` still initializes all eight clock-control registers. Without the define, behavior is unchanged. + +How it works: the CLK6/CLK7 functions in `si5351.cpp` are weak symbols. The sketch define makes `si5351.h` add small stubs that replace them, and the linker drops the originals. This needs a GCC or Clang toolchain, which every common Arduino core uses. + +You can also pass the macro as a compiler definition. This leaves the code out when `si5351.cpp` is compiled: * Arduino CLI: `--build-property compiler.cpp.extra_flags=-DSI5351_NO_CLK67` * PlatformIO: `build_flags = -DSI5351_NO_CLK67` +Measured flash on an Arduino Uno (arduino-cli 1.5.1, arduino:avr 1.8.6), in bytes: + +| Sketch | Default | Sketch `#define` | Compiler flag | +|---|---|---|---| +| `init()` + one `set_freq()`, runtime clock index | 10,868 | 9,870 | 9,836 | +| `init()` + one `set_freq()` on CLK0 | 10,140 | 9,778 | 9,740 | + Frequency Limits ---------------- Numbers below are what v2.4.1 programs, checked against `src/si5351.cpp`, `src/si5351.h`, AN619 rev. 0.8, and the Si5351A/B/C-B datasheet rev. 1.3. Frequencies passed to `set_freq()` are in units of 0.01 Hz. diff --git a/src/si5351.cpp b/src/si5351.cpp index d2c07ec..6e748ac 100644 --- a/src/si5351.cpp +++ b/src/si5351.cpp @@ -26,6 +26,7 @@ #include "Arduino.h" #include "Wire.h" +#define SI5351_LIBRARY_SOURCE #include "si5351.h" @@ -63,7 +64,7 @@ static uint8_t recalc_force; // sets *r_div, or returns 0 if no valid ratio/R pair exists. // Left out of the build when SI5351_NO_CLK67 is defined (see the README). #ifndef SI5351_NO_CLK67 -static uint8_t ms67_div(uint64_t pll_freq, uint64_t freq, uint8_t *r_div) +SI5351_CLK67_WEAK uint8_t Si5351::ms67_div(uint64_t pll_freq, uint64_t freq, uint8_t *r_div) { uint64_t n; uint8_t r; @@ -489,97 +490,107 @@ uint8_t Si5351::set_freq(uint64_t freq, enum si5351_clock clk) } else { + return set_freq67(freq, clk); + } +} + #ifndef SI5351_NO_CLK67 - // MS6 and MS7 logic - // ----------------- - uint8_t peer = (clk == SI5351_CLK6) ? (uint8_t)SI5351_CLK7 : (uint8_t)SI5351_CLK6; +// set_freq() for CLK6/CLK7. Weak: a sketch that defines SI5351_NO_CLK67 +// before #include replaces it with a stub (see si5351.h). +SI5351_CLK67_WEAK uint8_t Si5351::set_freq67(uint64_t freq, enum si5351_clock clk) +{ + struct Si5351RegSet ms_reg; + uint64_t pll_freq; + uint8_t int_mode = 0; + uint8_t div_by_4 = 0; + uint8_t r_div = 0; - // There is no valid MS6/7 setting for 0 Hz - if(freq == 0) - { - return 1; - } + // MS6 and MS7 logic + // ----------------- + uint8_t peer = (clk == SI5351_CLK6) ? (uint8_t)SI5351_CLK7 : (uint8_t)SI5351_CLK6; - // Lower bounds check (lowest valid MS6/7 ratio, VCO and R combination) - if(freq < SI5351_CLKOUT67_MIN) - { - freq = SI5351_CLKOUT67_MIN; - } + // There is no valid MS6/7 setting for 0 Hz + if(freq == 0) + { + return 1; + } - // Upper bounds check - if(freq >= SI5351_MULTISYNTH_DIVBY4_FREQ * SI5351_FREQ_MULT) - { - freq = SI5351_MULTISYNTH_DIVBY4_FREQ * SI5351_FREQ_MULT - 1; - } + // Lower bounds check (lowest valid MS6/7 ratio, VCO and R combination) + if(freq < SI5351_CLKOUT67_MIN) + { + freq = SI5351_CLKOUT67_MIN; + } - // If one of CLK6 or CLK7 is already set when trying to set the other, - // we have to ensure that it will also have an even integer division - // ratio (6..254, using the R divider if needed) with the same PLL, - // otherwise do not set it. - if(clk_freq[peer] != 0) - { - ms_reg.p1 = ms67_div(pllb_freq, freq, &r_div); - if(ms_reg.p1 == 0) - { - return 1; - } - ms_reg.p2 = 0; - ms_reg.p3 = 0; + // Upper bounds check + if(freq >= SI5351_MULTISYNTH_DIVBY4_FREQ * SI5351_FREQ_MULT) + { + freq = SI5351_MULTISYNTH_DIVBY4_FREQ * SI5351_FREQ_MULT - 1; + } - // Set the freq in memory - clk_freq[(uint8_t)clk] = freq; - } - else + // If one of CLK6 or CLK7 is already set when trying to set the other, + // we have to ensure that it will also have an even integer division + // ratio (6..254, using the R divider if needed) with the same PLL, + // otherwise do not set it. + if(clk_freq[peer] != 0) + { + ms_reg.p1 = ms67_div(pllb_freq, freq, &r_div); + if(ms_reg.p1 == 0) { - // No previous assignment, so set PLLB based on this clock - - // Set the freq in memory - clk_freq[(uint8_t)clk] = freq; + return 1; + } + ms_reg.p2 = 0; + ms_reg.p3 = 0; - // Smallest R divider that keeps the MS6/7 ratio <= 254 - while(freq < SI5351_MS67_MIN_FREQ && r_div < SI5351_OUTPUT_CLK_DIV_128) - { - freq <<= 1; - r_div++; - } + // Set the freq in memory + clk_freq[(uint8_t)clk] = freq; + } + else + { + // No previous assignment, so set PLLB based on this clock - pll_freq = multisynth67_calc(freq, 0, &ms_reg); - // Preserve original asymmetry: CLK6 hardcodes PLLB; CLK7 uses assignment - recalc_skip = clk; - defer_pll_reset = 1; - set_pll(pll_freq, (clk == SI5351_CLK6) ? SI5351_PLLB : pll_assignment[clk]); - recalc_skip = 0xFF; - } + // Set the freq in memory + clk_freq[(uint8_t)clk] = freq; - // Enable the output on first set_freq only, as for CLK0-5 (DEV-14). - // reset() already powers up CLK6/7 (reg 22/23 = 0x0C). - if(clk_first_set[(uint8_t)clk] == false) + // Smallest R divider that keeps the MS6/7 ratio <= 254 + while(freq < SI5351_MS67_MIN_FREQ && r_div < SI5351_OUTPUT_CLK_DIV_128) { - output_enable(clk, 1); - clk_first_set[(uint8_t)clk] = true; + freq <<= 1; + r_div++; } - div_by_4 = 0; - int_mode = 0; + pll_freq = multisynth67_calc(freq, 0, &ms_reg); + // Preserve original asymmetry: CLK6 hardcodes PLLB; CLK7 uses assignment + recalc_skip = clk; + defer_pll_reset = 1; + set_pll(pll_freq, (clk == SI5351_CLK6) ? SI5351_PLLB : pll_assignment[clk]); + recalc_skip = 0xFF; + } - // Set multisynth registers (MS must be set before PLL) - set_ms(clk, ms_reg, int_mode, r_div, div_by_4); + // Enable the output on first set_freq only, as for CLK0-5 (DEV-14). + // reset() already powers up CLK6/7 (reg 22/23 = 0x0C). + if(clk_first_set[(uint8_t)clk] == false) + { + output_enable(clk, 1); + clk_first_set[(uint8_t)clk] = true; + } - // One reset, after all PLL and MS writes, if the recalc owes one - defer_pll_reset = 0; - if(reset_owed) - { - reset_owed = 0; - pll_reset(pll_assignment[clk]); - } + div_by_4 = 0; + int_mode = 0; - return 0; -#else - // CLK6/CLK7 planner is compiled out. Do not write. - return 1; -#endif + // Set multisynth registers (MS must be set before PLL) + set_ms(clk, ms_reg, int_mode, r_div, div_by_4); + + // One reset, after all PLL and MS writes, if the recalc owes one + defer_pll_reset = 0; + if(reset_owed) + { + reset_owed = 0; + pll_reset(pll_assignment[clk]); } + + return 0; } +#endif /* * set_freq_manual(uint64_t freq, uint64_t pll_freq, enum si5351_clock clk) @@ -852,19 +863,35 @@ void Si5351::set_ms(enum si5351_clock clk, struct Si5351RegSet ms_reg, uint8_t i pll_reset(pll_assignment[clk]); } } -#ifndef SI5351_NO_CLK67 else if((uint8_t)clk <= (uint8_t)SI5351_CLK7) { - // MS6 and MS7 only use one register (90 / 91). // Bounded to CLK7 so an out-of-range clk writes nothing, as the // original switch() did (otherwise clk=8 would clobber reg 92). - si5351_write(SI5351_CLK6_PARAMETERS + ((uint8_t)clk - (uint8_t)SI5351_CLK6), - (uint8_t)ms_reg.p1); - ms_div(clk, r_div, div_by_4); + set_ms67(clk, (uint8_t)ms_reg.p1, r_div); } -#endif } +#ifndef SI5351_NO_CLK67 +// set_ms() for CLK6/CLK7. Weak, like set_freq67(). +SI5351_CLK67_WEAK void Si5351::set_ms67(enum si5351_clock clk, uint8_t p1, uint8_t r_div) +{ + // MS6 and MS7 only use one register (90 / 91). + si5351_write(SI5351_CLK6_PARAMETERS + ((uint8_t)clk - (uint8_t)SI5351_CLK6), p1); + + // R6_DIV is register 92 bits 2:0, R7_DIV bits 6:4 + uint8_t reg_val = si5351_read(SI5351_CLK6_7_OUTPUT_DIVIDER); + if(clk == SI5351_CLK6) + { + reg_val = (reg_val & ~(0x07)) | r_div; + } + else + { + reg_val = (reg_val & ~(0x70)) | (r_div << SI5351_OUTPUT_CLK_DIV_SHIFT); + } + si5351_write(SI5351_CLK6_7_OUTPUT_DIVIDER, reg_val); +} +#endif + /* * output_enable(enum si5351_clock clk, uint8_t enable) * @@ -1837,57 +1864,24 @@ void Si5351::update_int_status(struct Si5351IntStatus *int_status) void Si5351::ms_div(enum si5351_clock clk, uint8_t r_div, uint8_t div_by_4) { - uint8_t reg_val = 0; - uint8_t reg_addr = 0; - - if((uint8_t)clk <= (uint8_t)SI5351_CLK5) - { - // CLK0..CLK5: parameter byte 2 is linear with clk - reg_addr = SI5351_CLK0_PARAMETERS + 2 + ((uint8_t)clk * 8); - } - else - { -#ifndef SI5351_NO_CLK67 - reg_addr = SI5351_CLK6_7_OUTPUT_DIVIDER; -#else - return; -#endif - } + // CLK0..CLK5 only (CLK6/7 are in set_ms67()): parameter byte 2 is + // linear with clk + uint8_t reg_addr = SI5351_CLK0_PARAMETERS + 2 + ((uint8_t)clk * 8); + uint8_t reg_val = si5351_read(reg_addr); - reg_val = si5351_read(reg_addr); + // Clear the relevant bits + reg_val &= ~(0x7c); - if((uint8_t)clk <= (uint8_t)SI5351_CLK5) + if(div_by_4 == 0) { - // Clear the relevant bits - reg_val &= ~(0x7c); - - if(div_by_4 == 0) - { - reg_val &= ~(SI5351_OUTPUT_CLK_DIVBY4); - } - else - { - reg_val |= (SI5351_OUTPUT_CLK_DIVBY4); - } - - reg_val |= (r_div << SI5351_OUTPUT_CLK_DIV_SHIFT); + reg_val &= ~(SI5351_OUTPUT_CLK_DIVBY4); } -#ifndef SI5351_NO_CLK67 - else if(clk == SI5351_CLK6) + else { - // Clear the relevant bits - reg_val &= ~(0x07); - - reg_val |= r_div; + reg_val |= (SI5351_OUTPUT_CLK_DIVBY4); } - else if(clk == SI5351_CLK7) - { - // Clear the relevant bits - reg_val &= ~(0x70); - reg_val |= (r_div << SI5351_OUTPUT_CLK_DIV_SHIFT); - } -#endif + reg_val |= (r_div << SI5351_OUTPUT_CLK_DIV_SHIFT); si5351_write(reg_addr, reg_val); } diff --git a/src/si5351.h b/src/si5351.h index 239271a..d809350 100644 --- a/src/si5351.h +++ b/src/si5351.h @@ -355,12 +355,11 @@ class Si5351 void pll_update(enum si5351_pll, uint64_t); uint64_t pll_calc(enum si5351_pll, uint64_t, struct Si5351RegSet *, int32_t, uint8_t); uint64_t multisynth_calc(uint64_t, uint64_t, struct Si5351RegSet *); - /* Omitted when SI5351_NO_CLK67 is defined. See the README. The macro has - * to be a compiler definition; a #define in a sketch does not reach - * si5351.cpp. Without it, this declaration is always present. */ -#ifndef SI5351_NO_CLK67 + // CLK6/CLK7 code. See SI5351_NO_CLK67 at the end of this file. uint64_t multisynth67_calc(uint64_t, uint64_t, struct Si5351RegSet *); -#endif + uint8_t set_freq67(uint64_t, enum si5351_clock); + static uint8_t ms67_div(uint64_t, uint64_t, uint8_t *); + void set_ms67(enum si5351_clock, uint8_t, uint8_t); void update_sys_status(struct Si5351Status *); void update_int_status(struct Si5351IntStatus *); void ms_div(enum si5351_clock, uint8_t, uint8_t); @@ -374,4 +373,20 @@ class Si5351 uint8_t vcxo_pull; }; +/* Leaving out the CLK6/CLK7 code (about 1 KB of flash on an Uno). + * Put this at the top of the sketch, in one file only (the .ino): + * #define SI5351_NO_CLK67 + * #include + * or pass -DSI5351_NO_CLK67 to the compiler. set_freq() and + * set_freq_manual() on CLK6/CLK7 then return 1 and write nothing, and + * set_ms() on CLK6/CLK7 writes nothing. + * The library's CLK6/CLK7 functions are weak; the stubs below replace + * them, and the linker drops the originals. */ +#define SI5351_CLK67_WEAK __attribute__((weak)) +#if defined(SI5351_NO_CLK67) && !defined(SI5351_LIBRARY_SOURCE) +uint8_t Si5351::set_freq67(uint64_t, enum si5351_clock) { return 1; } +uint8_t Si5351::ms67_div(uint64_t, uint64_t, uint8_t *) { return 0; } +void Si5351::set_ms67(enum si5351_clock, uint8_t, uint8_t) {} +#endif + #endif /* SI5351_H_ */ diff --git a/tests/regression/README.md b/tests/regression/README.md index d4f3389..5dd4298 100644 --- a/tests/regression/README.md +++ b/tests/regression/README.md @@ -53,6 +53,6 @@ Exit code: 0 = every check PASS/XFAIL/SKIP/INFO; 1 = at least one unexpected FAI ## Layout `v231/` acceptance runner, scenarios, oracle, locks, and reports · `stubs/` Arduino/Wire host stubs · `issue106/` t106 and its multi-bus stubs · `reset_freq/` `reset_freq()` regression · `equiv/` harness, goldens snapshot, compare.py · `reference/v242_f885fca/` pinned v2.4.2 source (the hard gate) · `reference/master_1ddd43e/` historical source, not the gate · -`ctrl/` `plan/` branch locks · `flash/check_flash_budget.sh` Uno byte ceilings, including the `SI5351_NO_CLK67` sketch (separate CI workflow) · `python/` golden/spec suites and refs · +`ctrl/` `plan/` branch locks · `flash/check_flash_budget.sh` Uno byte ceilings, including the `SI5351_NO_CLK67` compiler-flag and sketch-#define builds (separate CI workflow) · `python/` golden/spec suites and refs · `sketches/` Ctor106 · `boards.txt` board set and Boards Manager URLs · `tools/summarize.py`. `v231/Makefile` is the original manual build, kept for reference only; the script does not use it. diff --git a/tests/regression/flash/budgets.txt b/tests/regression/flash/budgets.txt index 96965d9..4a41930 100644 --- a/tests/regression/flash/budgets.txt +++ b/tests/regression/flash/budgets.txt @@ -19,6 +19,9 @@ # min_runtime_no_clk67 is that program compiled with -DSI5351_NO_CLK67. # Ceilings below are the sizes after the PLL and init/reset merge, so a # later edit cannot grow back to the v2.4.2 baseline. -min_const 10202 -min_runtime 10930 +min_const 10140 +min_runtime 10868 min_runtime_no_clk67 9836 +# min_runtime_sketch_no_clk67: same program with #define SI5351_NO_CLK67 in the +# sketch (no compiler flag). A library that ignores the define builds 10930. +min_runtime_sketch_no_clk67 9870 diff --git a/tests/regression/flash/check_flash_budget.sh b/tests/regression/flash/check_flash_budget.sh index b22a210..5a21509 100755 --- a/tests/regression/flash/check_flash_budget.sh +++ b/tests/regression/flash/check_flash_budget.sh @@ -110,6 +110,8 @@ build_one() { build_one min_const build_one min_runtime build_one min_runtime_no_clk67 "compiler.cpp.extra_flags=-DSI5351_NO_CLK67" +# Sketch-side opt-out: the #define is in the .ino, no compiler flag. +build_one min_runtime_sketch_no_clk67 # Negative control: the same parser must reject an over-budget line and a # real log scored against a 1-byte ceiling. Success of this script requires diff --git a/tests/regression/flash/sketches/min_runtime_no_clk67.ino.txt b/tests/regression/flash/sketches/min_runtime_no_clk67.ino.txt index acede7c..ea97063 100644 --- a/tests/regression/flash/sketches/min_runtime_no_clk67.ino.txt +++ b/tests/regression/flash/sketches/min_runtime_no_clk67.ino.txt @@ -5,8 +5,8 @@ Si5351 si5351; /* Same program as min_runtime.ino.txt. The flash budget checker compiles * this sketch with -DSI5351_NO_CLK67 so multisynth67_calc and the CLK6/CLK7 - * branches are left out of si5351.cpp. A #define in this file would not - * reach the library translation unit, so the flag is a build property. + * branches are left out of si5351.cpp. This covers the compiler-flag + * opt-out; min_runtime_sketch_no_clk67 covers the #define-in-sketch one. */ volatile uint8_t clk_index = 0; diff --git a/tests/regression/flash/sketches/min_runtime_sketch_no_clk67.ino.txt b/tests/regression/flash/sketches/min_runtime_sketch_no_clk67.ino.txt new file mode 100644 index 0000000..81b5ec1 --- /dev/null +++ b/tests/regression/flash/sketches/min_runtime_sketch_no_clk67.ino.txt @@ -0,0 +1,23 @@ +/* min_runtime.ino.txt with the sketch-side opt-out: SI5351_NO_CLK67 is + * defined here, before the include, and NOT passed to the compiler. The + * weak CLK6/CLK7 functions are replaced by the header's stubs. */ +#define SI5351_NO_CLK67 +#include "si5351.h" +#include "Wire.h" + +Si5351 si5351; + +/* New flash fixture, not a reconstruction of the audit runtime sketch. + * That sketch was not saved (REPORT only). This file is the budget's program: + * a global volatile uint8_t index and a constant 14 MHz. The gate ceiling is + * the size of this file on the pinned Uno toolchain. + */ +volatile uint8_t clk_index = 0; + +void setup() +{ + si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0); + si5351.set_freq(1400000000ULL, (si5351_clock)clk_index); +} + +void loop() {} diff --git a/tests/regression/python/__pycache__/si5351_math.cpython-313.pyc b/tests/regression/python/__pycache__/si5351_math.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..afde029edf55b472e7120da7345b457bca74517e GIT binary patch literal 55580 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 literal 0 HcmV?d00001