#![no_std] #![no_main] use core::cell::RefCell; use defmt::info; use display_interface_spi::SPIInterface; use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice; use embassy_executor::Spawner; use embassy_nrf::{ bind_interrupts, gpio::{AnyPin, Level, Output, OutputDrive, Pin}, peripherals, spim, }; use embassy_sync::blocking_mutex::Mutex; use embassy_time::{Duration, Timer}; use ili9341::Ili9341; use {defmt_rtt as _, panic_probe as _}; use embedded_graphics::{ mono_font::{ascii::FONT_10X20, MonoTextStyle}, pixelcolor::Rgb565, prelude::*, primitives::{ Circle, PrimitiveStyle, PrimitiveStyleBuilder, Rectangle, StrokeAlignment, Triangle, }, text::{Alignment, Text}, }; use gui::*; // Setup interrupts bind_interrupts!(struct Irqs { // Setup interrupts for SPI (SERIAL3) UARTE3_SPIM3_SPIS3_TWIM3_TWIS3 => embassy_nrf::spim::InterruptHandler; }); /// Embassy task to blink a LED /// /// # Arguments /// pin - Any valid pin is accepted /// blink_delay - a `Duration` with the amount of time /// to wait between LED toggles. #[embassy_executor::task] async fn blink(pin: AnyPin, blink_delay: Duration) -> ! { let mut led = Output::new(pin, Level::Low, OutputDrive::Standard); loop { led.set_high(); Timer::after(blink_delay).await; led.set_low(); Timer::after(blink_delay).await; } } #[embassy_executor::task] async fn gui_task( peripheral: embassy_nrf::peripherals::SERIAL3, sck: AnyPin, miso: AnyPin, mosi: AnyPin, display_reset_pin: AnyPin, cs_pin: AnyPin, dc_pin: AnyPin, ) -> ! { /////////////// // Setup SPI // /////////////// // Create an SPI config with the SPI frequency at 8MHz let mut spim_config = spim::Config::default(); spim_config.frequency = spim::Frequency::M8; // Grab the SPI Master peripheral form the nRF60 let spim = embassy_nrf::spim::Spim::new(peripheral, Irqs, sck, miso, mosi, spim_config); // Use the SPI peripheral to create a shared SPI bus let spi_bus: Mutex = Mutex::new(RefCell::new(spim)); //////////////// // Setup pins // //////////////// // Initialize the CS, DC, and display reset pins as outputs let chip_select = Output::new(cs_pin, Level::High, OutputDrive::Standard); let direction_control = Output::new(dc_pin, Level::High, OutputDrive::Standard); let display_reset = Output::new(display_reset_pin, Level::High, OutputDrive::Standard); //////////////////////// // Create the display // //////////////////////// // Use the shared bus to create a SPI Device to use for the display let spi_display = SpiDevice::new(&spi_bus, chip_select); // Create a new SPI display interface let iface = SPIInterface::new(spi_display, direction_control); // Some options for the display let display_orientation = ili9341::Orientation::PortraitFlipped; let display_size = ili9341::DisplaySize240x320; // Create the display let display = Ili9341::new( iface, display_reset, &mut embassy_time::Delay, display_orientation, display_size, ) .unwrap(); let mut gui = Gui::new(display); loop { gui.draw().expect("Failed to draw GUI"); info!("Finished drawing GUI"); } } #[embassy_executor::main] async fn main(spawner: Spawner) { // Initialize the nRF let p = embassy_nrf::init(Default::default()); // Spawn the blink task spawner .spawn( // Here we give the task to spawn, `.degrade()` turns the specific // pin on the nRF into the `anyPin` type used above. // It is basically a conversion between hardware pin and generic pin. blink(p.P0_02.degrade(), Duration::from_millis(250)), ) .expect("Failed to start blink task"); let mosi = p.P0_13; let miso = p.P0_12; let sck = p.P0_30; let cs_pin = p.P0_31; let dc_pin = p.P0_20; // Data / Command pin for the display let disp_rst_pin = p.P0_11; // Create the GUI spawner .spawn(gui_task( p.SERIAL3, sck.degrade(), miso.degrade(), mosi.degrade(), disp_rst_pin.degrade(), cs_pin.degrade(), dc_pin.degrade(), )) .expect("Failed to spawn GUI task"); // Now loop, re-running the demo every second loop { info!("Hello, world!"); Timer::after_secs(1).await; } }