diff --git a/src/timer.rs b/src/timer.rs index 71b9eac..c22c37a 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -1,22 +1,46 @@ use arduino_hal::{clock::Clock, pac::TC0, DefaultClock}; +// Prescaler set for the timer (see tccr0b) +const TIMER_PRESCALE: u32 = 64; +// Timer clock tick rate per second +const TIMER_FREQ: u32 = DefaultClock::FREQ / TIMER_PRESCALE; + +// How much time in μs to reserve for post LED off operation (keyboard read) +const BUFFER_US: u32 = 250; +const BUFFER_TICKS: u32 = us_to_ticks(BUFFER_US); + +const fn us_to_ticks(us: u32) -> u32 { + TIMER_FREQ * us / 1_000_000 +} + // Sets up timer to rise two interrupts: -// 1. TIMER0_COMPA - every segment_rate_us μs -// 2. TIMER0_COMPB - segment_on_us μs after TIMER0_COMPA -pub fn segment_timer_init(tc0: TC0, segment_rate_us: u32, segment_on_us: u32) { +// 1. TIMER0_COMPA - segment_switch_us - time in μs to switch to next segment +// 2. TIMER0_COMPB - segment_on_us - time in μs to keep segment LEDs on +pub fn segment_timer_init(tc0: TC0, segment_switch_us: u32, segment_on_us: u32) { // 16_000_000 / 64 * 1000 / 1_000_000 => 250 - let ocra = DefaultClock::FREQ / 64 * segment_rate_us / 1_000_000; - let ocrb = DefaultClock::FREQ / 64 * segment_on_us / 1_000_000; - assert!(ocra > ocrb); + let ocra = us_to_ticks(segment_switch_us); + let ocrb = us_to_ticks(segment_on_us); + assert!( + ocra > ocrb + BUFFER_TICKS, + "segment_on_us cannot be longer than segment_switch_us - buffer" + ); // Use CTC mode: reset counter when matches compare value tc0.tccr0a.write(|w| w.wgm0().ctc()); // Set the compare value for TOP (reset) - tc0.ocr0a - .write(|w| w.bits(ocra.try_into().expect("timer init seg_freq out of rage"))); + tc0.ocr0a.write(|w| { + w.bits( + ocra.try_into() + .expect("timer init segment_switch_us out of rage"), + ) + }); // Set the compare value for B match - tc0.ocr0b - .write(|w| w.bits(ocrb.try_into().expect("timer init on_div out of rage"))); + tc0.ocr0b.write(|w| { + w.bits( + ocrb.try_into() + .expect("timer init segment_on_us out of rage"), + ) + }); // Slow down the timer (CLK / prescale) tc0.tccr0b.write(|w| w.cs0().prescale_64()); // Raise interrupt on TOP (reset) @@ -24,3 +48,20 @@ pub fn segment_timer_init(tc0: TC0, segment_rate_us: u32, segment_on_us: u32) { tc0.timsk0 .write(|w| w.ocie0a().set_bit().ocie0b().set_bit()); } + +// Set for how long the segment LEDs should be on in μs +pub fn set_segment_on_time(tc0: TC0, segment_on_us: u32) { + let ocra = tc0.ocr0a.read().bits(); + let ocrb = us_to_ticks(segment_on_us); + assert!( + ocra as u32 > ocrb + BUFFER_TICKS, + "segment_on_us cannot be longer than segment_switch_us - buffer" + ); + // Set the compare value for B match + tc0.ocr0b.write(|w| { + w.bits( + ocrb.try_into() + .expect("timer init segment_on_us out of rage"), + ) + }); +}