Add averaging over multiple windows for frequency measurement; optimize task yielding for USB stability.

This commit is contained in:
Kai Börnert
2026-04-27 13:42:30 +02:00
parent 61806a5fa2
commit 7f0714914f

View File

@@ -466,59 +466,73 @@ async fn worker(
let low_th: u16 = (ADC_MAX as u16) / 3; // ~1/3 Vref
let high_th: u16 = ((ADC_MAX as u32 * 2) / 3) as u16; // ~2/3 Vref
const AVG_WINDOWS: u32 = 4;
const YIELD_EVERY: u32 = 64;
let probe_duration = Duration::from_millis(100);
loop {
// Count rising edges of Q in a 100 ms window
let start = Instant::now();
let mut pulses: u32 = 0;
let mut last_q = q_high;
let mut total_pulses: u32 = 0;
probe_gnd.set_as_output(Speed::Low);
probe_gnd.set_low();
let probe_duration = Duration::from_millis(100);
while Instant::now()
.checked_duration_since(start)
.unwrap_or(Duration::from_millis(0))
< probe_duration
{
// Sample the analog input (Threshold/Trigger on A1)
let val: u16 = adc.convert(&mut ain, SampleTime::CYCLES28_5);
for _ in 0..AVG_WINDOWS {
// Count rising edges of Q in a 100 ms window
let start = Instant::now();
let mut pulses: u32 = 0;
let mut last_q = q_high;
let mut iter_count: u32 = 0;
// 555 core behavior:
// - If input <= 1/3 Vref => set Q high (trigger)
// - If input >= 2/3 Vref => set Q low (threshold)
// - Otherwise keep previous Q state (hysteresis)
if val <= low_th {
q_high = true;
} else if val >= high_th {
q_high = false;
probe_gnd.set_as_output(Speed::Low);
probe_gnd.set_low();
while Instant::now()
.checked_duration_since(start)
.unwrap_or(Duration::from_millis(0))
< probe_duration
{
// Sample the analog input (Threshold/Trigger on A1)
let val: u16 = adc.convert(&mut ain, SampleTime::CYCLES28_5);
// 555 core behavior:
// - If input <= 1/3 Vref => set Q high (trigger)
// - If input >= 2/3 Vref => set Q low (threshold)
// - Otherwise keep previous Q state (hysteresis)
if val <= low_th {
q_high = true;
} else if val >= high_th {
q_high = false;
}
// Drive output pin accordingly
if q_high {
q.set_high();
} else {
q.set_low();
}
// Count rising edges
if !last_q && q_high {
pulses = pulses.saturating_add(1);
}
last_q = q_high;
// Yield every YIELD_EVERY samples to keep USB alive without
// disrupting per-sample timing
iter_count += 1;
if iter_count % YIELD_EVERY == 0 {
yield_now().await;
}
}
// Drive output pin accordingly
if q_high {
q.set_high();
} else {
q.set_low();
}
// Count rising edges
if !last_q && q_high {
pulses = pulses.saturating_add(1);
}
last_q = q_high;
// Yield to allow USB and other tasks to run
yield_now().await;
probe_gnd.set_as_input(Pull::None);
total_pulses = total_pulses.saturating_add(pulses);
}
probe_gnd.set_as_input(Pull::None);
let freq_hz: u32 = pulses * (1000 / probe_duration.as_millis()) as u32; // pulses per 0.1s => Hz
let avg_pulses = total_pulses / AVG_WINDOWS;
let freq_hz: u32 = avg_pulses * (1000 / probe_duration.as_millis()) as u32;
let mut msg: heapless::String<128> = heapless::String::new();
let _ = write!(
&mut msg,
"555 window={}ms pulses={} freq={} Hz (A1->Q on PB0) id={:?}\r\n",
probe_duration.as_millis(),
pulses,
"555 window={}ms avg_pulses={} freq={} Hz (A1->Q on PB0) id={:?}\r\n",
probe_duration.as_millis() * AVG_WINDOWS as u64,
avg_pulses,
freq_hz,
identify_id.as_raw()
);