diff --git a/src/main.rs b/src/main.rs index a3c12aa..322f448 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,16 +1,12 @@ #![no_std] #![no_main] +mod menu; mod onboard_led; -use core::u16::MIN; - use cortex_m::prelude::_embedded_hal_PwmPin; - -use defmt::info; use defmt::println; use defmt_rtt as _; -use embedded_hal::digital::StatefulOutputPin; use panic_probe as _; use rp2040_hal::clocks::ClockSource; @@ -21,7 +17,6 @@ use rp2040_hal::gpio::FunctionSioOutput; use rp2040_hal::gpio::Pin; use rp2040_hal::gpio::PullDown; use rp2040_hal::gpio::PullNone; -use rp2040_hal::pll; use rp2040_hal::pll::PLLConfig; use rp2040_hal::pll::common_configs::PLL_USB_48MHZ; // Alias for our HAL crate @@ -35,6 +30,7 @@ use embedded_hal::digital::OutputPin; use sh1106_pico_rs::graphics::GraphicsBuf; use sh1106_pico_rs::sh1106::SH1106Dev; +use crate::menu::Menu; use crate::onboard_led::OnboardLed; /// NB if OVERCLOCKING @@ -95,10 +91,10 @@ fn main() -> ! { pac.PLL_SYS, xosc.operating_frequency(), PLLConfig { - vco_freq: 1500.MHz(), + vco_freq: 1600.MHz(), refdiv: 1, - post_div1: 5, - post_div2: 3, + post_div1: 4, + post_div2: 2, }, &mut clocks, &mut pac.RESETS, @@ -125,21 +121,27 @@ fn main() -> ! { // Init PWMs let mut pwm_slices = hal::pwm::Slices::new(pac.PWM, &mut pac.RESETS); + let mut div_int = 1; // Configure PWM0 - let pwm = &mut pwm_slices.pwm7; - pwm.set_ph_correct(); - pwm.set_div_int(20); + let pwm = &mut pwm_slices.pwm3; + pwm.clr_ph_correct(); + pwm.set_div_int(div_int); pwm.set_div_frac(0); pwm.clear_interrupt(); pwm.enable(); - // let mut pwm_pin = pins.gpio15; - // pwm_pin.set_drive_strength(rp2040_hal::gpio::OutputDriveStrength::TwelveMilliAmps); - // pwm.channel_b.output_to(pwm_pin); + let mut sink = pins.gpio5.into_push_pull_output(); + sink.set_low(); + sink.set_drive_strength(rp2040_hal::gpio::OutputDriveStrength::TwelveMilliAmps); + let mut sink = pins.gpio7.into_push_pull_output(); + sink.set_low(); + sink.set_drive_strength(rp2040_hal::gpio::OutputDriveStrength::TwelveMilliAmps); + let mut pwm_pin = pins.gpio6; + pwm_pin.set_drive_strength(rp2040_hal::gpio::OutputDriveStrength::TwoMilliAmps); + pwm.channel_a.output_to(pwm_pin); - // let mut duty = 0; - // pwm.set_top(50000); - // pwm.channel_a.set_duty(duty); + pwm.set_top(3); + pwm.channel_a.set_duty(2); // let mut on_off_input = pins.gpio15.into_pull_up_input(); @@ -165,16 +167,25 @@ fn main() -> ! { let sh1106_dev = sh1106_dev; let mut gfx_buf = GraphicsBuf::new(); - gfx_buf.sprites[0].x = 114; + gfx_buf.sprites[0].y = 40; + gfx_buf.sprites[0].x = 60; gfx_buf.clear(); gfx_buf.redraw(); + let mut str_buf = [0u8; 12]; + let str_len = u32_into_str(pll_freq.to_kHz(), &mut str_buf); + let khz_str = str::from_utf8(&str_buf[str_buf.len() - str_len..]).unwrap(); + + gfx_buf.draw_string(18, 20, "Booted at: "); + gfx_buf.draw_string(78, 20, khz_str); + gfx_buf.draw_string(78 + (6 * str_len as u8), 20, "kHz"); + sh1106_dev.blit_framebuffer(&mut i2c, &gfx_buf); let mut tick: u32 = 0; - let mut led = OnboardLed::new(pins.gpio16.into_push_pull_output().into_dyn_pin()); + let mut led = OnboardLed::new(pll_freq, pins.gpio16.into_push_pull_output().into_dyn_pin()); println!("Booted at {}MHz", pll_freq.to_MHz()); println!("PWM at {}Hz", pll_freq.to_Hz() / (20 * 2 * 50000)); @@ -183,48 +194,103 @@ fn main() -> ! { let mut g = 0u8; let mut b = 0u8; - const ON_VALUE: u8 = 64; + loop { + if enter_input.is_low().unwrap() { + break; + } + } + + let mut menu = Menu::new(); + + menu.add_item("Int Div Up"); + menu.add_item("Int Div Down"); + menu.add_item("Chichi"); + menu.add_item("Nyaoha"); + + let menu = menu; + let mut cursor_pos = 0; + let mut cur_selection = 0; + + gfx_buf.sprites[1].visible = true; + gfx_buf.sprites[1].x = 10; + gfx_buf.sprites[1].y = 12; loop { tick = tick.wrapping_add(1); - let i = (tick % 144) as usize; - // let r = WAVE_TABLE[i] / 2; - // let g = WAVE_TABLE[(i + 48) % 128] / 2; - // let b = WAVE_TABLE[(i + 96) % 128] / 2; - // led.set_color(r, g, b); + cortex_m::asm::delay(5_000_000); - // match i { - // ..48 => led.set_color(128, 0, 0), - // 48..96 => led.set_color(0, 128, 0), - // _ => led.set_color(0, 0, 128), - // } - - cortex_m::asm::delay(10_000_000); - - if left_input.is_low().unwrap() { - r = match r { - ON_VALUE => 0, - _ => ON_VALUE, + if right_input.is_low().unwrap() { + cursor_pos -= 1; + if cursor_pos < 0 { + cursor_pos = 3; } } - if right_input.is_low().unwrap() { - g = match g { - ON_VALUE => 0, - _ => ON_VALUE, - } + if left_input.is_low().unwrap() { + cursor_pos = (cursor_pos + 1) % 4; } if enter_input.is_low().unwrap() { - b = match b { - ON_VALUE => 0, - _ => ON_VALUE, + cur_selection = cursor_pos; + + match cur_selection { + 0 => { + div_int = 1.max(div_int - 1); + pwm.set_div_int(div_int); + } + 1 => { + div_int = div_int.saturating_add(1); + pwm.set_div_int(div_int); + } + _ => (), } } + match cur_selection { + 0 => { + let i = (tick % 144) as usize; + r = WAVE_TABLE[i % 128] / 8; + g = WAVE_TABLE[(i + 48) % 128] / 8; + b = WAVE_TABLE[(i + 96) % 128] / 8; + } + 1 => { + r = 64; + g = 0; + b = 0; + } + 2 => { + r = 0; + g = 64; + b = 0; + } + 3 => { + r = 0; + g = 0; + b = 64; + } + _ => panic!("Shouldn't be able to select beyond menu"), + } + led.set_color(r, g, b); + gfx_buf.clear(); + gfx_buf.redraw(); + + let mut y = 10; + menu.get_menu_items().for_each(|mi| { + gfx_buf.draw_string(20, y, mi.get_name()); + y += 12; + }); + + gfx_buf.sprites[0].y = cursor_pos * 12 + 10; + gfx_buf.sprites[1].y = cur_selection * 12 + 10; + + let cur_menu_item = menu.get_item(cursor_pos as usize).unwrap(); + gfx_buf.sprites[0].x = (gfx_buf.get_string_px_length(cur_menu_item.get_name()) + 28) as i32; + + sh1106_dev.blit_framebuffer(&mut i2c, &gfx_buf); + // pwm.channel_a.set_duty(duty); // gfx_buf.clear(); diff --git a/src/menu.rs b/src/menu.rs new file mode 100644 index 0000000..74d4e1f --- /dev/null +++ b/src/menu.rs @@ -0,0 +1,49 @@ +pub struct Menu { + items: [Option; 8], +} + +impl Menu { + pub fn new() -> Self { + Self { items: [None; 8] } + } + + pub fn add_item(&mut self, name: &str) { + let Some(empty_slot) = self.items.iter_mut().find(|mi| mi.is_none()) else { + return; + }; + + *empty_slot = Some(MenuItem::new(name)); + } + + pub fn get_menu_items(&self) -> impl Iterator { + self.items.iter().filter_map(|omi| omi.clone()) + } + + pub fn get_item(&self, index: usize) -> Option { + self.items[index] + } +} + +#[derive(Clone, Copy)] +pub struct MenuItem { + name_buf: [u8; 20], + name_len: usize, +} + +impl MenuItem { + pub fn new(name: &str) -> Self { + let mut name_buf = [0u8; 20]; + let copy_len = name.len().min(20); + + name_buf[0..copy_len].copy_from_slice(&name.as_bytes()[0..copy_len]); + + Self { + name_buf, + name_len: copy_len, + } + } + + pub fn get_name(&self) -> &str { + str::from_utf8(&self.name_buf[0..self.name_len]).unwrap() + } +} diff --git a/src/onboard_led.rs b/src/onboard_led.rs index 3d01370..45a1c84 100644 --- a/src/onboard_led.rs +++ b/src/onboard_led.rs @@ -1,13 +1,18 @@ +use cortex_m::asm::nop; use embedded_hal::digital::OutputPin; -use rp2040_hal::gpio::{DynPinId, FunctionSioOutput, Pin, PullDown}; +use rp2040_hal::{ + fugit::HertzU32, + gpio::{DynPinId, FunctionSioOutput, Pin, PullDown}, +}; pub struct OnboardLed { + pll_freq: HertzU32, led_pin: Pin, } impl OnboardLed { - pub fn new(led_pin: Pin) -> Self { - Self { led_pin } + pub fn new(pll_freq: HertzU32, led_pin: Pin) -> Self { + Self { pll_freq, led_pin } } pub fn set_color(&mut self, r: u8, g: u8, b: u8) { @@ -20,17 +25,20 @@ impl OnboardLed { for i in 0..24 { let bit = color & (0x1 << (23 - i)); + let nop_count = self.pll_freq.to_Hz() / 50_000_000; self.led_pin.set_high().unwrap(); if bit == 0 { - cortex_m::asm::nop(); - cortex_m::asm::nop(); - cortex_m::asm::nop(); + for _ in 0..nop_count { + cortex_m::asm::nop(); + cortex_m::asm::nop(); + cortex_m::asm::nop(); + } } else { - cortex_m::asm::delay(60); + cortex_m::asm::delay(60 * nop_count); } self.led_pin.set_low().unwrap(); - cortex_m::asm::delay(35); + cortex_m::asm::delay(35 * nop_count); } } }