Skip to content

feat: left-aligned ADC and circular channel list (#121) - #127

Merged
FredM67 merged 30 commits into
devfrom
121-suggestions-1-2
Sep 21, 2026
Merged

FredM67 merged 30 commits into
devfrom
121-suggestions-1-2

Conversation

@FredM67

@FredM67 FredM67 commented Oct 16, 2025 •

Copy link
Copy Markdown
Owner

Pull request

Proposed changes

Implements both suggestions from #121 (thanks @florentbr).

1 — Circular linked list for ADC channel selection

The ISR's switch over the six channels is replaced by a static circular list of
adc_ctx_t { next, index, admux }. Each entry carries the ADMUX value for the
following channel, so the ISR just follows the pointer and writes ADMUX — no
dispatch, no bounds check.

2 — Left-aligned ADC conversion (ADLAR = 1)

  • ADMUX sets ADLAR, so raw samples arrive at ×64 scale (10 bits, left-aligned
    in 16). Rounding is a plain rawSample | 32U.
  • The DC-offset filter becomes a Q17.15 free-running integrator: processVoltage()
    adds every i_sampleVminusDC to uint32_t l_filterDC_V, and
    processMinusHalfCycle() takes l_filterDC_V >> 15. Each sample feeds back with
    a gain of 1/32768; the accumulator is never reset and needs no clamp.
  • Samples are decimated to 14 bits (>> 2, ×16) before multiplication, so both the
    power and V² products stay in a 16×16→32 multiply and the result is shifted back
    by 8.

Calibration is unchanged. The old path was ADC ×256 → >> 2 → product ×4096 →
>> 12 → ×1; the new one is ADC ×64 → >> 2 → product ×256 → >> 8 → ×1. Net
scaling is identical, so existing f_powerCal / f_voltageCal values carry over
as-is — no user action on upgrade.

V² accumulator headroom. processVoltage() picks its shift from the datalog
period: >> 8 up to 10 s, >> 12 above. At the default 5 s (1600 sample sets/s per
phase) a full-scale sine accumulates ~1.0e9 into the uint32_t, leaving ~4×
headroom.

Tests

  • test/native/test_power_rms_comparison/ — runs the old and new pipelines side by
    side over synthetic waveforms and asserts the power / Vrms results agree.
  • test/native/test_dc_offset_filter/ — covers the Q17.15 integrator (settling,
    saturation, polarity at the rails).
  • test/embedded/test_voltage_accumulation/ — verifies the accumulator does not
    overflow across datalog periods and voltages.
  • test/embedded/test_mult_asm/ — extended for the new operand ranges.

All four are wired into the CI matrices in .github/workflows/build.yml.

Hardware validation

Bench-tested on commit 5d20297 with f_powerCal 0.050000 and f_voltageCal
0.81510 / 0.81840 / 0.81950: V1 reads 234.4–234.8 V, free RAM 1611,
minSampleSets/MC 32 (equal to the theoretical maximum of 1600 / 50, i.e. no sample
set dropped), #ofSampleSets ~8015 per 5 s period.

Deferred

Storing i_sampleVminusDC pre-decimated to 14 bits, to avoid shifting the voltage
twice per sample set (#121 comment).
Worth ~4 cycles (0.25 µs), but it makes the variable's scale depend on where you are
in the six-channel ISR interleave — ×64 until the DC filter is updated, ×16
afterwards — which a future reordering would break silently. Not taken while the ISR
has this much margin; revisit if timing ever gets tight.

Closes #121

Types of changes

  • New feature (non-breaking change which adds functionality).
  • Enhancement (non-breaking change which enhances functionality)
  • Bug Fix (non-breaking change which fixes an issue).
  • Breaking change (fix or feature that would cause existing functionality to change).

Checklist

  • I have read the README document.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.

Replace switch-case logic in ADC interrupt with circular linked list
for improved performance and reduced code size.

Based on florentbr's optimization suggestion #1 from issue #113.

- Add adc_ctx_t structure with minimal memory footprint
- Implement circular linked list for 6 ADC channels
- Eliminate branching in time-critical ISR code
- Maintain exact same functionality as original implementation
Reorganize code structure for better maintainability:
- Remove duplicate ADC definitions from top of file
- Keep all ADC optimization code together near the ISR
- Improve code organization and readability

No functional changes, just code organization improvement.
- Changed DC offset from per-cycle LPF to per-sample EMA filter
- Use Q16.16 fixed-point format for efficient calculation
- Enable ADLAR=1 for left-aligned ADC results
- Simplify voltage/current sample processing
- Reduce computational overhead in ISR
Move opening brace of the else branch to a new line for consistent brace style in processing.cpp
…n metadata

- Replace two type-specific overloads with a single constexpr template<typename T, size_t N>
  initializeArray(T (&array)[N], T value) to remove duplication and support any array element type.
- Expand and clarify Doxygen comments for initializeArray (usage, template params, notes).
- Update version.h CURRENT_TIME and reset
@FredM67 FredM67 linked an issue Oct 16, 2025 that may be closed by this pull request
FredM67 and others added 6 commits October 17, 2025 07:18
- Add mult_asm.h with optimized 16x16->32 signed multiplication (~3x faster)
- Integrate assembly multiplication in processCurrentRawSample() and processVoltage()
- Fix ADMUX timing issue (#125): move ADMUX assignment to end of ISR
- Change CT filter condition to 'if constexpr' for guaranteed dead code elimination
- Add unit tests for assembly multiplication functions

Performance improvements:
- ISR multiplication: ~15-20 cycles vs ~50+ cycles (library calls)
- Zero overhead for disabled CT filtering (compile-time elimination)
- Proper ADMUX timing: 128+ CPU cycles after trigger event per datasheet

Based on florentbr's optimization suggestions and ATmega328p datasheet requirements.
- Add multU16x16_to32 unsigned multiplication function
- Change l_sum_Vsquared from int32_t to uint32_t (V² always positive)
- Rename mult16x16_to32 to multS16x16_to32 for clarity
- Add comprehensive test coverage for unsigned multiplication
- Add voltage accumulation overflow tests (220 lines)
- Validates current shift strategy is safe for all datalog periods
- Proves uint32_t provides 2x headroom vs int32_t (4.3B vs 2.1B)

Related: #121, #125, PR #127
Make spacing consistent around template parameters and static_cast uses,
and tidy up stray blank/whitespace in test_main.cpp for the voltage
accumulation overflow tests.
@FredM67
FredM67 marked this pull request as ready for review October 17, 2025 16:50
…rocessCurrentRawSample

Add inline declarations (uint16_t sample parameter) in both header sections so the function signatures match the always_inline/optimized declarations and the Doxygen variants, avoiding mismatches.
…t scaling and tests

- In ISR-heavy paths, reduce voltage/current samples by >>2 (to 14-bit / x16 scale)
  prior to multS16x16_to32 to improve efficiency on 8-bit MCUs.
- Update scaling shifts to match the new pre-shift:
  - real power multiplication: use filt >>2 then mult, final shift >>8
  - V² accumulation: use filt >>2 then mult, final shift >>8 for <=10s or >>12 for >10s
  (effectively reducing previous right-shifts by 4 bits while preserving numeric scale)
- Update test/embedded/test_voltage_accumulation to use the 14-bit pre-shift strategy,
  adjust test cases and messages (including overflow demo) and refresh conclusions.
@FredM67

FredM67 commented Oct 22, 2025 •

Copy link
Copy Markdown
Owner Author

@florentbr Good news, at least for voltage on L1. The value are still correct ;-)

18:37:17.366 > ----------------------------------
18:37:17.397 > Sketch ID: Mk2_3phase_RFdatalog_temp
18:37:17.446 > From branch '121-suggestions-1-2', commit 5d202972
18:37:17.494 > Build on 2025-10-22 18:36:51+02:00
18:37:17.541 > ADC mode:       free-running
18:37:17.557 > Electrical settings
18:37:17.590 >  f_powerCal for L1 =    0.050000
18:37:17.622 >  f_voltageCal, for Vrms_L1 =    0.81510
18:37:17.670 >  f_powerCal for L2 =    0.050000
18:37:17.701 >  f_voltageCal, for Vrms_L2 =    0.81840
18:37:17.749 >  f_powerCal for L3 =    0.050000
18:37:17.782 >  f_voltageCal, for Vrms_L3 =    0.81950
18:37:17.814 >  f_phaseCal for all phases =     1.00
18:37:17.862 >  Export rate (Watts) = 20
18:37:17.893 >  zero-crossing persistence (sample sets) = 1
18:37:17.941 > Output mode:    normal
18:37:17.957 >  f_capacityOfEnergyBucket_main = 180000.00
18:37:18.006 >  f_lowerEnergyThreshold   = 90000.00
18:37:18.053 >  f_upperEnergyThreshold   = 90000.00
18:37:18.085 > Temperature capability is NOT present
18:37:18.133 > Dual-tariff capability is NOT present
18:37:18.165 > Load rotation feature is NOT present
18:37:18.213 > Relay diversion feature is NOT present
18:37:18.245 > Override feature is present
18:37:18.277 > *** Override Pins Configuration ***
18:37:18.325 >  Pin: 4  Bitmask: 0b11100000
18:37:18.342 > RF capability is NOT present
18:37:18.373 > Datalogging capability in Human-readable format
18:37:18.438 > Load Priorities:
18:37:18.454 >  load 0
18:37:18.454 >  load 1
18:37:18.469 >  load 2
18:37:18.485 > >>free RAM = 1611
18:37:18.502 > ----
18:37:30.385 > 5.64, P:0, P1:0, P2:0, P3:0, V1:234.44, V2:0.81, V3:0.81, (minSampleSets/MC 32, #ofSampleSets 8013)
18:37:35.376 > 7.52, P:0, P1:0, P2:0, P3:0, V1:234.54, V2:0.81, V3:0.81, (minSampleSets/MC 32, #ofSampleSets 8014)
18:37:40.382 > 11.07, P:0, P1:0, P2:0, P3:0, V1:234.55, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8015)
18:37:45.389 > 13.45, P:0, P1:0, P2:0, P3:0, V1:234.68, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8015)
18:37:50.379 > 15.74, P:0, P1:0, P2:0, P3:0, V1:234.39, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8016)
18:37:55.386 > 18.17, P:0, P1:0, P2:0, P3:0, V1:234.26, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8015)
18:38:00.392 > 19.90, P:0, P1:0, P2:0, P3:0, V1:234.13, V2:0.81, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8016)
18:38:05.399 > 22.55, P:0, P1:0, P2:0, P3:0, V1:234.51, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8016)
18:38:10.389 > 24.43, P:0, P1:0, P2:0, P3:0, V1:234.55, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8014)
18:38:15.395 > 26.43, P:0, P1:0, P2:0, P3:0, V1:234.60, V2:0.00, V3:0.00, (minSampleSets/MC 31, #ofSampleSets 8013)
18:38:20.386 > 28.73, P:0, P1:0, P2:0, P3:0, V1:234.49, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8014)
18:38:25.392 > 30.85, P:0, P1:0, P2:0, P3:0, V1:234.63, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8014)
18:38:30.399 > 34.34, P:0, P1:0, P2:0, P3:0, V1:234.50, V2:0.00, V3:0.81, (minSampleSets/MC 32, #ofSampleSets 8015)
18:38:35.389 > 35.04, P:0, P1:0, P2:0, P3:0, V1:234.48, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8014)
18:38:40.396 > 38.91, P:0, P1:0, P2:0, P3:0, V1:234.22, V2:0.00, V3:0.81, (minSampleSets/MC 31, #ofSampleSets 8014)
18:38:45.402 > 41.13, P:0, P1:0, P2:0, P3:0, V1:234.31, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8013)
18:38:50.393 > 42.43, P:0, P1:0, P2:0, P3:0, V1:234.41, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8013)
18:38:55.400 > 44.17, P:0, P1:0, P2:0, P3:0, V1:234.46, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8014)
18:39:00.389 > 47.38, P:0, P1:0, P2:0, P3:0, V1:234.32, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8013)
18:39:05.396 > 50.13, P:0, P1:0, P2:0, P3:0, V1:234.09, V2:0.00, V3:0.00, (minSampleSets/MC 31, #ofSampleSets 8014)
18:39:10.403 > 51.61, P:0, P1:0, P2:0, P3:0, V1:234.05, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8014)
18:39:15.394 > 53.73, P:0, P1:0, P2:0, P3:0, V1:234.42, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8012)
18:39:20.400 > 57.18, P:0, P1:0, P2:0, P3:0, V1:234.63, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8013)
18:39:25.391 > 59.20, P:0, P1:0, P2:0, P3:0, V1:234.77, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8013)
18:39:30.396 > 62.84, P:0, P1:0, P2:0, P3:0, V1:234.67, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8014)
18:39:35.403 > 65.29, P:0, P1:0, P2:0, P3:0, V1:234.62, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8015)
18:39:40.409 > 67.60, P:0, P1:0, P2:0, P3:0, V1:234.75, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8015)
18:39:45.400 > 69.98, P:0, P1:0, P2:0, P3:0, V1:234.67, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8015)
18:39:50.407 > 72.59, P:0, P1:0, P2:0, P3:0, V1:234.72, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8015)
18:39:55.413 > 73.82, P:0, P1:0, P2:0, P3:0, V1:234.58, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8015)
18:40:00.404 > 75.37, P:0, P1:0, P2:0, P3:0, V1:234.71, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8015)
18:40:05.410 > 77.44, P:0, P1:0, P2:0, P3:0, V1:234.78, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8016)
18:40:10.417 > 79.48, P:0, P1:0, P2:0, P3:0, V1:234.78, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8016)
18:40:15.406 > 81.38, P:0, P1:0, P2:0, P3:0, V1:234.69, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8016)
18:40:20.414 > 84.67, P:0, P1:0, P2:0, P3:0, V1:234.41, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8016)
18:40:25.420 > 87.67, P:0, P1:0, P2:0, P3:0, V1:234.39, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8016)
18:40:30.427 > 90.30, P:0, P1:0, P2:0, P3:0, V1:234.50, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8017)
18:40:35.416 > 92.40, P:0, P1:0, P2:0, P3:0, V1:234.49, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8017)
18:40:40.423 > 94.29, P:0, P1:0, P2:0, P3:0, V1:234.53, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8017)
18:40:45.429 > 96.73, P:0, P1:0, P2:0, P3:0, V1:234.70, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8016)
18:40:50.436 > 99.96, P:0, P1:0, P2:0, P3:0, V1:234.80, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8015)
18:40:55.427 > 102.24, P:0, P1:0, P2:0, P3:0, V1:234.64, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8016)
18:41:00.433 > 104.34, P:0, P1:0, P2:0, P3:0, V1:234.69, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8016)
18:41:05.439 > 106.01, P:0, P1:0, P2:0, P3:0, V1:234.67, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8016)
18:41:10.429 > 110.39, P:0, P1:0, P2:0, P3:0, V1:234.78, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8017)
18:41:15.436 > 114.01, P:0, P1:0, P2:0, P3:0, V1:234.81, V2:0.81, V3:0.81, (minSampleSets/MC 32, #ofSampleSets 8016)
18:41:20.442 > 115.98, P:0, P1:0, P2:0, P3:0, V1:234.73, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8016)
18:41:25.448 > 118.20, P:0, P1:0, P2:0, P3:0, V1:234.71, V2:0.00, V3:0.00, (minSampleSets/MC 32, #ofSampleSets 8015)

From time to time, there's a value of "0.81" for V2 and V3, even nothing is wired. Same exact effet with the "original" version :D

* fix: update ADMUX at end of ADC ISR to meet ATmega328P timing

Move ADMUX write to the end of the ADC_vect ISR so at least 128 CPU cycles
have passed since the trigger event (per ATmega328P datasheet). Prevents
premature channel switching and ensures correct sampling timing.

* #126 (comment)
@FredM67
FredM67 changed the base branch from main to dev December 27, 2025 12:35
Base automatically changed from dev to main January 29, 2026 10:42
Add comprehensive test suite for the DC offset filter changes in PR #127:

- 20 unit tests covering initialization, tracking, edge cases, precision
- 5 comparison tests proving equivalence with old filter implementation
- Documents int16_t overflow at ADC max (1023) - safe range is 0-1022
- Verifies new filter tracks same as old (within 5 ADC counts)
- Documents slower time constant (~400 vs ~200 cycles) for better noise immunity

Key findings:
- Mathematical equivalence confirmed between old and new implementations
- New filter has no explicit limits (vs old 412-612 range)
- Normal 230V operation uses ADC ~96-928, well within safe range

Co-Authored-By: Claude (global.anthropic.claude-opus-4-5-20251101-v1:0) <noreply@anthropic.com>
FredM67 added a commit that referenced this pull request Jan 30, 2026
Add comprehensive test suite for the DC offset filter changes in PR #127:

- 20 unit tests covering initialization, tracking, edge cases, precision
- 5 comparison tests proving equivalence with old filter implementation
- Documents int16_t overflow at ADC max (1023) - safe range is 0-1022
- Verifies new filter tracks same as old (within 5 ADC counts)
- Documents slower time constant (~400 vs ~200 cycles) for better noise immunity

Key findings:
- Mathematical equivalence confirmed between old and new implementations
- New filter has no explicit limits (vs old 412-612 range)
- Normal 230V operation uses ADC ~96-928, well within safe range

Co-Authored-By: Claude (global.anthropic.claude-opus-4-5-20251101-v1:0) <noreply@anthropic.com>
FredM67 and others added 3 commits January 30, 2026 17:49
Add comprehensive test suite comparing old (right-aligned ADC) vs new
(left-aligned ADC) implementations for power and RMS calculations.

Key finding: With matching DC offset, implementations are MATHEMATICALLY
IDENTICAL (<0.1% difference over full cycle). The ~2% difference seen
with default settings comes from DC offset choice (511 vs 512), NOT
from algorithm differences.

Test coverage (19 tests total):
- Basic power calculation (4 tests)
- RMS voltage calculation (2 tests)
- Full cycle comparison (3 tests)
- Edge cases and precision (5 tests)
- Extended tests with noise (5 tests):
  * 10,000 cycles long-term stability
  * ±2 LSB realistic ADC noise
  * ±5 LSB stress noise
  * Varying power factor (0°-90°) with noise
  * 50,000 cycles stress test (~17 min simulated)

All tests confirm safe migration path from old to new implementation.

Co-Authored-By: Claude (global.anthropic.claude-opus-4-5-20251101-v1:0) <noreply@anthropic.com>
Add 6 new tests simulating realistic solar/household scenarios:
- Multiple current amplitudes (20-400, light to heavy load)
- Sinusoidal load variation (5000 cycles)
- Random load steps (appliance on/off, 10000 cycles)
- Cloud shadow simulation (solar dynamics, 10000 cycles)
- Daily solar profile (24-hour pattern, 8640 cycles)
- Import/export transitions (bidirectional flow, 10000 cycles)

All tests verify <1% difference between old and new implementations
across varying current amplitudes and dynamic load conditions.

Total test suite now covers 25 scenarios including noise and edge cases.

Co-Authored-By: Claude (global.anthropic.claude-opus-4-5-20251101-v1:0) <noreply@anthropic.com>
Update realistic load variation tests to use full ADC range:
- test_multiple_current_amplitudes: now tests 10 levels (20-505)
- test_sinusoidal_load_variation: range 50-500
- test_random_load_steps: range 20-505
- test_cloud_shadow_simulation: clear sky at 500
- test_daily_solar_profile: peak at 500

Adjusted tolerances for edge cases:
- 0.2% for random/cloud tests at high amplitudes
- 3% for daily profile (includes many low-power night cycles)

All 25 tests pass across full dynamic range.

Co-Authored-By: Claude (global.anthropic.claude-opus-4-5-20251101-v1:0) <noreply@anthropic.com>
FredM67 and others added 2 commits January 30, 2026 18:21
Add printf-based statistics output to all realistic load variation tests:
- test_multiple_current_amplitudes: tabular output for 10 amplitude levels
- test_sinusoidal_load_variation: cycles, range, and power comparison
- test_random_load_steps: cycles, range, and power comparison
- test_cloud_shadow_simulation: cycles, range, and power comparison
- test_daily_solar_profile: cycles, range, and power comparison
- test_import_export_transitions: cycles, range, and power comparison

Also adds TestStats struct (unused but available for future use) and
includes <cstdio> header for printf functionality.

Co-Authored-By: Claude (global.anthropic.claude-opus-4-5-20251101-v1:0) <noreply@anthropic.com>
@FredM67
FredM67 changed the base branch from main to dev September 21, 2026 08:02
FredM67 and others added 4 commits September 21, 2026 10:05
Bring the ADLAR fixed-point branch up to date with dev (which itself was
just resynced with main after PR #138's squash-merge).

Conflict resolutions:
- mult_asm.h: kept dev's version. The assembly instruction sequences are
  byte-identical on both sides; dev's adds template parameters with
  is_same_v static_asserts documenting the required argument types.
- processing.cpp: kept this branch's version. dev's two unique changes
  (the `if constexpr (lpf_gain != 0.0F && alpha != 0.0F)` guard and the
  adc_ctx_t linked-list ADC ISR) are already present here, with the
  ADLAR redesign layered on top.
- test/embedded/test_mult_asm/test_main.cpp: kept this branch's much more
  thorough version, casting its bare int literals to the argument types
  dev's static_asserts require. Two int-promoted subtractions in the
  simulation loops needed an explicit int16_t cast as well.

Also wire three suites into the CI matrix that had never run there:
test_voltage_accumulation (embedded), test_dc_offset_filter and
test_power_rms_comparison (native). These are exactly the tests that
validate this branch's DC-offset and power/RMS rework. The timing
benchmarks (test_mult_asm_perf) stay out, as wall-clock assertions are
unreliable under Wokwi.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Whitespace only: clang-format 18 re-aligns the trailing-comment column of
each group, and the static_cast<> additions shifted those groups.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The Wokwi CI harness runs with --fail-text "FAIL" and aborts on the
first match anywhere in the serial log. The "Overflow Demo (should
FAIL with >>8 for 20s)" banner tripped it, so the job failed even
though all six Unity tests passed.

Reword the banner and note the constraint inline so it is not
reintroduced. No test logic changed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Unity compiles TEST_ASSERT_GREATER_THAN_UINT64 into an unconditional
"64-bit Support Disabled" failure on AVR, so test_20s_shift8_overflow
could never pass. Compare against UINT32_MAX directly and assert on the
bool instead; the uint64_t arithmetic itself works fine on AVR.

Serial.print() is likewise 32-bit on AVR, so the accumulator was printed
truncated (1809433306 instead of ~6.10e9, i.e. the true sum mod 2^32),
which made the diagnostic output actively misleading. Add printU64().

The test's premise was correct: 20s at >>8 really does exceed UINT32_MAX,
which is what makes the >>12 shift mandatory for periods above 10s.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@FredM67 FredM67 mentioned this pull request Sep 21, 2026
FredM67 and others added 2 commits September 21, 2026 13:59
processing.h still declared int16_t overloads of processCurrentRawSample()
and processVoltageRawSample(). Since the ADLAR rework those are defined
nowhere - the definitions in processing.cpp take uint16_t. It links today
only because ISR(ADC_vect) passes a uint16_t, an exact match; any caller
passing a signed value would silently bind the undeclared overload and fail
at link time. Remove them.

Also update processMinusHalfCycle()'s documentation, which still described
the pre-ADLAR clamped filter ("approximately one percent of the average
offset ... previous mains cycle", "remains within defined limits"). The
filter is now a free-running Q17.15 integrator with no min/max clamp, as
covered by test/native/test_dc_offset_filter.

Restore the file header @date/@copyright, which had regressed to 2021.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
These seven files carry no change other than an @Date bump applied by the old
pre-commit hook, which stamped every staged file whether or not it had been
edited. They add nothing to the ADLAR work and would conflict pointlessly with
feature/remote-loads.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@FredM67 FredM67 changed the title 121 suggestions 1 2 feat: left-aligned ADC and circular channel list (#121) Sep 21, 2026
@FredM67
FredM67 merged commit 73651e3 into dev Sep 21, 2026
17 checks passed
@FredM67
FredM67 deleted the 121-suggestions-1-2 branch September 21, 2026 13:13
FredM67 added a commit that referenced this pull request Oct 2, 2026
…board (#184)

The universal 3phaseDiverter board (rev. 6.0 and later) is designed for the internal 1.1 V
reference of the ATmega328P (buffered from AREF by an LMV321A), which the firmware must select.
Until now the firmware always used AVCC, the reference of the old 3-phase board, so a new board
measured wrongly. The change was on the unmerged new-pcb branch (cfe0682), written for the
ISR before the circular channel list of #127.

- config.h: PCB_VERSION, OLD (default, unchanged behaviour) or NEW;
- processing.cpp: _ADMUX selects AVCC or the internal 1.1 V, and the first conversion now uses
  it too (it ran on the AREF setting before the ISR took over);
- the startup summary shows the board;
- READMEs (EN/FR): how to choose, and to recalibrate after a change; CHANGELOG.

Checked: OLD gives the same ADMUX values as before (0x60 | channel) and passes the grid
simulator scenarios; NEW gives 0xE0 | channel.

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Suggestions 1 & 2

2 participants