#![no_std] #![no_main] mod keyboard; #[rtic::app( device = rp2040_hal::pac, dispatchers = [TIMER_IRQ_1] )] mod app { use crate::keyboard::Keyboard; use cortex_m::delay::Delay; use display_interface_spi::SPIInterfaceNoCS; use embedded_graphics::{ draw_target::DrawTarget, mono_font::{ascii::FONT_10X20, MonoTextStyleBuilder}, pixelcolor::{Rgb565, RgbColor}, prelude::{Point, Primitive}, primitives::{Circle, PrimitiveStyle, Triangle}, text::{Baseline, Text}, Drawable, }; use embedded_hal::PwmPin; use fugit::RateExtU32; use hal::{ gpio::{ bank0::{Gpio0, Gpio1, Gpio2}, DynPinId, FunctionSio, Pin, PullDown, PullUp, SioInput, SioOutput, }, Clock, }; use mipidsi::Builder; use panic_probe as _; use rp2040_hal as hal; use rtic_monotonics::rp2040::*; use shift_register_driver::sipo::ShiftRegister16; const XTAL_FREQ_HZ: u32 = 12_000_000u32; type MyShiftRegister = ShiftRegister16< Pin<Gpio1, FunctionSio<SioOutput>, PullDown>, Pin<Gpio2, FunctionSio<SioOutput>, PullDown>, Pin<Gpio0, FunctionSio<SioOutput>, PullDown>, >; #[shared] struct Shared {} #[local] struct Local {} #[init] fn init(ctx: init::Context) -> (Shared, Local, init::Monotonics) { let mut pac = ctx.device; let mut watchdog = hal::Watchdog::new(pac.WATCHDOG); let clocks = hal::clocks::init_clocks_and_plls( XTAL_FREQ_HZ, pac.XOSC, pac.CLOCKS, pac.PLL_SYS, pac.PLL_USB, &mut pac.RESETS, &mut watchdog, ) .ok() .unwrap(); let sio = hal::Sio::new(pac.SIO); let pins = hal::gpio::Pins::new( pac.IO_BANK0, pac.PADS_BANK0, sio.gpio_bank0, &mut pac.RESETS, ); // Init PWMs let mut pwm_slices = hal::pwm::Slices::new(pac.PWM, &mut pac.RESETS); // Display backlight let pwm = &mut pwm_slices.pwm5; pwm.set_ph_correct(); pwm.enable(); let disp_backlight = &mut pwm.channel_a; disp_backlight.output_to(pins.gpio10); let max_duty = disp_backlight.get_max_duty(); disp_backlight.set_duty(max_duty / 2); // Shift register let sr_clk = pins.gpio1.into_push_pull_output(); let sr_ser = pins.gpio0.into_push_pull_output(); let sr_rclk = pins.gpio2.into_push_pull_output(); let sr = cortex_m::singleton!(: MyShiftRegister = ShiftRegister16::new(sr_clk, sr_rclk, sr_ser)) .unwrap(); let sr_pins = sr.decompose(); let [_led_b, _led_g, _led_r, _tp_reset, disp_reset, _, _, _, col1, col2, col3, col4, col5, col6, col7, _unused] = sr_pins; // Keyboard let cols = [col1, col2, col3, col4, col5, col6, col7]; let rows: [Pin<DynPinId, FunctionSio<SioInput>, PullUp>; 7] = [ pins.gpio9.into_pull_up_input().into_dyn_pin(), pins.gpio8.into_pull_up_input().into_dyn_pin(), pins.gpio7.into_pull_up_input().into_dyn_pin(), pins.gpio6.into_pull_up_input().into_dyn_pin(), pins.gpio5.into_pull_up_input().into_dyn_pin(), pins.gpio4.into_pull_up_input().into_dyn_pin(), pins.gpio3.into_pull_up_input().into_dyn_pin(), ]; let keyboard = Keyboard::new(cols, rows); // SPI Display let display_cs = pins.gpio16.into_push_pull_output(); let spi_mosi = pins.gpio15.into_function::<hal::gpio::FunctionSpi>(); let spi_miso = pins.gpio12.into_function::<hal::gpio::FunctionSpi>(); let spi_sclk = pins.gpio14.into_function::<hal::gpio::FunctionSpi>(); let spi = hal::spi::Spi::<_, _, _, 8>::new(pac.SPI1, (spi_mosi, spi_miso, spi_sclk)); let spi = spi.init( &mut pac.RESETS, clocks.peripheral_clock.freq(), 16.MHz(), embedded_hal::spi::MODE_0, ); let spi_cs = SPIInterfaceNoCS::new(spi, display_cs); let mut delay = Delay::new(ctx.core.SYST, clocks.system_clock.freq().to_Hz()); let mut display = Builder::st7789(spi_cs) .with_display_size(320, 240) .init(&mut delay, Some(disp_reset)) .unwrap(); // Make the display all black display.clear(Rgb565::BLACK).unwrap(); // Draw a smiley face with white eyes and a red mouth draw_smiley(&mut display).unwrap(); // text! let text_style = MonoTextStyleBuilder::new() .font(&FONT_10X20) .text_color(Rgb565::YELLOW) .build(); Text::with_baseline( "Hello world!", Point::new(16, 128), text_style, Baseline::Top, ) .draw(&mut display) .unwrap(); (Shared {}, Local {}, init::Monotonics()) } fn draw_smiley<T: DrawTarget<Color = Rgb565>>(display: &mut T) -> Result<(), T::Error> { // Draw the left eye as a circle located at (50, 100), with a diameter of 40, filled with white Circle::new(Point::new(50, 100), 40) .into_styled(PrimitiveStyle::with_fill(Rgb565::WHITE)) .draw(display)?; // Draw the right eye as a circle located at (50, 200), with a diameter of 40, filled with white Circle::new(Point::new(50, 200), 40) .into_styled(PrimitiveStyle::with_fill(Rgb565::WHITE)) .draw(display)?; // Draw an upside down red triangle to represent a smiling mouth Triangle::new( Point::new(130, 140), Point::new(130, 200), Point::new(160, 170), ) .into_styled(PrimitiveStyle::with_fill(Rgb565::RED)) .draw(display)?; // Cover the top part of the mouth with a black triangle so it looks closed instead of open Triangle::new( Point::new(130, 150), Point::new(130, 190), Point::new(150, 170), ) .into_styled(PrimitiveStyle::with_fill(Rgb565::BLACK)) .draw(display)?; Ok(()) } }