From 42c18a6d5a68bc0386bd5c45c44a6c26c1d175a9 Mon Sep 17 00:00:00 2001 From: Hexa Dust Date: Sat, 4 Oct 2025 15:01:50 +0100 Subject: [PATCH] brightness scaling optimization --- src/display.rs | 8 +++++++- src/main.rs | 31 +++++++------------------------ src/timer.rs | 11 ++++------- 3 files changed, 18 insertions(+), 32 deletions(-) diff --git a/src/display.rs b/src/display.rs index 4c0d912..9ce600f 100644 --- a/src/display.rs +++ b/src/display.rs @@ -5,7 +5,7 @@ use arduino_hal::{ port::{mode::Output, Pin}, }; -use crate::DISPLAY_SEGMENTS; +use crate::{DISPLAY_SEGMENTS, IO_SEGMENT_ON_MAX_US, IO_SEGMENT_ON_MIN_US}; pub struct SegmentPins { kd_seg_a: Pin, @@ -96,6 +96,12 @@ impl Brightness { pub const fn unwrap(self) -> u8 { self.0 } + + // Scales brightness (0-255) to range between IO_SEGMENT_ON_MIN_US and IO_SEGMENT_ON_MAX_US + pub fn scale_brightness(self) -> u32 { + // Using >> to avoid 32bit division which take ~576 cycles + IO_SEGMENT_ON_MIN_US + ((IO_SEGMENT_ON_MAX_US - IO_SEGMENT_ON_MIN_US) * self.0 as u32 >> 8) + } } #[derive(Clone, Copy, PartialEq, Eq)] diff --git a/src/main.rs b/src/main.rs index e936d01..7ebe86c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -50,16 +50,6 @@ pub const IO_SEGMENT_RATE_US: u32 = 1000; // Time in μs between segment updates pub const IO_SEGMENT_ON_MIN_US: u32 = 80; // How long in μs to hold segment LEDs on (dark) pub const IO_SEGMENT_ON_MAX_US: u32 = 700; // How long in μs to hold segment LEDs on (bright) -//TODO: When inline it is much slower due to use of Brightness instead of const 0xFF?! -//TODO: Optimize this code, currently it does 2 add, 1 sub, 1 mul and 1 div all on 32bit numbers! -#[inline(never)] -fn scale_brightness(b: Brightness) -> u32 { - assert_eq!((Brightness::full().unwrap() as u32), 0xFF); - IO_SEGMENT_ON_MIN_US - + (IO_SEGMENT_ON_MAX_US - IO_SEGMENT_ON_MIN_US) * b.unwrap() as u32 - / (Brightness::full().unwrap() as u32) -} - // Calculator setup pub const STACK_DEPTH: usize = 7; type Calc = StackCalc; @@ -95,7 +85,7 @@ unsafe fn TIMER0_COMPA() { access_global(&IO_LOOP, cs, |io_loop| { access_global(&SEGMENT_TIMER, cs, |st| { let brightness = io_loop.display_on(); - let elapsed = st.segment_on_time(scale_brightness(brightness)); + let elapsed = st.segment_on_time(brightness.scale_brightness()); io_loop.frame_data = Some((elapsed, brightness.unwrap())); }); }); @@ -638,21 +628,14 @@ fn main() -> ! { TransientState::Err { .. } => display.error(), } - avr_device::interrupt::free(|cs| { + let ((frame, index), frame_data) = avr_device::interrupt::free(|cs| { access_global(&IO_LOOP, cs, |io_loop| { io_loop.update_display(&display); - let (frame, index) = io_loop.frame(); - if frame % 64 == 0 && index == frame_data_index { - ufmt::uwriteln!( - &mut serial, - "[{}, {}] {:?}", - frame, - index, - io_loop.frame_data() - ) - .ok(); - } - }); + (io_loop.frame(), io_loop.frame_data()) + }) }); + if frame % 64 == 0 && index == frame_data_index { + ufmt::uwriteln!(&mut serial, "[{}, {}] {:?}", frame, index, frame_data).ok(); + } } } diff --git a/src/timer.rs b/src/timer.rs index 6fcba95..0e3f980 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -44,15 +44,12 @@ impl SegmentTimer { // Set for how long the segment LEDs should be on in μs // Controls TIMER0_COMPB interrupt time after TIMER0_COMPA pub fn segment_on_time(&mut self, segment_on_us: u32) -> u8 { - let ocrb = us_to_ticks(segment_on_us); + let delay: u8 = us_to_ticks(segment_on_us) + .try_into() + .expect("timer init segment_on_us out of rage"); let elapsed = self.timer.tcnt0.read().bits(); // Set the compare value for B match - self.timer.ocr0b.write(|w| { - w.bits( - ocrb.try_into() - .expect("timer init segment_on_us out of rage"), - ) - }); + self.timer.ocr0b.write(|w| w.bits(elapsed + delay)); return elapsed; } }