diff --git a/esp-wrover-kit/Cargo.toml b/esp-wrover-kit/Cargo.toml index 1bfa490..e8bfb2b 100644 --- a/esp-wrover-kit/Cargo.toml +++ b/esp-wrover-kit/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "spooky-wrover-kit" -version = "0.7.0" +version = "0.8.0" authors = ["Juraj Michálek "] edition = "2021" license = "MIT" @@ -27,7 +27,7 @@ panic-halt = "0.2" shared-bus = { version = "0.3.0" } spooky-core = { path = "../spooky-core", default-features = false, features = [ "static_maze" ] } spooky-embedded = { path = "../spooky-embedded", default-features = false, features = [ "static_maze" ] } -heapless = { version = "0.7.14", default-features = false } +spi-dma-displayinterface = { path = "../spi-dma-displayinterface", features = [ "esp32" ] } [features] default = [ "esp_wrover_kit" ] diff --git a/esp-wrover-kit/src/app.rs b/esp-wrover-kit/src/app.rs index 74b102a..5cd4fc9 100644 --- a/esp-wrover-kit/src/app.rs +++ b/esp-wrover-kit/src/app.rs @@ -1,14 +1,19 @@ use crate::types::ConfiguredPins; -use embedded_graphics::{pixelcolor::Rgb565, prelude::DrawTarget}; +use embedded_graphics::pixelcolor::Rgb565; use spooky_core::{engine::Engine, spritebuf::SpriteBuf, universe::Universe}; use embedded_graphics_framebuf::FrameBuf; use embedded_hal::digital::v2::InputPin; +use display_interface::WriteOnlyDataCommand; +use mipidsi::models::Model; +use embedded_hal::digital::v2::OutputPin; use crate::setup::{setup_movement_controller, setup_button_keyboard}; use embedded_graphics::prelude::RgbColor; -pub fn app_loop( +pub fn app_loop( + display: &mut mipidsi::Display, + lcd_h_res:u16, + lcd_v_res:u16, configured_pins: ConfiguredPins, - display: &mut DISP, seed_buffer: [u8; 32]) where UP: InputPin, @@ -17,7 +22,9 @@ where RP: InputPin, DB: InputPin, TP: InputPin, - DISP: DrawTarget, + DI: WriteOnlyDataCommand, + M: Model, + RST: OutputPin, { let button_keyboard = setup_button_keyboard(configured_pins); @@ -34,7 +41,7 @@ where universe.initialize(); loop { - let _ = display - .draw_iter(universe.render_frame().into_iter()); + let pixel_iterator = universe.render_frame().get_pixel_iter(); + let _ = display.set_pixels(0, 0, lcd_v_res-1, lcd_h_res, pixel_iterator); } } diff --git a/esp-wrover-kit/src/main.rs b/esp-wrover-kit/src/main.rs index 585d058..41428ce 100644 --- a/esp-wrover-kit/src/main.rs +++ b/esp-wrover-kit/src/main.rs @@ -6,14 +6,20 @@ #[global_allocator] static ALLOCATOR: esp_alloc::EspHeap = esp_alloc::EspHeap::empty(); +// use display_interface_spi::SPIInterfaceNoCS; +use spi_dma_displayinterface::spi_dma_displayinterface::SPIInterfaceNoCS; + use esp_backtrace as _; -use hal::{psram, prelude::*, peripherals::Peripherals, +use hal::{psram, prelude::*, + peripherals::Peripherals, + dma::DmaPriority, + pdma::Dma, spi::{ - master::Spi, + master::{prelude::*, Spi}, SpiMode, }, clock::{ClockControl, CpuClock}, Delay, Rng, IO}; -use display_interface_spi::SPIInterfaceNoCS; + use embedded_graphics::{ mono_font::{ascii::FONT_8X13, MonoTextStyle}, prelude::{Point, RgbColor}, @@ -25,7 +31,8 @@ mod setup; mod types; mod app; use app::app_loop; -use setup::*; + +use crate::types::ConfiguredPins; pub fn init_psram_heap() { unsafe { @@ -41,29 +48,64 @@ fn main() -> ! { init_psram_heap(); let system = peripherals.SYSTEM.split(); - let clocks = ClockControl::configure(system.clock_control, CpuClock::Clock240MHz).freeze(); + + // With DMA we have sufficient throughput, so we can clock down the CPU to 160MHz + let clocks = ClockControl::configure(system.clock_control, CpuClock::Clock160MHz).freeze(); let mut delay = Delay::new(&clocks); let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); - let (unconfigured_pins, configured_pins, configured_system_pins) = setup_pins(io.pins); - let spi = Spi::new_no_cs_no_miso( + let lcd_h_res = 240; + let lcd_v_res = 320; + + let lcd_sclk = io.pins.gpio19; + let lcd_mosi = io.pins.gpio23; + let lcd_miso = io.pins.gpio25; + let lcd_cs = io.pins.gpio22; + let lcd_dc = io.pins.gpio21.into_push_pull_output(); + let _lcd_backlight = io.pins.gpio5.into_push_pull_output(); + let lcd_reset = io.pins.gpio18.into_push_pull_output(); + + let dma = Dma::new(system.dma); + let dma_channel = dma.spi2channel; + + let mut descriptors = [0u32; 8 * 3]; + let mut rx_descriptors = [0u32; 8 * 3]; + + let configured_pins = ConfiguredPins { + up_button: io.pins.gpio14.into_pull_up_input(), + down_button: io.pins.gpio12.into_pull_up_input(), + left_button: io.pins.gpio13.into_pull_up_input(), + right_button: io.pins.gpio15.into_pull_up_input(), + dynamite_button: io.pins.gpio26.into_pull_up_input(), + teleport_button: io.pins.gpio27.into_pull_up_input(), + }; + + let spi = Spi::new( peripherals.SPI2, - unconfigured_pins.sclk, - unconfigured_pins.mosi, + lcd_sclk, + lcd_mosi, + lcd_miso, + lcd_cs, 60u32.MHz(), SpiMode::Mode0, &clocks, - ); + // ); + ).with_dma(dma_channel.configure( + false, + &mut descriptors, + &mut rx_descriptors, + DmaPriority::Priority0, + )); - let di = SPIInterfaceNoCS::new(spi, configured_system_pins.dc); + let di = SPIInterfaceNoCS::new(spi, lcd_dc); let mut display = match mipidsi::Builder::ili9341_rgb565(di) - .with_display_size(240 as u16, 320 as u16) + .with_display_size(lcd_h_res as u16, lcd_v_res as u16) .with_orientation(mipidsi::Orientation::Landscape(false)) .with_color_order(mipidsi::ColorOrder::Bgr) - .init(&mut delay, Some(configured_system_pins.reset)) { + .init(&mut delay, Some(lcd_reset)) { Ok(disp) => { disp }, Err(_) => { panic!() }, }; @@ -80,6 +122,6 @@ fn main() -> ! { let mut seed_buffer = [1u8; 32]; rng.read(&mut seed_buffer).unwrap(); - app_loop(configured_pins, &mut display, seed_buffer); + app_loop(&mut display, lcd_h_res, lcd_v_res, configured_pins, seed_buffer); loop {} } diff --git a/esp-wrover-kit/src/setup.rs b/esp-wrover-kit/src/setup.rs index 4c77680..401f5b4 100644 --- a/esp-wrover-kit/src/setup.rs +++ b/esp-wrover-kit/src/setup.rs @@ -1,34 +1,8 @@ -use crate::types::{UnconfiguredPins, ConfiguredPins, ConfiguredSystemPins}; -use embedded_hal::digital::v2::{OutputPin, InputPin}; -use hal::gpio::{self, Pins}; +use crate::types::ConfiguredPins; +use embedded_hal::digital::v2::InputPin; use spooky_embedded::{ button_keyboard::ButtonKeyboard, embedded_movement_controller::EmbeddedMovementController }; use spooky_core; -pub fn setup_pins(pins: Pins) -> (UnconfiguredPins, ConfiguredPins, ConfiguredSystemPins) { - let unconfigured_pins = UnconfiguredPins { - sclk: pins.gpio19, - mosi: pins.gpio23, - }; - - let configured_pins = ConfiguredPins { - up_button: pins.gpio14.into_pull_up_input(), - down_button: pins.gpio12.into_pull_up_input(), - left_button: pins.gpio13.into_pull_up_input(), - right_button: pins.gpio15.into_pull_up_input(), - dynamite_button: pins.gpio26.into_pull_up_input(), - teleport_button: pins.gpio27.into_pull_up_input(), - }; - - let configured_system_pins = ConfiguredSystemPins { - dc: pins.gpio21.into_push_pull_output(), - backlight: pins.gpio5.into_push_pull_output(), - reset: pins.gpio18.into_push_pull_output(), - }; - - (unconfigured_pins, configured_pins, configured_system_pins) -} - pub fn setup_button_keyboard( configured_pins: ConfiguredPins ) -> ButtonKeyboard { diff --git a/esp-wrover-kit/src/types.rs b/esp-wrover-kit/src/types.rs index 2e41a9d..910009d 100644 --- a/esp-wrover-kit/src/types.rs +++ b/esp-wrover-kit/src/types.rs @@ -1,11 +1,4 @@ -use hal::gpio; -use embedded_hal::digital::v2::{ InputPin, OutputPin }; - -// Generic type for unconfigured pins -pub struct UnconfiguredPins { - pub sclk: gpio::Gpio19, - pub mosi: gpio::Gpio23, -} +use embedded_hal::digital::v2::InputPin; pub struct ConfiguredPins { pub up_button: Up, @@ -15,9 +8,3 @@ pub struct ConfiguredPins { - pub dc: Dc, - pub backlight: Bckl, - pub reset: Reset, -} diff --git a/esp32-c3-devkit-rust/Cargo.toml b/esp32-c3-devkit-rust/Cargo.toml index 5b93363..d7dca8c 100644 --- a/esp32-c3-devkit-rust/Cargo.toml +++ b/esp32-c3-devkit-rust/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "spooky-esp32-c3" -version = "0.7.0" +version = "0.8.0" authors = ["Juraj Michálek "] edition = "2021" license = "MIT" @@ -27,7 +27,7 @@ panic-halt = "0.2" shared-bus = { version = "0.3.0" } spooky-core = { path = "../spooky-core", default-features = false, features = ["static_maze"]} spooky-embedded = { path = "../spooky-embedded", default-features = false, features = [ "static_maze" ] } -heapless = { version = "0.7.14", default-features = false } +spi-dma-displayinterface = { path = "../spi-dma-displayinterface", features = ["esp32c3"] } [features] default = [ "esp32c3_ili9341" ] diff --git a/esp32-c3-devkit-rust/src/app.rs b/esp32-c3-devkit-rust/src/app.rs index 7410cec..e731445 100644 --- a/esp32-c3-devkit-rust/src/app.rs +++ b/esp32-c3-devkit-rust/src/app.rs @@ -3,16 +3,22 @@ use embedded_graphics::{pixelcolor::Rgb565, prelude::DrawTarget}; use spooky_core::{engine::Engine, spritebuf::SpriteBuf, universe::Universe}; use embedded_graphics_framebuf::FrameBuf; use embedded_graphics::prelude::RgbColor; +use display_interface::WriteOnlyDataCommand; +use embedded_hal::digital::v2::OutputPin; +use mipidsi::models::Model; use crate::accel_movement_controller::AccelMovementController; use crate::Accelerometer; -pub fn app_loop( - display: &mut DISP, +pub fn app_loop( + display: &mut mipidsi::Display, + lcd_h_res:u16, + lcd_v_res:u16, seed_buffer: [u8; 32], - icm: impl Accelerometer // You'll need to pass your accelerometer device here -) -where - DISP: DrawTarget, + icm: impl Accelerometer +) where + DI: WriteOnlyDataCommand, + M: Model, + RST: OutputPin, { let accel_movement_controller = AccelMovementController::new(icm, 0.2); @@ -30,7 +36,7 @@ where universe.initialize(); loop { - let _ = display - .draw_iter(universe.render_frame().into_iter()); + let pixel_iterator = universe.render_frame().get_pixel_iter(); + let _ = display.set_pixels(0, 0, lcd_v_res, lcd_h_res, pixel_iterator); } } diff --git a/esp32-c3-devkit-rust/src/main.rs b/esp32-c3-devkit-rust/src/main.rs index 8c5baa7..543598c 100644 --- a/esp32-c3-devkit-rust/src/main.rs +++ b/esp32-c3-devkit-rust/src/main.rs @@ -4,7 +4,9 @@ #[global_allocator] static ALLOCATOR: esp_alloc::EspHeap = esp_alloc::EspHeap::empty(); -use display_interface_spi::SPIInterfaceNoCS; +// use display_interface_spi::SPIInterfaceNoCS; +use spi_dma_displayinterface::spi_dma_displayinterface::SPIInterfaceNoCS; + use embedded_graphics::{ mono_font::{ascii::FONT_8X13, MonoTextStyle}, prelude::{Point, RgbColor}, @@ -16,11 +18,16 @@ use esp_println::println; use hal::{ clock::{ClockControl, CpuClock}, - // gdma::Gdma, + dma::DmaPriority, + gdma::Gdma, i2c, peripherals::Peripherals, prelude::*, - spi::{master::Spi, SpiMode}, + spi::{ + master::{prelude::*, Spi}, + // master::Spi, + SpiMode, + }, Delay, Rng, IO @@ -31,10 +38,6 @@ use app::app_loop; mod accel_movement_controller; mod s3box_composite_controller; -mod setup; -use setup::setup_pins; - -mod types; use esp_backtrace as _; @@ -47,29 +50,55 @@ use shared_bus::BusManagerSimple; fn main() -> ! { let peripherals = Peripherals::take(); let system = peripherals.SYSTEM.split(); - let clocks = ClockControl::configure(system.clock_control, CpuClock::Clock160MHz).freeze(); + + // With DMA we have sufficient throughput, so we can clock down the CPU to 80MHz + let clocks = ClockControl::configure(system.clock_control, CpuClock::Clock80MHz).freeze(); let mut delay = Delay::new(&clocks); println!("About to initialize the SPI LED driver"); let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); - let (uninitialized_pins, /*configured_pins, */configured_system_pins) = setup_pins(io.pins); - println!("SPI LED driver initialized"); + + let lcd_h_res = 240; + let lcd_v_res = 320; + + let lcd_sclk = io.pins.gpio0; + let lcd_mosi = io.pins.gpio6; + let lcd_miso = io.pins.gpio11; // random unused pin + let lcd_cs = io.pins.gpio5; + let lcd_dc = io.pins.gpio4.into_push_pull_output(); + let _lcd_backlight = io.pins.gpio1.into_push_pull_output(); + let lcd_reset = io.pins.gpio3.into_push_pull_output(); + + let i2c_sda = io.pins.gpio10; + let i2c_scl = io.pins.gpio8; + + let dma = Gdma::new(peripherals.DMA); + let dma_channel = dma.channel0; + + let mut descriptors = [0u32; 8 * 3]; + let mut rx_descriptors = [0u32; 8 * 3]; + let spi = Spi::new( peripherals.SPI2, - uninitialized_pins.sclk, - uninitialized_pins.mosi, - uninitialized_pins.miso, - uninitialized_pins.cs, + lcd_sclk, + lcd_mosi, + lcd_miso, + lcd_cs, 60u32.MHz(), SpiMode::Mode0, &clocks, - ); + ).with_dma(dma_channel.configure( + false, + &mut descriptors, + &mut rx_descriptors, + DmaPriority::Priority0, + )); println!("SPI ready"); - let di = SPIInterfaceNoCS::new(spi, configured_system_pins.dc); + let di = SPIInterfaceNoCS::new(spi, lcd_dc); // ESP32-S3-BOX display initialization workaround: Wait for the display to power up. // If delay is 250ms, picture will be fuzzy. @@ -77,10 +106,10 @@ fn main() -> ! { delay.delay_ms(500u32); let mut display = match mipidsi::Builder::st7789(di) - .with_display_size(240 as u16, 320 as u16) + .with_display_size(lcd_h_res as u16, lcd_v_res as u16) .with_orientation(mipidsi::Orientation::Landscape(true)) .with_color_order(mipidsi::ColorOrder::Rgb) - .init(&mut delay, Some(configured_system_pins.reset)) { + .init(&mut delay, Some(lcd_reset)) { Ok(display) => display, Err(_e) => { // Handle the error and possibly exit the application @@ -102,8 +131,8 @@ fn main() -> ! { println!("Initialized"); let i2c = i2c::I2C::new( peripherals.I2C0, - uninitialized_pins.sda, - uninitialized_pins.scl, + i2c_sda, + i2c_scl, 100u32.kHz(), &clocks, ); @@ -119,7 +148,7 @@ fn main() -> ! { rng.read(&mut seed_buffer).unwrap(); - app_loop( &mut display, seed_buffer, icm); + app_loop( &mut display, lcd_h_res, lcd_v_res, seed_buffer, icm); loop {} } diff --git a/esp32-c3-devkit-rust/src/setup.rs b/esp32-c3-devkit-rust/src/setup.rs deleted file mode 100644 index d0f78d8..0000000 --- a/esp32-c3-devkit-rust/src/setup.rs +++ /dev/null @@ -1,32 +0,0 @@ -use crate::types::{UnconfiguredPins, ConfiguredSystemPins}; -use embedded_hal::digital::v2::OutputPin; -use hal::gpio::{self, Pins}; - -pub fn setup_pins(pins: Pins) -> (UnconfiguredPins, /*ConfiguredPins, */ConfiguredSystemPins) { - let unconfigured_pins = UnconfiguredPins { - sclk: pins.gpio0, - mosi: pins.gpio6, - miso: pins.gpio11, - cs: pins.gpio5, - sda: pins.gpio10, - scl: pins.gpio8, - }; - - // let configured_pins = ConfiguredPins { - // up_button: pins.gpio14.into_pull_up_input(), - // down_button: pins.gpio12.into_pull_up_input(), - // left_button: pins.gpio13.into_pull_up_input(), - // right_button: pins.gpio15.into_pull_up_input(), - // dynamite_button: pins.gpio26.into_pull_up_input(), - // teleport_button: pins.gpio27.into_pull_up_input(), - // }; - - let configured_system_pins = ConfiguredSystemPins { - dc: pins.gpio4.into_push_pull_output(), - backlight: pins.gpio1.into_push_pull_output(), - reset: pins.gpio3.into_push_pull_output(), - }; - - (unconfigured_pins, /*configured_pins, */configured_system_pins) -} diff --git a/esp32-c3-devkit-rust/src/types.rs b/esp32-c3-devkit-rust/src/types.rs deleted file mode 100644 index b276ffa..0000000 --- a/esp32-c3-devkit-rust/src/types.rs +++ /dev/null @@ -1,18 +0,0 @@ -use hal::gpio; -use embedded_hal::digital::v2::OutputPin; - -// Generic type for unconfigured pins -pub struct UnconfiguredPins { - pub sclk: gpio::Gpio0, - pub mosi: gpio::Gpio6, - pub miso: gpio::Gpio11, - pub cs: gpio::Gpio5, - pub sda: gpio::Gpio10, - pub scl: gpio::Gpio8, -} - -pub struct ConfiguredSystemPins { - pub dc: Dc, - pub backlight: Bckl, - pub reset: Reset, -} diff --git a/esp32-c3-lcdkit/Cargo.toml b/esp32-c3-lcdkit/Cargo.toml index 8aa0600..9e6f775 100644 --- a/esp32-c3-lcdkit/Cargo.toml +++ b/esp32-c3-lcdkit/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "spooky-esp32-c3-lcdkit" -version = "0.7.0" +version = "0.8.0" authors = ["Juraj Michálek "] edition = "2021" license = "MIT" @@ -28,11 +28,11 @@ panic-halt = "0.2" shared-bus = { version = "0.3.0" } spooky-core = { path = "../spooky-core", default-features = false, features = ["static_maze"]} spooky-embedded = { path = "../spooky-embedded", default-features = false, features = [ "static_maze" ] } -heapless = { version = "0.7.14", default-features = false } # rotary-encoder-embedded = "0.2.0" # rotary-encoder-embedded = { path = "../../rotary-encoder-embedded" } rotary-encoder-embedded = { git = "https://github.com/georgik/rotary-encoder-embedded.git", branch = "feature/poll" } critical-section = "1.1.2" +spi-dma-displayinterface = { path = "../spi-dma-displayinterface", features = [ "esp32c3" ] } [features] default = [ "esp32c3_ili9341" ] diff --git a/esp32-c3-lcdkit/src/app.rs b/esp32-c3-lcdkit/src/app.rs index 719e444..273219e 100644 --- a/esp32-c3-lcdkit/src/app.rs +++ b/esp32-c3-lcdkit/src/app.rs @@ -1,16 +1,22 @@ -use embedded_graphics::{pixelcolor::Rgb565, prelude::DrawTarget}; +use embedded_graphics::pixelcolor::Rgb565; use spooky_core::{engine::Engine, spritebuf::SpriteBuf, universe::Universe}; use embedded_graphics_framebuf::FrameBuf; use embedded_graphics::prelude::RgbColor; - -pub fn app_loop( - display: &mut DISP, +use embedded_hal::digital::v2::OutputPin; +use display_interface::WriteOnlyDataCommand; +use mipidsi::models::Model; + +pub fn app_loop( + display: &mut mipidsi::Display, + lcd_h_res:u16, + lcd_v_res:u16, seed_buffer: [u8; 32], // icm: impl Accelerometer // You'll need to pass your accelerometer device here -) -where - DISP: DrawTarget, +) where + DI: WriteOnlyDataCommand, + M: Model, + RST: OutputPin, { // let accel_movement_controller = AccelMovementController::new(icm, 0.2); @@ -29,7 +35,7 @@ where universe.initialize(); loop { - let _ = display - .draw_iter(universe.render_frame().into_iter()); + let pixel_iterator = universe.render_frame().get_pixel_iter(); + let _ = display.set_pixels(0, 0, lcd_v_res, lcd_h_res, pixel_iterator); } } diff --git a/esp32-c3-lcdkit/src/main.rs b/esp32-c3-lcdkit/src/main.rs index 49bbaac..c84992c 100644 --- a/esp32-c3-lcdkit/src/main.rs +++ b/esp32-c3-lcdkit/src/main.rs @@ -4,7 +4,9 @@ #[global_allocator] static ALLOCATOR: esp_alloc::EspHeap = esp_alloc::EspHeap::empty(); -use display_interface_spi::SPIInterfaceNoCS; +// use display_interface_spi::SPIInterfaceNoCS; +use spi_dma_displayinterface::spi_dma_displayinterface::SPIInterfaceNoCS; + use embedded_graphics::{ mono_font::{ascii::FONT_8X13, MonoTextStyle}, prelude::Point, @@ -17,12 +19,16 @@ use esp_println::println; use hal::{ clock::{ClockControl, CpuClock}, gpio::{Input, PullUp}, - // gdma::Gdma, + dma::DmaPriority, + gdma::Gdma, interrupt, peripherals::{self, Peripherals, TIMG0}, prelude::*, riscv, - spi::{master::Spi, SpiMode}, + spi::{ + master::{prelude::*, Spi}, + SpiMode, + }, timer::{Timer, Timer0, TimerGroup}, Delay, Rng, @@ -32,12 +38,8 @@ use hal::{ mod app; mod lcdkit_composite_controller; -mod setup; mod rotary_movement_controller; use rotary_encoder_embedded::{standard::StandardMode, Direction, RotaryEncoder}; -use setup::setup_pins; - -mod types; use esp_backtrace as _; @@ -78,7 +80,9 @@ fn TG0_T0_LEVEL() { fn main() -> ! { let peripherals = Peripherals::take(); let system = peripherals.SYSTEM.split(); - let clocks = ClockControl::configure(system.clock_control, CpuClock::Clock160MHz).freeze(); + + // With DMA we have sufficient throughput, so we can clock down the CPU to 80MHz + let clocks = ClockControl::configure(system.clock_control, CpuClock::Clock80MHz).freeze(); let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks); let mut timer0 = timer_group0.timer0; @@ -88,22 +92,47 @@ fn main() -> ! { println!("About to initialize the SPI LED driver"); let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); // https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp32c3/esp32-c3-lcdkit/user_guide.html#gpio-allocation - let (uninitialized_pins, mut configured_system_pins, rotary_pins) = setup_pins(io.pins); - println!("SPI LED driver initialized"); + + let lcd_h_res = 240; + let lcd_v_res = 240; + + let lcd_sclk = io.pins.gpio1; + let lcd_mosi = io.pins.gpio0; + let lcd_miso = io.pins.gpio4; + let lcd_cs = io.pins.gpio7; + let lcd_dc = io.pins.gpio2.into_push_pull_output(); + let mut lcd_backlight = io.pins.gpio5.into_push_pull_output(); + let lcd_reset = io.pins.gpio8.into_push_pull_output(); + + let rotary_dt = io.pins.gpio10.into_pull_up_input(); + let rotary_clk = io.pins.gpio6.into_pull_up_input(); + let rotary_switch = io.pins.gpio9.into_pull_up_input(); + + let dma = Gdma::new(peripherals.DMA); + let dma_channel = dma.channel0; + + let mut descriptors = [0u32; 8 * 3]; + let mut rx_descriptors = [0u32; 8 * 3]; + let spi = Spi::new( peripherals.SPI2, - uninitialized_pins.sclk, - uninitialized_pins.mosi, - uninitialized_pins.miso, - uninitialized_pins.cs, + lcd_sclk, + lcd_mosi, + lcd_miso, + lcd_cs, 60u32.MHz(), SpiMode::Mode0, &clocks, - ); + ).with_dma(dma_channel.configure( + false, + &mut descriptors, + &mut rx_descriptors, + DmaPriority::Priority0, + )); println!("SPI ready"); - let di = SPIInterfaceNoCS::new(spi, configured_system_pins.dc); + let di = SPIInterfaceNoCS::new(spi, lcd_dc); // ESP32-S3-BOX display initialization workaround: Wait for the display to power up. // If delay is 250ms, picture will be fuzzy. @@ -115,7 +144,7 @@ fn main() -> ! { .with_orientation(mipidsi::Orientation::Portrait(false)) .with_color_order(mipidsi::ColorOrder::Bgr) .with_invert_colors(mipidsi::ColorInversion::Inverted) - .init(&mut delay, Some(configured_system_pins.reset)) + .init(&mut delay, Some(lcd_reset)) { Ok(disp) => disp, Err(_) => { @@ -123,7 +152,7 @@ fn main() -> ! { } }; - let _ = configured_system_pins.backlight.set_high(); + let _ = lcd_backlight.set_high(); println!("Initializing..."); Text::new( @@ -139,7 +168,7 @@ fn main() -> ! { rng.read(&mut seed_buffer).unwrap(); let rotary_encoder = - RotaryEncoder::new(rotary_pins.dt, rotary_pins.clk).into_standard_mode(); + RotaryEncoder::new(rotary_dt, rotary_clk).into_standard_mode(); interrupt::enable( peripherals::Interrupt::TG0_T0_LEVEL, @@ -165,7 +194,7 @@ fn main() -> ! { let rotary_movement_controller = crate::rotary_movement_controller::RotaryMovementController::new(); let movement_controller = crate::lcdkit_composite_controller::LcdKitCompositeController::new(demo_movement_controller, rotary_movement_controller); - use embedded_graphics::{pixelcolor::Rgb565, prelude::DrawTarget}; + use embedded_graphics::pixelcolor::Rgb565; use spooky_core::{engine::Engine, spritebuf::SpriteBuf, universe::Universe}; use embedded_graphics_framebuf::FrameBuf; use embedded_graphics::prelude::RgbColor; @@ -205,7 +234,7 @@ fn main() -> ! { // Switch direction of actions - if rotary_pins.switch.is_low().unwrap_or(false) && !switch_in_progress { + if rotary_switch.is_low().unwrap_or(false) && !switch_in_progress { println!("Switching direction"); if clockwise_action == spooky_core::engine::Action::Right { clockwise_action = spooky_core::engine::Action::Down; @@ -236,8 +265,9 @@ fn main() -> ! { } } + let pixel_iterator = universe.render_frame().get_pixel_iter(); + // -1 for some reason is necessary otherwise the display is skewed + let _ = display.set_pixels(0, 0, lcd_v_res-1, lcd_h_res, pixel_iterator); - let _ = display - .draw_iter(universe.render_frame().into_iter()); } } diff --git a/esp32-c3-lcdkit/src/setup.rs b/esp32-c3-lcdkit/src/setup.rs deleted file mode 100644 index ddaf63a..0000000 --- a/esp32-c3-lcdkit/src/setup.rs +++ /dev/null @@ -1,42 +0,0 @@ -use crate::types::{ConfiguredSystemPins, RotaryPins, UnconfiguredPins}; -use embedded_hal::digital::v2::OutputPin; -use hal::gpio::{self, Input, Pins, PullUp}; - -pub fn setup_pins( - pins: Pins, -) -> ( - UnconfiguredPins, - ConfiguredSystemPins, - RotaryPins< - hal::gpio::GpioPin, 10>, - hal::gpio::GpioPin, 6>, - hal::gpio::GpioPin, 9>, - >, -) { - let unconfigured_pins = UnconfiguredPins { - sclk: pins.gpio1, - mosi: pins.gpio0, - miso: pins.gpio4, - sda: pins.gpio3, - // scl: pins.gpio6, - cs: pins.gpio7, - }; - - let configured_system_pins = ConfiguredSystemPins { - dc: pins.gpio2.into_push_pull_output(), - backlight: pins.gpio5.into_push_pull_output(), - reset: pins.gpio8.into_push_pull_output(), - }; - - let rotary_pins = RotaryPins { - dt: pins.gpio10.into_pull_up_input(), - clk: pins.gpio6.into_pull_up_input(), - switch: pins.gpio9.into_pull_up_input(), - }; - - ( - unconfigured_pins, - /*configured_pins, */ configured_system_pins, - rotary_pins, - ) -} diff --git a/esp32-c3-lcdkit/src/types.rs b/esp32-c3-lcdkit/src/types.rs deleted file mode 100644 index 142828a..0000000 --- a/esp32-c3-lcdkit/src/types.rs +++ /dev/null @@ -1,25 +0,0 @@ -use embedded_hal::digital::v2::{InputPin, OutputPin}; -use hal::gpio; - -// Generic type for unconfigured pins -pub struct UnconfiguredPins { - pub sclk: gpio::Gpio1, - pub mosi: gpio::Gpio0, - pub miso: gpio::Gpio4, - pub sda: gpio::Gpio3, - // pub scl: gpio::Gpio6, - pub cs: gpio::Gpio7, -} - -pub struct RotaryPins -{ - pub dt: DT, - pub clk: CLK, - pub switch: SW, -} - -pub struct ConfiguredSystemPins { - pub dc: Dc, - pub backlight: Bckl, - pub reset: Reset, -} diff --git a/esp32-c6-devkit/Cargo.toml b/esp32-c6-devkit/Cargo.toml index 4d0532b..e1cba7c 100644 --- a/esp32-c6-devkit/Cargo.toml +++ b/esp32-c6-devkit/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "spooky-esp32-c6" -version = "0.7.0" +version = "0.8.0" authors = ["Juraj Michálek "] edition = "2021" license = "MIT" @@ -28,16 +28,12 @@ petgraph = { git = "https://github.com/zendurix/petgraph.git", branch = "better_ shared-bus = { version = "0.3.0" } spooky-core = { path = "../spooky-core", default-features = false, features = [ "static_maze"]} spooky-embedded = { path = "../spooky-embedded", default-features = false, features = [ "static_maze" ] } -heapless = { version = "0.7.14", default-features = false } +spi-dma-displayinterface = { path = "../spi-dma-displayinterface", features = [ "esp32c6" ] } [features] default = [ "esp32c6_ili9341" ] system_timer = [] - - button_controls = [] imu_controls = [] - esp32c6 = ["system_timer"] - esp32c6_ili9341 = [ "esp32c6" ] diff --git a/esp32-c6-devkit/src/app.rs b/esp32-c6-devkit/src/app.rs index f75823a..48a032b 100644 --- a/esp32-c6-devkit/src/app.rs +++ b/esp32-c6-devkit/src/app.rs @@ -1,21 +1,26 @@ -use crate::{types::ConfiguredPins, devkitc6_composite_controller::DevkitC6CompositeController}; -use embedded_graphics::{pixelcolor::Rgb565, prelude::DrawTarget}; +use crate::devkitc6_composite_controller::DevkitC6CompositeController; +use display_interface::WriteOnlyDataCommand; +use embedded_graphics::pixelcolor::Rgb565; +use mipidsi::models::Model; use spooky_core::{engine::Engine, spritebuf::SpriteBuf, universe::Universe}; use embedded_graphics_framebuf::FrameBuf; -use embedded_hal::digital::v2::InputPin; use embedded_graphics::prelude::RgbColor; use crate::ladder_movement_controller::LadderMovementController; +use embedded_hal::digital::v2::OutputPin; use hal::{adc::{ADC1, AdcPin, ADC}, gpio::{GpioPin, Analog}}; -use log::debug; -pub fn app_loop( +pub fn app_loop( + display: &mut mipidsi::Display, + lcd_h_res:u16, + lcd_v_res:u16, adc1: ADC<'_, ADC1>, adc_ladder_pin: AdcPin, ADC1>, - display: &mut DISP, seed_buffer: [u8; 32] ) where - DISP: DrawTarget, + DI: WriteOnlyDataCommand, + M: Model, + RST: OutputPin, { let ladder_movement_controller = LadderMovementController::new(adc1, adc_ladder_pin); @@ -34,7 +39,7 @@ where universe.initialize(); loop { - let _ = display - .draw_iter(universe.render_frame().into_iter()); + let pixel_iterator = universe.render_frame().get_pixel_iter(); + let _ = display.set_pixels(0, 0, lcd_v_res, lcd_h_res, pixel_iterator); } } diff --git a/esp32-c6-devkit/src/main.rs b/esp32-c6-devkit/src/main.rs index 7af5f12..d885681 100644 --- a/esp32-c6-devkit/src/main.rs +++ b/esp32-c6-devkit/src/main.rs @@ -1,14 +1,15 @@ #![no_std] #![no_main] -#![feature(default_alloc_error_handler)] #[global_allocator] static ALLOCATOR: esp_alloc::EspHeap = esp_alloc::EspHeap::empty(); -use display_interface_spi::SPIInterfaceNoCS; +// use display_interface_spi::SPIInterfaceNoCS; +use spi_dma_displayinterface::spi_dma_displayinterface::SPIInterfaceNoCS; + use embedded_graphics::{ mono_font::{ascii::FONT_8X13, MonoTextStyle}, - prelude::{DrawTarget, Point, RgbColor}, + prelude::{Point, RgbColor}, text::Text, Drawable, }; @@ -17,83 +18,87 @@ use log::info; use hal::{ clock::{ClockControl, CpuClock}, - // gdma::Gdma, + dma::DmaPriority, + gdma::Gdma, peripherals::Peripherals, prelude::*, - spi::{master::Spi, SpiMode}, + spi::{ + master::{prelude::*, Spi}, + SpiMode, + }, Delay, Rng, IO, adc::{AdcConfig, Attenuation, ADC, ADC1}, }; - mod app; use app::app_loop; mod devkitc6_composite_controller; mod ladder_movement_controller; -mod setup; -use setup::*; - -mod types; - -// systimer was introduced in ESP32-S2, it's not available for ESP32 -#[cfg(feature = "system_timer")] -use hal::systimer::SystemTimer; - -// use panic_halt as _; use esp_backtrace as _; -use embedded_graphics::pixelcolor::Rgb565; - - #[entry] fn main() -> ! { let peripherals = Peripherals::take(); - let mut system = peripherals.SYSTEM.split(); - let mut clocks = ClockControl::configure(system.clock_control, CpuClock::Clock160MHz).freeze(); + let system = peripherals.SYSTEM.split(); - let mut delay = Delay::new(&clocks); + // With DMA we have sufficient throughput, so we can clock down the CPU to 80MHz + let clocks = ClockControl::configure(system.clock_control, CpuClock::Clock80MHz).freeze(); esp_println::logger::init_logger_from_env(); info!("About to initialize the SPI LED driver"); let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); - let (uninitialized_pins, configured_pins, configured_system_pins) = setup_pins(io.pins); + + let lcd_h_res = 240; + let lcd_v_res = 320; + + let lcd_sclk = io.pins.gpio6; + let lcd_mosi = io.pins.gpio7; + let lcd_cs = io.pins.gpio20; + let lcd_miso = io.pins.gpio0; // random unused pin + let lcd_dc = io.pins.gpio21.into_push_pull_output(); + let _lcd_backlight = io.pins.gpio4.into_push_pull_output(); + let lcd_reset = io.pins.gpio3.into_push_pull_output(); + + let adc_pin = io.pins.gpio2.into_analog(); + + let dma = Gdma::new(peripherals.DMA); + let dma_channel = dma.channel0; + + let mut descriptors = [0u32; 8 * 3]; + let mut rx_descriptors = [0u32; 8 * 3]; let spi = Spi::new( peripherals.SPI2, - uninitialized_pins.sclk, - uninitialized_pins.mosi, - uninitialized_pins.miso, - uninitialized_pins.cs, + lcd_sclk, + lcd_mosi, + lcd_miso, + lcd_cs, 60u32.MHz(), SpiMode::Mode0, - &clocks, - ); + &clocks + ).with_dma(dma_channel.configure( + false, + &mut descriptors, + &mut rx_descriptors, + DmaPriority::Priority0, + )); - let di = SPIInterfaceNoCS::new(spi, configured_system_pins.dc); + let di = SPIInterfaceNoCS::new(spi, lcd_dc); let mut delay = Delay::new(&clocks); -// let mut display = mipidsi::Builder::ili9341_rgb565(di) -// .with_display_size(240 as u16, 320 as u16) -// // .with_framebuffer_size(240 as u16, 320 as u16) -// .with_orientation(mipidsi::Orientation::Landscape(true)) -// .with_color_order(mipidsi::ColorOrder::Rgb) -// .init(&mut delay, Some(configured_system_pins.reset)) { -// Ok(disp) => { disp }, -// Err(_) => { panic!() }, -// }; let mut display = match mipidsi::Builder::ili9341_rgb565(di) - .with_display_size(240 as u16, 320 as u16) + .with_display_size(lcd_h_res as u16, lcd_v_res as u16) .with_orientation(mipidsi::Orientation::Landscape(true)) .with_color_order(mipidsi::ColorOrder::Rgb) - .init(&mut delay, Some(configured_system_pins.reset)) { + .init(&mut delay, Some(lcd_reset)) { Ok(disp) => { disp }, Err(_) => { panic!() }, }; @@ -114,12 +119,12 @@ fn main() -> ! { info!("Initializing the ADC"); let mut adc1_config = AdcConfig::new(); - let adc_pin = adc1_config.enable_pin(configured_pins.adc_pin, Attenuation::Attenuation11dB); + let adc_pin = adc1_config.enable_pin(adc_pin, Attenuation::Attenuation11dB); let analog = peripherals.APB_SARADC.split(); let adc1 = ADC::::adc(analog.adc1, adc1_config).unwrap(); info!("Entering main loop"); - app_loop(adc1, adc_pin, &mut display, seed_buffer); + app_loop(&mut display, lcd_h_res, lcd_v_res, adc1, adc_pin, seed_buffer); loop {} } diff --git a/esp32-c6-devkit/src/setup.rs b/esp32-c6-devkit/src/setup.rs deleted file mode 100644 index cadf04c..0000000 --- a/esp32-c6-devkit/src/setup.rs +++ /dev/null @@ -1,25 +0,0 @@ -use crate::types::{UninitializedPins, ConfiguredPins, ConfiguredSystemPins}; -use embedded_hal::digital::v2::{OutputPin, InputPin}; -use hal::gpio::{self, Pins}; - -pub fn setup_pins(pins: Pins) -> (UninitializedPins, ConfiguredPins, ConfiguredSystemPins) { - let unconfigured_pins = UninitializedPins { - sclk: pins.gpio6, - mosi: pins.gpio7, - miso: pins.gpio0, - cs: pins.gpio20, - }; - - let configured_pins = ConfiguredPins { - adc_pin: pins.gpio2.into_analog(), - }; - - - let configured_system_pins = ConfiguredSystemPins { - dc: pins.gpio21.into_push_pull_output(), - backlight: pins.gpio4.into_push_pull_output(), - reset: pins.gpio3.into_push_pull_output(), - }; - - (unconfigured_pins, configured_pins, configured_system_pins) -} diff --git a/esp32-c6-devkit/src/types.rs b/esp32-c6-devkit/src/types.rs deleted file mode 100644 index 702f8eb..0000000 --- a/esp32-c6-devkit/src/types.rs +++ /dev/null @@ -1,20 +0,0 @@ -use hal::gpio::{self, GpioPin, Analog}; -use embedded_hal::digital::v2::OutputPin; - -// Generic type for unconfigured pins -pub struct UninitializedPins { - pub sclk: gpio::Gpio6, - pub mosi: gpio::Gpio7, - pub miso: gpio::Gpio0, - pub cs: gpio::Gpio20, -} - -pub struct ConfiguredPins { - pub adc_pin: GpioPin, -} - -pub struct ConfiguredSystemPins { - pub dc: Dc, - pub backlight: Bckl, - pub reset: Reset, -} diff --git a/esp32-s2-kaluga/Cargo.toml b/esp32-s2-kaluga/Cargo.toml index bf1c0f3..e770848 100644 --- a/esp32-s2-kaluga/Cargo.toml +++ b/esp32-s2-kaluga/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "spooky-s2-kaluga" -version = "0.7.0" +version = "0.8.0" authors = ["Juraj Michálek "] edition = "2021" license = "MIT" @@ -32,7 +32,7 @@ spooky-core = { path = "../spooky-core", default-features = false, features = [ "static_maze", ] } spooky-embedded = { path = "../spooky-embedded", default-features = false, features = [ "static_maze" ] } -heapless = { version = "0.7.14", default-features = false } +spi-dma-displayinterface = { path = "../spi-dma-displayinterface", features = [ "esp32s2" ] } [features] default = ["rt", "esp32s2_kaluga" ] diff --git a/esp32-s2-kaluga/src/app.rs b/esp32-s2-kaluga/src/app.rs index 3f005e9..a6a15f3 100644 --- a/esp32-s2-kaluga/src/app.rs +++ b/esp32-s2-kaluga/src/app.rs @@ -1,19 +1,26 @@ use crate::kaluga_composite_controller::KalugaCompositeController; -use embedded_graphics::{pixelcolor::Rgb565, prelude::DrawTarget}; +use embedded_graphics::pixelcolor::Rgb565; use spooky_core::{engine::Engine, spritebuf::SpriteBuf, universe::Universe}; use embedded_graphics_framebuf::FrameBuf; use hal::{adc::{ADC1, AdcPin, ADC}, gpio::{GpioPin, Analog}}; use embedded_graphics::prelude::RgbColor; +use embedded_hal::digital::v2::OutputPin; +use mipidsi::models::Model; +use display_interface::WriteOnlyDataCommand; use crate::ladder_movement_controller::LadderMovementController; -pub fn app_loop( +pub fn app_loop( + display: &mut mipidsi::Display, + lcd_h_res:u16, + lcd_v_res:u16, adc1: ADC<'_, ADC1>, adc_ladder_pin: AdcPin, ADC1>, - display: &mut DISP, seed_buffer: [u8; 32], ) where - DISP: DrawTarget, + DI: WriteOnlyDataCommand, + M: Model, + RST: OutputPin, { let ladder_movement_controller = LadderMovementController::new(adc1, adc_ladder_pin); @@ -32,7 +39,7 @@ where universe.initialize(); loop { - let _ = display - .draw_iter(universe.render_frame().into_iter()); + let pixel_iterator = universe.render_frame().get_pixel_iter(); + let _ = display.set_pixels(0, 0, lcd_v_res-1, lcd_h_res, pixel_iterator); } } diff --git a/esp32-s2-kaluga/src/main.rs b/esp32-s2-kaluga/src/main.rs index 63e60b4..ecd8d54 100644 --- a/esp32-s2-kaluga/src/main.rs +++ b/esp32-s2-kaluga/src/main.rs @@ -1,10 +1,12 @@ #![no_std] #![no_main] -// Main baord: https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/hw-reference/esp32s2/user-guide-esp32-s2-kaluga-1-kit.html +// Main board: https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/hw-reference/esp32s2/user-guide-esp32-s2-kaluga-1-kit.html // Buttons - Lyra extension board: https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/hw-reference/esp32s2/user-guide-esp-lyrat-8311a_v1.3.html -use display_interface_spi::SPIInterfaceNoCS; +// use display_interface_spi::SPIInterfaceNoCS; +use spi_dma_displayinterface::spi_dma_displayinterface::SPIInterfaceNoCS; + use embedded_graphics::{ prelude::{Point, RgbColor}, mono_font::{ @@ -17,10 +19,14 @@ use embedded_graphics::{ use hal::{ clock::{ ClockControl, CpuClock }, - // gdma::Gdma, + dma::DmaPriority, + pdma::Dma, peripherals::Peripherals, prelude::*, - spi::{master::Spi, SpiMode}, + spi::{ + master::{prelude::*, Spi}, + SpiMode, + }, Rng, IO, Delay, @@ -34,11 +40,6 @@ use app::app_loop; mod kaluga_composite_controller; mod ladder_movement_controller; -mod setup; -use setup::setup_pins; - -mod types; - use esp_backtrace as _; #[entry] @@ -46,7 +47,9 @@ fn main() -> ! { let peripherals = Peripherals::take(); let system = peripherals.SYSTEM.split(); - let clocks = ClockControl::configure(system.clock_control, CpuClock::Clock240MHz).freeze(); + + // With DMA we have sufficient throughput, so we can clock down the CPU to 160MHz + let clocks = ClockControl::configure(system.clock_control, CpuClock::Clock160MHz).freeze(); esp_println::logger::init_logger_from_env(); @@ -57,31 +60,42 @@ fn main() -> ! { // let mut backlight = io.pins.gpio6.into_push_pull_output(); // backlight.set_high().unwrap(); - let (uninitialized_pins, configured_pins, configured_system_pins) = setup_pins(io.pins); + let lcd_h_res = 240; + let lcd_v_res = 320; + + let lcd_sclk = io.pins.gpio15; + let lcd_mosi = io.pins.gpio9; + let lcd_miso = io.pins.gpio8; + let lcd_cs = io.pins.gpio11; + let lcd_dc = io.pins.gpio13.into_push_pull_output(); + let _lcd_backlight = io.pins.gpio5.into_push_pull_output(); + let lcd_reset = io.pins.gpio16.into_push_pull_output(); + + let adc_pin = io.pins.gpio6.into_analog(); - // This does not work on Kaluga. One need to use the CS pin, since there are more than one device on the SPI bus. - // let spi = spi::Spi::new_no_cs_no_miso( - // peripherals.SPI2, - // uninitialized_pins.sclk, - // uninitialized_pins.mosi, - // 60u32.MHz(), - // spi::SpiMode::Mode0, - // &mut system.peripheral_clock_control, - // &clocks, - // ); + let dma = Dma::new(system.dma); + let dma_channel = dma.spi2channel; + let mut descriptors = [0u32; 8 * 3]; + let mut rx_descriptors = [0u32; 8 * 3]; let spi = Spi::new( peripherals.SPI2, - uninitialized_pins.sclk, - uninitialized_pins.mosi, - uninitialized_pins.miso, - uninitialized_pins.cs, + lcd_sclk, + lcd_mosi, + lcd_miso, + lcd_cs, 60u32.MHz(), SpiMode::Mode0, - &clocks); + &clocks + ).with_dma(dma_channel.configure( + false, + &mut descriptors, + &mut rx_descriptors, + DmaPriority::Priority0, + )); - let di = SPIInterfaceNoCS::new(spi, configured_system_pins.dc); + let di = SPIInterfaceNoCS::new(spi, lcd_dc); let mut delay = Delay::new(&clocks); delay.delay_ms(500u32); @@ -91,7 +105,7 @@ fn main() -> ! { .with_display_size(320, 240) .with_orientation(mipidsi::Orientation::Landscape(true)) .with_color_order(mipidsi::ColorOrder::Rgb) - .init(&mut delay, Some(configured_system_pins.reset)) { + .init(&mut delay, Some(lcd_reset)) { Ok(disp) => { disp }, Err(_) => { panic!() }, }; @@ -113,12 +127,12 @@ fn main() -> ! { info!("Initializing the ADC"); let mut adc1_config = AdcConfig::new(); - let adc_pin = adc1_config.enable_pin(configured_pins.adc_pin, Attenuation::Attenuation11dB); + let adc_pin = adc1_config.enable_pin(adc_pin, Attenuation::Attenuation11dB); let analog = peripherals.SENS.split(); let adc1 = ADC::::adc(analog.adc1, adc1_config).unwrap(); info!("Entering main loop"); - app_loop(adc1, adc_pin, &mut display, seed_buffer); + app_loop(&mut display, lcd_h_res, lcd_v_res, adc1, adc_pin, seed_buffer); loop {} } diff --git a/esp32-s2-kaluga/src/setup.rs b/esp32-s2-kaluga/src/setup.rs deleted file mode 100644 index 9b558aa..0000000 --- a/esp32-s2-kaluga/src/setup.rs +++ /dev/null @@ -1,24 +0,0 @@ -use crate::types::{UninitializedPins, ConfiguredPins, ConfiguredSystemPins}; -use embedded_hal::digital::v2::OutputPin; -use hal::gpio::{self, Pins}; - -pub fn setup_pins(pins: Pins) -> (UninitializedPins, ConfiguredPins, ConfiguredSystemPins) { - let unconfigured_pins = UninitializedPins { - sclk: pins.gpio15, - mosi: pins.gpio9, - miso: pins.gpio8, - cs: pins.gpio11, - }; - - let configured_pins = ConfiguredPins { - adc_pin: pins.gpio6.into_analog(), - }; - - let configured_system_pins = ConfiguredSystemPins { - dc: pins.gpio13.into_push_pull_output(), - backlight: pins.gpio5.into_push_pull_output(), - reset: pins.gpio16.into_push_pull_output(), - }; - - (unconfigured_pins, configured_pins, configured_system_pins) -} diff --git a/esp32-s2-kaluga/src/types.rs b/esp32-s2-kaluga/src/types.rs deleted file mode 100644 index 021326f..0000000 --- a/esp32-s2-kaluga/src/types.rs +++ /dev/null @@ -1,20 +0,0 @@ -use hal::gpio::{self, GpioPin, Analog}; -use embedded_hal::digital::v2::OutputPin; - -// Generic type for unconfigured pins -pub struct UninitializedPins { - pub sclk: gpio::Gpio15, - pub mosi: gpio::Gpio9, - pub miso: gpio::Gpio8, - pub cs: gpio::Gpio11, -} - -pub struct ConfiguredPins { - pub adc_pin: GpioPin, -} - -pub struct ConfiguredSystemPins { - pub dc: Dc, - pub backlight: Bckl, - pub reset: Reset, -} diff --git a/esp32-s3-box-lite/Cargo.toml b/esp32-s3-box-lite/Cargo.toml index baa61a5..890b0d8 100644 --- a/esp32-s3-box-lite/Cargo.toml +++ b/esp32-s3-box-lite/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "spooky-s3-box-lite" -version = "0.4.0" +version = "0.8.0" authors = ["Juraj Michálek "] edition = "2021" license = "MIT" @@ -26,11 +26,10 @@ icm42670 = { git = "https://github.com/jessebraham/icm42670/" } mipidsi = "0.7.1" panic-halt = "0.2" shared-bus = { version = "0.3.0" } -# spooky-core = { path = "../spooky-core" } # Insufficient memory on ESP32-S3 with 0.9.0, switched to static maze without alloc spooky-core = { path = "../spooky-core" } spooky-embedded = { path = "../spooky-embedded", default-features = false, features = [ "dynamic_maze" ] } -heapless = { version = "0.7.14", default-features = false } +spi-dma-displayinterface = { path = "../spi-dma-displayinterface", features = [ "esp32s3" ] } [features] default = ["esp32s3_box"] @@ -40,10 +39,7 @@ system_timer = [] button_controls = [] imu_controls = [] -esp32 = [] -esp32s2 = ["system_timer"] esp32s3 = [] -esp32c3 = ["system_timer"] # Enable this feature in case you have an ESP32-S3-BOX board with ILI9342C esp32s3_box = [ "esp32s3", "imu_controls" ] diff --git a/esp32-s3-box-lite/src/app.rs b/esp32-s3-box-lite/src/app.rs index b2cec96..1711e82 100644 --- a/esp32-s3-box-lite/src/app.rs +++ b/esp32-s3-box-lite/src/app.rs @@ -3,16 +3,22 @@ use embedded_graphics::{pixelcolor::Rgb565, prelude::DrawTarget}; use spooky_core::{engine::Engine, spritebuf::SpriteBuf, universe::Universe}; use embedded_graphics_framebuf::FrameBuf; use embedded_graphics::prelude::RgbColor; +use embedded_hal::digital::v2::OutputPin; +use mipidsi::models::Model; +use display_interface::WriteOnlyDataCommand; use crate::accel_movement_controller::AccelMovementController; use crate::Accelerometer; -pub fn app_loop( - display: &mut DISP, +pub fn app_loop( + display: &mut mipidsi::Display, + lcd_h_res:u16, + lcd_v_res:u16, seed_buffer: [u8; 32], // icm: impl Accelerometer // You'll need to pass your accelerometer device here -) -where - DISP: DrawTarget, +) where + DI: WriteOnlyDataCommand, + M: Model, + RST: OutputPin, { // let accel_movement_controller = AccelMovementController::new(icm, 0.2); @@ -30,7 +36,7 @@ where universe.initialize(); loop { - let _ = display - .draw_iter(universe.render_frame().into_iter()); + let pixel_iterator = universe.render_frame().get_pixel_iter(); + let _ = display.set_pixels(0, 0, lcd_h_res, lcd_v_res, pixel_iterator); } } diff --git a/esp32-s3-box-lite/src/main.rs b/esp32-s3-box-lite/src/main.rs index ef038d3..177e036 100644 --- a/esp32-s3-box-lite/src/main.rs +++ b/esp32-s3-box-lite/src/main.rs @@ -4,10 +4,12 @@ #[global_allocator] static ALLOCATOR: esp_alloc::EspHeap = esp_alloc::EspHeap::empty(); -use display_interface_spi::SPIInterfaceNoCS; +// use display_interface_spi::SPIInterfaceNoCS; +use spi_dma_displayinterface::spi_dma_displayinterface::SPIInterfaceNoCS; + use embedded_graphics::{ mono_font::{ascii::FONT_8X13, MonoTextStyle}, - prelude::{DrawTarget, Point, RgbColor}, + prelude::{Point, RgbColor}, text::Text, Drawable, }; @@ -16,12 +18,16 @@ use esp_println::println; use hal::{ clock::{ClockControl, CpuClock}, - // gdma::Gdma, + dma::DmaPriority, + gdma::Gdma, i2c, peripherals::Peripherals, prelude::*, psram, - spi::{master::Spi, SpiMode}, + spi::{ + master::{prelude::*, Spi}, + SpiMode, + }, Delay, Rng, IO @@ -32,10 +38,6 @@ use app::app_loop; mod accel_movement_controller; mod s3box_composite_controller; -mod setup; -use setup::setup_pins; - -mod types; use esp_backtrace as _; @@ -64,22 +66,46 @@ fn main() -> ! { println!("About to initialize the SPI LED driver"); let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); - let (unconfigured_pins, /*configured_pins, */mut configured_system_pins) = setup_pins(io.pins); - println!("SPI LED driver initialized"); + + let lcd_h_res = 320; + let lcd_v_res = 240; + + let lcd_sclk = io.pins.gpio7; + let lcd_mosi = io.pins.gpio6; + let lcd_cs = io.pins.gpio5; + let lcd_miso = io.pins.gpio19; + let lcd_dc = io.pins.gpio4.into_push_pull_output(); + let mut lcd_backlight = io.pins.gpio45.into_push_pull_output(); + let lcd_reset = io.pins.gpio48.into_push_pull_output(); + + // let i2c_sda = io.pins.gpio8; + // let i2c_scl = io.pins.gpio18; + + let dma = Gdma::new(peripherals.DMA); + let dma_channel = dma.channel0; + + let mut descriptors = [0u32; 8 * 3]; + let mut rx_descriptors = [0u32; 8 * 3]; + let spi = Spi::new( peripherals.SPI2, - unconfigured_pins.sclk, - unconfigured_pins.mosi, - unconfigured_pins.miso, - unconfigured_pins.cs, + lcd_sclk, + lcd_mosi, + lcd_miso, + lcd_cs, 40u32.MHz(), SpiMode::Mode0, &clocks, - ); + ).with_dma(dma_channel.configure( + false, + &mut descriptors, + &mut rx_descriptors, + DmaPriority::Priority0, + )); println!("SPI ready"); - let di = SPIInterfaceNoCS::new(spi, configured_system_pins.dc); + let di = SPIInterfaceNoCS::new(spi, lcd_dc); // ESP32-S3-BOX display initialization workaround: Wait for the display to power up. // If delay is 250ms, picture will be fuzzy. @@ -91,7 +117,7 @@ fn main() -> ! { .with_orientation(mipidsi::Orientation::LandscapeInverted(true)) .with_color_order(mipidsi::ColorOrder::Rgb) .with_invert_colors(mipidsi::ColorInversion::Inverted) - .init(&mut delay, Some(configured_system_pins.reset)) { + .init(&mut delay, Some(lcd_reset)) { Ok(display) => display, Err(e) => { // Handle the error and possibly exit the application @@ -99,7 +125,7 @@ fn main() -> ! { } }; - configured_system_pins.backlight.set_low(); + let _ = lcd_backlight.set_low(); println!("Initializing..."); Text::new( @@ -133,7 +159,7 @@ fn main() -> ! { // app_loop( &mut display, seed_buffer, icm); - app_loop( &mut display, seed_buffer); + app_loop( &mut display, lcd_h_res, lcd_v_res, seed_buffer); loop {} } diff --git a/esp32-s3-box-lite/src/setup.rs b/esp32-s3-box-lite/src/setup.rs deleted file mode 100644 index 70fec09..0000000 --- a/esp32-s3-box-lite/src/setup.rs +++ /dev/null @@ -1,63 +0,0 @@ -use crate::types::{UnconfiguredPins, ConfiguredPins, ConfiguredSystemPins}; -use embedded_hal::digital::v2::{OutputPin, InputPin}; -use hal::gpio::{self, Pins}; -use spooky_embedded::{ button_keyboard::ButtonKeyboard, embedded_movement_controller::EmbeddedMovementController }; -use spooky_core; - -pub fn setup_pins(pins: Pins) -> (UnconfiguredPins, /*ConfiguredPins, */ConfiguredSystemPins) { - let unconfigured_pins = UnconfiguredPins { - sclk: pins.gpio7, - mosi: pins.gpio6, - miso: pins.gpio19, - cs: pins.gpio5, - sda: pins.gpio8, - scl: pins.gpio18, - }; - - // let configured_pins = ConfiguredPins { - // up_button: pins.gpio14.into_pull_up_input(), - // down_button: pins.gpio12.into_pull_up_input(), - // left_button: pins.gpio13.into_pull_up_input(), - // right_button: pins.gpio15.into_pull_up_input(), - // dynamite_button: pins.gpio26.into_pull_up_input(), - // teleport_button: pins.gpio27.into_pull_up_input(), - // }; - - let configured_system_pins = ConfiguredSystemPins { - dc: pins.gpio4.into_push_pull_output(), - backlight: pins.gpio45.into_push_pull_output(), - reset: pins.gpio48.into_push_pull_output(), - }; - - (unconfigured_pins, /*configured_pins, */configured_system_pins) -} - -pub fn setup_button_keyboard( - configured_pins: ConfiguredPins -) -> ButtonKeyboard { - ButtonKeyboard::new( - configured_pins.up_button, - configured_pins.down_button, - configured_pins.left_button, - configured_pins.right_button, - configured_pins.dynamite_button, - configured_pins.teleport_button, - ) -} - -pub fn setup_movement_controller( - seed_buffer: [u8; 32], - button_keyboard: ButtonKeyboard -) -> EmbeddedMovementController -where - Up: InputPin, - Down: InputPin, - Left: InputPin, - Right: InputPin, - Dyn: InputPin, - Tel: InputPin, -{ - let demo_movement_controller = spooky_core::demo_movement_controller::DemoMovementController::new(seed_buffer); - EmbeddedMovementController::new(demo_movement_controller, button_keyboard) -} \ No newline at end of file diff --git a/esp32-s3-box-lite/src/types.rs b/esp32-s3-box-lite/src/types.rs deleted file mode 100644 index 2f5213b..0000000 --- a/esp32-s3-box-lite/src/types.rs +++ /dev/null @@ -1,27 +0,0 @@ -use hal::gpio; -use embedded_hal::digital::v2::{ InputPin, OutputPin }; - -// Generic type for unconfigured pins -pub struct UnconfiguredPins { - pub sclk: gpio::Gpio7, - pub mosi: gpio::Gpio6, - pub miso: gpio::Gpio19, - pub cs: gpio::Gpio5, - pub sda: gpio::Gpio8, - pub scl: gpio::Gpio18, -} - -pub struct ConfiguredPins { - pub up_button: Up, - pub down_button: Down, - pub left_button: Left, - pub right_button: Right, - pub dynamite_button: Dyn, - pub teleport_button: Tel, -} - -pub struct ConfiguredSystemPins { - pub dc: Dc, - pub backlight: Bckl, - pub reset: Reset, -} diff --git a/esp32-s3-box/Cargo.toml b/esp32-s3-box/Cargo.toml index 0397559..923cc28 100644 --- a/esp32-s3-box/Cargo.toml +++ b/esp32-s3-box/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "spooky-s3-box" -version = "0.4.0" +version = "0.8.0" authors = ["Juraj Michálek "] edition = "2021" license = "MIT" @@ -26,24 +26,15 @@ icm42670 = { git = "https://github.com/jessebraham/icm42670/" } mipidsi = "0.7.1" panic-halt = "0.2" shared-bus = { version = "0.3.0" } -# spooky-core = { path = "../spooky-core" } -# Insufficient memory on ESP32-S3 with 0.9.0, switched to static maze without alloc spooky-core = { path = "../spooky-core" } spooky-embedded = { path = "../spooky-embedded", default-features = false, features = [ "dynamic_maze" ] } -heapless = { version = "0.7.14", default-features = false } +spi-dma-displayinterface = { path = "../spi-dma-displayinterface", features = [ "esp32s3" ] } [features] default = ["esp32s3_box"] -system_timer = [] - button_controls = [] imu_controls = [] - -esp32 = [] -esp32s2 = ["system_timer"] esp32s3 = [] -esp32c3 = ["system_timer"] -# Enable this feature in case you have an ESP32-S3-BOX board with ILI9342C esp32s3_box = [ "esp32s3", "imu_controls" ] diff --git a/esp32-s3-box/src/accel_movement_controller.rs b/esp32-s3-box/src/accel_movement_controller.rs index e933714..fa956d9 100644 --- a/esp32-s3-box/src/accel_movement_controller.rs +++ b/esp32-s3-box/src/accel_movement_controller.rs @@ -1,6 +1,6 @@ +use icm42670::accelerometer::Accelerometer; use spooky_core::engine::Action; use spooky_core::movement_controller::MovementController; -use icm42670::accelerometer::Accelerometer; pub struct AccelMovementController where I: Accelerometer, @@ -27,8 +27,7 @@ impl MovementController for AccelMovementController where I: Accelerometer, { - fn set_active(&mut self, _index:usize) { - } + fn set_active(&mut self, _index: usize) {} fn get_movement(&self) -> Action { self.last_action diff --git a/esp32-s3-box/src/app.rs b/esp32-s3-box/src/app.rs index 7410cec..81645fa 100644 --- a/esp32-s3-box/src/app.rs +++ b/esp32-s3-box/src/app.rs @@ -1,23 +1,31 @@ -use crate::s3box_composite_controller::S3BoxCompositeController; -use embedded_graphics::{pixelcolor::Rgb565, prelude::DrawTarget}; -use spooky_core::{engine::Engine, spritebuf::SpriteBuf, universe::Universe}; -use embedded_graphics_framebuf::FrameBuf; -use embedded_graphics::prelude::RgbColor; use crate::accel_movement_controller::AccelMovementController; +use crate::s3box_composite_controller::S3BoxCompositeController; use crate::Accelerometer; +use display_interface::WriteOnlyDataCommand; +use embedded_graphics::pixelcolor::Rgb565; +use embedded_graphics::prelude::RgbColor; +use embedded_graphics_framebuf::FrameBuf; +use embedded_hal::digital::v2::OutputPin; +use mipidsi::models::Model; +use spooky_core::{engine::Engine, spritebuf::SpriteBuf, universe::Universe}; -pub fn app_loop( - display: &mut DISP, +pub fn app_loop( + display: &mut mipidsi::Display, + lcd_h_res:u16, + lcd_v_res:u16, seed_buffer: [u8; 32], - icm: impl Accelerometer // You'll need to pass your accelerometer device here -) -where - DISP: DrawTarget, + icm: impl Accelerometer, +) where + DI: WriteOnlyDataCommand, + M: Model, + RST: OutputPin, { let accel_movement_controller = AccelMovementController::new(icm, 0.2); - let demo_movement_controller = spooky_core::demo_movement_controller::DemoMovementController::new(seed_buffer); - let movement_controller = S3BoxCompositeController::new(demo_movement_controller, accel_movement_controller); + let demo_movement_controller = + spooky_core::demo_movement_controller::DemoMovementController::new(seed_buffer); + let movement_controller = + S3BoxCompositeController::new(demo_movement_controller, accel_movement_controller); let mut data = [Rgb565::BLACK; 320 * 240]; let fbuf = FrameBuf::new(&mut data, 320, 240); @@ -30,7 +38,7 @@ where universe.initialize(); loop { - let _ = display - .draw_iter(universe.render_frame().into_iter()); + let pixel_iterator = universe.render_frame().get_pixel_iter(); + let _ = display.set_pixels(0, 0, lcd_h_res, lcd_v_res, pixel_iterator); } } diff --git a/esp32-s3-box/src/main.rs b/esp32-s3-box/src/main.rs index 5d47811..1db40e7 100644 --- a/esp32-s3-box/src/main.rs +++ b/esp32-s3-box/src/main.rs @@ -4,10 +4,12 @@ #[global_allocator] static ALLOCATOR: esp_alloc::EspHeap = esp_alloc::EspHeap::empty(); -use display_interface_spi::SPIInterfaceNoCS; +// use display_interface_spi::SPIInterfaceNoCS; +use spi_dma_displayinterface::spi_dma_displayinterface::SPIInterfaceNoCS; + use embedded_graphics::{ mono_font::{ascii::FONT_8X13, MonoTextStyle}, - prelude::{DrawTarget, Point, RgbColor}, + prelude::{Point, RgbColor}, text::Text, Drawable, }; @@ -16,15 +18,17 @@ use esp_println::println; use hal::{ clock::{ClockControl, CpuClock}, - // gdma::Gdma, + dma::DmaPriority, + gdma::Gdma, i2c, peripherals::Peripherals, prelude::*, psram, - spi::{master::Spi, SpiMode}, - Delay, - Rng, - IO + spi::{ + master::{prelude::*, Spi}, + SpiMode, + }, + Delay, Rng, IO, }; mod app; @@ -32,10 +36,6 @@ use app::app_loop; mod accel_movement_controller; mod s3box_composite_controller; -mod setup; -use setup::setup_pins; - -mod types; use esp_backtrace as _; @@ -57,27 +57,54 @@ fn main() -> ! { psram::init_psram(peripherals.PSRAM); init_psram_heap(); - let mut system = peripherals.SYSTEM.split(); - let clocks = ClockControl::configure(system.clock_control, CpuClock::Clock240MHz).freeze(); + let system = peripherals.SYSTEM.split(); + let clocks = ClockControl::configure(system.clock_control, CpuClock::Clock160MHz).freeze(); let mut delay = Delay::new(&clocks); println!("About to initialize the SPI LED driver"); let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); - let (unconfigured_pins, /*configured_pins, */mut configured_system_pins) = setup_pins(io.pins); - println!("SPI LED driver initialized"); - let spi = Spi::new_no_cs_no_miso( + + let lcd_h_res = 320; + let lcd_v_res = 240; + + let lcd_sclk = io.pins.gpio7; + let lcd_mosi = io.pins.gpio6; + let lcd_cs = io.pins.gpio5; + let lcd_miso = io.pins.gpio2; // random unused pin + let lcd_dc = io.pins.gpio4.into_push_pull_output(); + let mut lcd_backlight = io.pins.gpio45.into_push_pull_output(); + let lcd_reset = io.pins.gpio48.into_push_pull_output(); + + let i2c_sda = io.pins.gpio8; + let i2c_scl = io.pins.gpio18; + + let dma = Gdma::new(peripherals.DMA); + let dma_channel = dma.channel0; + + let mut descriptors = [0u32; 8 * 3]; + let mut rx_descriptors = [0u32; 8 * 3]; + + let spi = Spi::new( peripherals.SPI2, - unconfigured_pins.sclk, - unconfigured_pins.mosi, + lcd_sclk, + lcd_mosi, + lcd_miso, + lcd_cs, 60u32.MHz(), SpiMode::Mode0, &clocks, - ); + ) + .with_dma(dma_channel.configure( + false, + &mut descriptors, + &mut rx_descriptors, + DmaPriority::Priority0, + )); println!("SPI ready"); - let di = SPIInterfaceNoCS::new(spi, configured_system_pins.dc); + let di = SPIInterfaceNoCS::new(spi, lcd_dc); // ESP32-S3-BOX display initialization workaround: Wait for the display to power up. // If delay is 250ms, picture will be fuzzy. @@ -85,38 +112,31 @@ fn main() -> ! { delay.delay_ms(500u32); let mut display = match mipidsi::Builder::ili9342c_rgb565(di) - .with_display_size(320, 240) + .with_display_size(lcd_h_res, lcd_v_res) .with_orientation(mipidsi::Orientation::PortraitInverted(false)) .with_color_order(mipidsi::ColorOrder::Bgr) - .init(&mut delay, Some(configured_system_pins.reset)) { + .init(&mut delay, Some(lcd_reset)) + { Ok(display) => display, - Err(e) => { + Err(_e) => { // Handle the error and possibly exit the application panic!("Display initialization failed"); } }; - configured_system_pins.backlight.set_high(); + let _ = lcd_backlight.set_high(); println!("Initializing..."); - Text::new( - "Initializing...", - Point::new(80, 110), - MonoTextStyle::new(&FONT_8X13, RgbColor::WHITE), - ) - .draw(&mut display) - .unwrap(); - - + Text::new( + "Initializing...", + Point::new(80, 110), + MonoTextStyle::new(&FONT_8X13, RgbColor::WHITE), + ) + .draw(&mut display) + .unwrap(); // #[cfg(any(feature = "imu_controls"))] - let i2c = i2c::I2C::new( - peripherals.I2C0, - unconfigured_pins.sda, - unconfigured_pins.scl, - 100u32.kHz(), - &clocks, - ); + let i2c = i2c::I2C::new(peripherals.I2C0, i2c_sda, i2c_scl, 100u32.kHz(), &clocks); // #[cfg(any(feature = "imu_controls"))] let bus = BusManagerSimple::new(i2c); @@ -127,8 +147,7 @@ fn main() -> ! { let mut seed_buffer = [0u8; 32]; rng.read(&mut seed_buffer).unwrap(); - - app_loop( &mut display, seed_buffer, icm); - loop {} - + println!("Entering main loop"); + app_loop(&mut display, lcd_h_res, lcd_v_res, seed_buffer, icm); + panic!(); } diff --git a/esp32-s3-box/src/s3box_composite_controller.rs b/esp32-s3-box/src/s3box_composite_controller.rs index fbd8a0b..57e1d6e 100644 --- a/esp32-s3-box/src/s3box_composite_controller.rs +++ b/esp32-s3-box/src/s3box_composite_controller.rs @@ -1,8 +1,8 @@ -use spooky_core::engine::Action; -use spooky_core::movement_controller::MovementController; -use spooky_core::demo_movement_controller::DemoMovementController; use crate::accel_movement_controller::AccelMovementController; use icm42670::accelerometer::Accelerometer; +use spooky_core::demo_movement_controller::DemoMovementController; +use spooky_core::engine::Action; +use spooky_core::movement_controller::MovementController; pub struct S3BoxCompositeController where @@ -19,7 +19,10 @@ impl S3BoxCompositeController where I: Accelerometer, { - pub fn new(demo_controller: DemoMovementController, accel_controller: AccelMovementController) -> Self { + pub fn new( + demo_controller: DemoMovementController, + accel_controller: AccelMovementController, + ) -> Self { Self { demo_controller, accel_controller, @@ -49,7 +52,7 @@ where self.set_active(1); } self.demo_controller.tick() - }, + } 1 => self.accel_controller.tick(), _ => {} } diff --git a/esp32-s3-box/src/setup.rs b/esp32-s3-box/src/setup.rs deleted file mode 100644 index c603fdd..0000000 --- a/esp32-s3-box/src/setup.rs +++ /dev/null @@ -1,61 +0,0 @@ -use crate::types::{UnconfiguredPins, ConfiguredPins, ConfiguredSystemPins}; -use embedded_hal::digital::v2::{OutputPin, InputPin}; -use hal::gpio::{self, Pins}; -use spooky_embedded::{ button_keyboard::ButtonKeyboard, embedded_movement_controller::EmbeddedMovementController }; -use spooky_core; - -pub fn setup_pins(pins: Pins) -> (UnconfiguredPins, /*ConfiguredPins, */ConfiguredSystemPins) { - let unconfigured_pins = UnconfiguredPins { - sclk: pins.gpio7, - mosi: pins.gpio6, - sda: pins.gpio8, - scl: pins.gpio18, - }; - - // let configured_pins = ConfiguredPins { - // up_button: pins.gpio14.into_pull_up_input(), - // down_button: pins.gpio12.into_pull_up_input(), - // left_button: pins.gpio13.into_pull_up_input(), - // right_button: pins.gpio15.into_pull_up_input(), - // dynamite_button: pins.gpio26.into_pull_up_input(), - // teleport_button: pins.gpio27.into_pull_up_input(), - // }; - - let configured_system_pins = ConfiguredSystemPins { - dc: pins.gpio4.into_push_pull_output(), - backlight: pins.gpio45.into_push_pull_output(), - reset: pins.gpio48.into_push_pull_output(), - }; - - (unconfigured_pins, /*configured_pins, */configured_system_pins) -} - -pub fn setup_button_keyboard( - configured_pins: ConfiguredPins -) -> ButtonKeyboard { - ButtonKeyboard::new( - configured_pins.up_button, - configured_pins.down_button, - configured_pins.left_button, - configured_pins.right_button, - configured_pins.dynamite_button, - configured_pins.teleport_button, - ) -} - -pub fn setup_movement_controller( - seed_buffer: [u8; 32], - button_keyboard: ButtonKeyboard -) -> EmbeddedMovementController -where - Up: InputPin, - Down: InputPin, - Left: InputPin, - Right: InputPin, - Dyn: InputPin, - Tel: InputPin, -{ - let demo_movement_controller = spooky_core::demo_movement_controller::DemoMovementController::new(seed_buffer); - EmbeddedMovementController::new(demo_movement_controller, button_keyboard) -} \ No newline at end of file diff --git a/esp32-s3-box/src/types.rs b/esp32-s3-box/src/types.rs deleted file mode 100644 index 333aa35..0000000 --- a/esp32-s3-box/src/types.rs +++ /dev/null @@ -1,25 +0,0 @@ -use hal::gpio; -use embedded_hal::digital::v2::{ InputPin, OutputPin }; - -// Generic type for unconfigured pins -pub struct UnconfiguredPins { - pub sclk: gpio::Gpio7, - pub mosi: gpio::Gpio6, - pub sda: gpio::Gpio8, - pub scl: gpio::Gpio18, -} - -pub struct ConfiguredPins { - pub up_button: Up, - pub down_button: Down, - pub left_button: Left, - pub right_button: Right, - pub dynamite_button: Dyn, - pub teleport_button: Tel, -} - -pub struct ConfiguredSystemPins { - pub dc: Dc, - pub backlight: Bckl, - pub reset: Reset, -} diff --git a/esp32-s3-usb-otg/Cargo.toml b/esp32-s3-usb-otg/Cargo.toml index 1544564..88ce82f 100644 --- a/esp32-s3-usb-otg/Cargo.toml +++ b/esp32-s3-usb-otg/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "spooky-s3-usb-otg" -version = "0.7.0" +version = "0.8.0" authors = ["Juraj Michálek "] edition = "2021" license = "MIT" @@ -28,21 +28,13 @@ mipidsi = "0.7.1" panic-halt = "0.2" shared-bus = { version = "0.3.0" } spooky-core = { path = "../spooky-core" } -heapless = { version = "0.7.14", default-features = false } +# spi-dma-displayinterface ={ path = "../spi-dma-displayinterface", features = [ "esp32s3" ] } [features] -default = ["rt", "esp32s3_usb_otg"] -rt = ["xtensa-lx-rt"] - -system_timer = [] - +default = ["esp32s3_usb_otg"] button_controls = [] imu_controls = [] - -esp32 = [] -esp32s2 = [ "system_timer" ] esp32s3 = [ ] -esp32c3 = [ "system_timer" ] # Enable this feature in case you have an ESP32-S3-USB-OTG board with ST7789 -esp32s3_usb_otg = [ "xtensa-lx-rt", "esp32s3", "button_controls" ] +esp32s3_usb_otg = [ "esp32s3", "button_controls" ] diff --git a/esp32-s3-usb-otg/src/main.rs b/esp32-s3-usb-otg/src/main.rs index 1f86c17..3c33d52 100644 --- a/esp32-s3-usb-otg/src/main.rs +++ b/esp32-s3-usb-otg/src/main.rs @@ -1,15 +1,15 @@ #![no_std] #![no_main] -#![feature(default_alloc_error_handler)] #[global_allocator] static ALLOCATOR: esp_alloc::EspHeap = esp_alloc::EspHeap::empty(); use display_interface_spi::SPIInterfaceNoCS; + use embedded_graphics::{ - prelude::{Point, DrawTarget, RgbColor}, + prelude::{Point, RgbColor}, mono_font::{ - ascii::{FONT_8X13}, + ascii::FONT_8X13, MonoTextStyle, }, text::Text, @@ -20,32 +20,27 @@ use esp_println::println; use hal::{ clock::{ ClockControl, CpuClock }, - // gdma::Gdma, + dma::DmaPriority, + gdma::Gdma, peripherals::Peripherals, prelude::*, - spi::{master::Spi, SpiMode}, + spi::{ + master::{prelude::*, Spi}, + SpiMode, + }, Rng, IO, Delay, }; -// systimer was introduced in ESP32-S2, it's not available for ESP32 -#[cfg(feature="system_timer")] -use hal::systimer::{SystemTimer}; - -// use panic_halt as _; use esp_backtrace as _; -use embedded_graphics::{pixelcolor::Rgb565}; -// use esp32s2_hal::Rng; - -#[cfg(any(feature = "esp32s2_ili9341", feature = "esp32_wrover_kit", feature = "esp32c3_ili9341"))] -use ili9341::{DisplaySize240x320, Ili9341, Orientation}; +use embedded_graphics::pixelcolor::Rgb565; use spooky_core::{spritebuf::SpriteBuf, engine::Engine, engine::Action::{ Up, Down, Left, Right, Teleport, PlaceDynamite }}; use embedded_hal::digital::v2::OutputPin; -use embedded_graphics_framebuf::{FrameBuf}; +use embedded_graphics_framebuf::FrameBuf; pub struct Universe { pub engine: Engine, @@ -53,7 +48,7 @@ pub struct Universe { impl > Universe { - pub fn new(seed: Option<[u8; 32]>, engine:Engine) -> Universe { + pub fn new(_seed: Option<[u8; 32]>, engine:Engine) -> Universe { Universe { engine, } @@ -97,8 +92,7 @@ impl > Universe } - -#[xtensa_lx_rt::entry] +#[entry] fn main() -> ! { const HEAP_SIZE: usize = 65535*4; static mut HEAP: [u8; HEAP_SIZE] = [0; HEAP_SIZE]; @@ -106,51 +100,65 @@ fn main() -> ! { let peripherals = Peripherals::take(); - #[cfg(any(feature = "esp32"))] - let mut system = peripherals.DPORT.split(); - #[cfg(any(feature = "esp32s2", feature = "esp32s3", feature = "esp32c3"))] - let mut system = peripherals.SYSTEM.split(); - let clocks = ClockControl::configure(system.clock_control, CpuClock::Clock240MHz).freeze(); + let system = peripherals.SYSTEM.split(); + let clocks = ClockControl::configure(system.clock_control, CpuClock::Clock80MHz).freeze(); let mut delay = Delay::new(&clocks); - // self.delay = Some(delay); println!("About to initialize the SPI LED driver"); let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); - // https://espressif-docs.readthedocs-hosted.com/projects/espressif-esp-dev-kits/en/latest/esp32s3/esp32-s3-usb-otg/user_guide.html - // let button_up = button::Button::new(); + // https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp32s3/esp32-s3-usb-otg/user_guide.html let button_ok_pin = io.pins.gpio0.into_pull_up_input(); let button_menu_pin = io.pins.gpio14.into_pull_up_input(); let button_up_pin = io.pins.gpio10.into_pull_up_input(); let button_down_pin = io.pins.gpio11.into_pull_up_input(); - let mut backlight = io.pins.gpio9.into_push_pull_output(); + let lcd_h_res = 240; + let lcd_v_res = 240; + + let lcd_sclk = io.pins.gpio6; + let lcd_mosi = io.pins.gpio7; + let lcd_miso = io.pins.gpio12; // random unused pin + let lcd_cs = io.pins.gpio5; + let lcd_dc = io.pins.gpio4.into_push_pull_output(); + let mut lcd_backlight = io.pins.gpio9.into_push_pull_output(); + let lcd_reset = io.pins.gpio18.into_push_pull_output(); + + let dma = Gdma::new(peripherals.DMA); + let dma_channel = dma.channel0; + + let mut descriptors = [0u32; 8 * 3]; + let mut rx_descriptors = [0u32; 8 * 3]; let spi = Spi::new( - peripherals.SPI3, - io.pins.gpio6, - io.pins.gpio7, - io.pins.gpio12, - io.pins.gpio5, + peripherals.SPI2, + lcd_sclk, + lcd_mosi, + lcd_miso, + lcd_cs, 60u32.MHz(), SpiMode::Mode0, - &clocks); + &clocks) + .with_dma(dma_channel.configure( + false, + &mut descriptors, + &mut rx_descriptors, + DmaPriority::Priority0, + )); - backlight.set_high().unwrap(); + lcd_backlight.set_high().unwrap(); - let reset = io.pins.gpio18.into_push_pull_output(); - let di = SPIInterfaceNoCS::new(spi, io.pins.gpio4.into_push_pull_output()); + let di = SPIInterfaceNoCS::new(spi, lcd_dc); - #[cfg(any(feature = "esp32s2_ili9341", feature = "esp32_wrover_kit", feature = "esp32c3_ili9341"))] - let mut delay = Delay::new(&clocks); + delay.delay_ms(500u32); let mut display = mipidsi::Builder::st7789(di) - .with_display_size(240, 240) + .with_display_size(lcd_h_res, lcd_v_res) .with_orientation(mipidsi::Orientation::PortraitInverted(false)) .with_invert_colors(mipidsi::ColorInversion::Inverted) - .init(&mut delay, Some(reset)).unwrap(); + .init(&mut delay, Some(lcd_reset)).unwrap(); Text::new( "Initializing...", @@ -164,8 +172,8 @@ fn main() -> ! { let mut rng = Rng::new(peripherals.RNG); let mut seed_buffer = [0u8;32]; rng.read(&mut seed_buffer).unwrap(); - let mut data = [Rgb565::BLACK ; 240*240]; - let fbuf = FrameBuf::new(&mut data, 240, 240); + let mut data = [Rgb565::BLACK ; 240 * 240]; + let fbuf = FrameBuf::new(&mut data, lcd_h_res.into(), lcd_v_res.into()); let spritebuf = SpriteBuf::new(fbuf); let engine = Engine::new(spritebuf, Some(seed_buffer)); @@ -192,6 +200,7 @@ fn main() -> ! { universe.move_right(); } - display.draw_iter(universe.render_frame().into_iter()).unwrap(); + let pixel_iterator = universe.render_frame().get_pixel_iter(); + let _ = display.set_pixels(0, 0, lcd_h_res, lcd_v_res, pixel_iterator); } } diff --git a/m5stack-core2/Cargo.toml b/m5stack-core2/Cargo.toml index defd760..e85c025 100644 --- a/m5stack-core2/Cargo.toml +++ b/m5stack-core2/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "spooky-m5stack-core2" -version = "0.7.0" +version = "0.8.0" authors = ["Juraj Michálek "] edition = "2021" license = "MIT" @@ -31,11 +31,11 @@ shared-bus = { version = "0.3.0" } spooky-core = { path = "../spooky-core", default-features = false, features = [ "static_maze", ] } -heapless = { version = "0.7.14", default-features = false } esp-println = { version = "0.7.0", features = [ "esp32", "log" ] } log = { version = "0.4.18" } axp192 = { git = "https://github.com/georgik/axp192-rs.git", rev = "80e4fd27dfab", optional = true } #axp192 = { path = "../../axp192", optional = true } +spi-dma-displayinterface = { path = "../spi-dma-displayinterface", features = [ "esp32" ] } [features] default = ["m5stack_core2"] diff --git a/m5stack-core2/src/app.rs b/m5stack-core2/src/app.rs index dc6327f..65d0d04 100644 --- a/m5stack-core2/src/app.rs +++ b/m5stack-core2/src/app.rs @@ -1,17 +1,24 @@ use crate::{m5stack_composite_controller::M5StackCompositeController, accel_device::AccelDevice}; -use embedded_graphics::{pixelcolor::Rgb565, prelude::DrawTarget}; +use embedded_graphics::pixelcolor::Rgb565; use spooky_core::{engine::Engine, spritebuf::SpriteBuf, universe::Universe}; use embedded_graphics_framebuf::FrameBuf; use embedded_graphics::prelude::RgbColor; +use display_interface::WriteOnlyDataCommand; +use mipidsi::models::Model; +use embedded_hal::digital::v2::OutputPin; use crate::accel_movement_controller::AccelMovementController; -pub fn app_loop( - display: &mut DISP, +pub fn app_loop( + display: &mut mipidsi::Display, + lcd_h_res:u16, + lcd_v_res:u16, seed_buffer: [u8; 32], icm: impl AccelDevice // You'll need to pass your accelerometer device here ) where - DISP: DrawTarget, + DI: WriteOnlyDataCommand, + M: Model, + RST: OutputPin, { let accel_movement_controller = AccelMovementController::new(icm, 0.3); @@ -29,7 +36,7 @@ where universe.initialize(); loop { - let _ = display - .draw_iter(universe.render_frame().into_iter()); + let pixel_iterator = universe.render_frame().get_pixel_iter(); + let _ = display.set_pixels(0, 0, lcd_v_res-1, lcd_h_res, pixel_iterator); } } diff --git a/m5stack-core2/src/main.rs b/m5stack-core2/src/main.rs index 91ce1c6..5c9ab77 100644 --- a/m5stack-core2/src/main.rs +++ b/m5stack-core2/src/main.rs @@ -4,7 +4,10 @@ // https://shop.m5stack.com/products/m5stack-core2-esp32-iot-development-kit use accel_device::Mpu6886Wrapper; -use display_interface_spi::SPIInterfaceNoCS; + +// use display_interface_spi::SPIInterfaceNoCS; +use spi_dma_displayinterface::spi_dma_displayinterface::SPIInterfaceNoCS; + use embedded_graphics::{ mono_font::{ascii::FONT_8X13, MonoTextStyle}, prelude::{Point, RgbColor}, @@ -14,11 +17,13 @@ use embedded_graphics::{ use hal::{ clock::{ClockControl, CpuClock}, + dma::DmaPriority, + pdma::Dma, i2c::I2C, peripherals::Peripherals, prelude::*, spi::{ - master::Spi, + master::{prelude::*, Spi}, SpiMode, }, Delay, Rng, IO, @@ -63,7 +68,9 @@ fn main() -> ! { let peripherals = Peripherals::take(); let system = peripherals.SYSTEM.split(); - let clocks = ClockControl::configure(system.clock_control, CpuClock::Clock240MHz).freeze(); + + // With DMA we have sufficient throughput, so we can clock down the CPU to 160MHz + let clocks = ClockControl::configure(system.clock_control, CpuClock::Clock160MHz).freeze(); let mut delay = Delay::new(&clocks); @@ -95,30 +102,50 @@ fn main() -> ! { } // M5Stack CORE 2 - https://docs.m5stack.com/en/core/core2 - let mut backlight = io.pins.gpio3.into_push_pull_output(); + let lcd_h_res = 240; + let lcd_v_res = 320; + + let lcd_sclk = io.pins.gpio18; + let lcd_mosi = io.pins.gpio23; + let lcd_miso = io.pins.gpio38; + let lcd_cs = io.pins.gpio5; + let lcd_dc = io.pins.gpio15.into_push_pull_output(); + let mut lcd_backlight = io.pins.gpio3.into_push_pull_output(); + let lcd_reset = io.pins.gpio4.into_push_pull_output(); + + let dma = Dma::new(system.dma); + let dma_channel = dma.spi2channel; + + let mut descriptors = [0u32; 8 * 3]; + let mut rx_descriptors = [0u32; 8 * 3]; + let spi = Spi::new( - peripherals.SPI3, - io.pins.gpio18, // SCLK - io.pins.gpio23, // MOSI - io.pins.gpio38, // MISO - io.pins.gpio5, // CS + peripherals.SPI2, + lcd_sclk, + lcd_mosi, + lcd_miso, + lcd_cs, 60u32.MHz(), SpiMode::Mode0, &clocks, - ); + ).with_dma(dma_channel.configure( + false, + &mut descriptors, + &mut rx_descriptors, + DmaPriority::Priority0, + )); - backlight.set_high().unwrap(); + lcd_backlight.set_high().unwrap(); - let reset = io.pins.gpio4.into_push_pull_output(); - let di = SPIInterfaceNoCS::new(spi, io.pins.gpio15.into_push_pull_output()); + let di = SPIInterfaceNoCS::new(spi, lcd_dc); #[cfg(feature = "m5stack_core2")] let mut display = mipidsi::Builder::ili9342c_rgb565(di) .with_display_size(320, 240) .with_color_order(mipidsi::ColorOrder::Bgr) .with_invert_colors(mipidsi::ColorInversion::Inverted) - .init(&mut delay, Some(reset)) + .init(&mut delay, Some(lcd_reset)) .unwrap(); #[cfg(feature = "wokwi")] @@ -126,7 +153,7 @@ fn main() -> ! { .with_display_size(320, 240) .with_orientation(mipidsi::Orientation::Landscape(false)) .with_color_order(mipidsi::ColorOrder::Bgr) - .init(&mut delay, Some(reset)) + .init(&mut delay, Some(lcd_reset)) .unwrap(); Text::new( @@ -164,7 +191,7 @@ fn main() -> ! { let mut seed_buffer = [0u8; 32]; rng.read(&mut seed_buffer).unwrap(); - app_loop( &mut display, seed_buffer, icm); + app_loop( &mut display, lcd_h_res, lcd_v_res, seed_buffer, icm); loop {} } diff --git a/m5stack-core2/src/setup.rs b/m5stack-core2/src/setup.rs deleted file mode 100644 index da3e331..0000000 --- a/m5stack-core2/src/setup.rs +++ /dev/null @@ -1,60 +0,0 @@ -use crate::types::{UnconfiguredPins, ConfiguredPins, ConfiguredSystemPins}; -use embedded_hal::digital::v2::{OutputPin, InputPin}; -use hal::gpio::{self, Pins}; -use spooky_embedded::{ button_keyboard::ButtonKeyboard, embedded_movement_controller::EmbeddedMovementController }; -use spooky_core; - -pub fn setup_pins(pins: Pins) -> (UnconfiguredPins, ConfiguredSystemPins) { - let unconfigured_pins = UnconfiguredPins { - sclk: pins.gpio7, - mosi: pins.gpio6, - sda: pins.gpio21, // Updated for M5Stack - scl: pins.gpio22, // Updated for M5Stack - }; - - let configured_system_pins = ConfiguredSystemPins { - dc: pins.gpio4.into_push_pull_output(), - backlight: pins.gpio45.into_push_pull_output(), - reset: pins.gpio48.into_push_pull_output(), - }; - - (unconfigured_pins, configured_system_pins) -} - -pub fn setup_button_keyboard( - pins: Pins // Passing in the Pins here, or you could pass in the ConfiguredPins if you uncomment that code -) -> ButtonKeyboard { - let configured_pins = ConfiguredPins { - up_button: pins.gpio39.into_pull_up_input(), // Button A - down_button: pins.gpio38.into_pull_up_input(), // Button B - left_button: pins.gpio37.into_pull_up_input(), // Button C - right_button: pins.gpio37.into_pull_up_input(), // Dummy example; replace appropriately - dynamite_button: pins.gpio37.into_pull_up_input(), // Dummy example; replace appropriately - teleport_button: pins.gpio37.into_pull_up_input(), // Dummy example; replace appropriately - }; - - ButtonKeyboard::new( - configured_pins.up_button, - configured_pins.down_button, - configured_pins.left_button, - configured_pins.right_button, - configured_pins.dynamite_button, - configured_pins.teleport_button, - ) -} - -pub fn setup_movement_controller( - seed_buffer: [u8; 32], - button_keyboard: ButtonKeyboard -) -> EmbeddedMovementController -where - Up: InputPin, - Down: InputPin, - Left: InputPin, - Right: InputPin, - Dyn: InputPin, - Tel: InputPin, -{ - let demo_movement_controller = spooky_core::demo_movement_controller::DemoMovementController::new(seed_buffer); - EmbeddedMovementController::new(demo_movement_controller, button_keyboard) -} diff --git a/m5stack-core2/src/types.rs b/m5stack-core2/src/types.rs deleted file mode 100644 index de9b29e..0000000 --- a/m5stack-core2/src/types.rs +++ /dev/null @@ -1,25 +0,0 @@ -use hal::gpio; -use embedded_hal::digital::v2::{ InputPin, OutputPin }; - -// Generic type for unconfigured pins -pub struct UnconfiguredPins { - pub sclk: gpio::Gpio18, // SPI Clock - pub mosi: gpio::Gpio23, // SPI Master Out Slave In - pub sda: gpio::Gpio21, // I2C Data - pub scl: gpio::Gpio22, // I2C Clock -} - -pub struct ConfiguredPins { - pub up_button: Up, // Button A - pub down_button: Down, // Button B - pub left_button: Left, // Button C - pub right_button: Right, // Button D (if applicable) - pub dynamite_button: Dyn, // Additional Custom Button (if applicable) - pub teleport_button: Tel, // Additional Custom Button (if applicable) -} - -pub struct ConfiguredSystemPins { - pub dc: Dc, // Data/Command for Display - pub backlight: Bckl, // LCD backlight control - pub reset: Reset, // Reset line for any additional modules or for LCD -} diff --git a/m5stack-fire/Cargo.toml b/m5stack-fire/Cargo.toml index 31d5d93..d7f088b 100644 --- a/m5stack-fire/Cargo.toml +++ b/m5stack-fire/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "spooky-m5stack-fire" -version = "0.7.0" +version = "0.8.0" authors = ["Juraj Michálek "] edition = "2021" license = "MIT" @@ -13,7 +13,6 @@ esp-backtrace = { version = "0.9.0", features = [ "panic-handler", "print-uart", ] } -xtensa-lx-rt = { version = "0.16.0", features = ["esp32"], optional = true } [dependencies] embedded-graphics = "0.8.0" @@ -33,7 +32,7 @@ shared-bus = { version = "0.3.0" } spooky-core = { path = "../spooky-core", default-features = false, features = [ "static_maze", ] } -heapless = { version = "0.7.14", default-features = false } +spi-dma-displayinterface = { path = "../spi-dma-displayinterface", features = [ "esp32" ] } [features] default = ["m5stack_fire"] @@ -43,13 +42,9 @@ button_controls = [] imu_controls = [] esp32 = [] -esp32s2 = ["system_timer"] -esp32s3 = [] -esp32c3 = ["system_timer"] mpu6050 = ["imu_controls", "dep:mpu6050"] mpu9250 = ["imu_controls", "dep:mpu9250"] -wokwi = [ "xtensa-lx-rt", "esp32", "mpu6050" ] - -m5stack_fire = ["xtensa-lx-rt", "esp32", "mpu9250" ] +wokwi = [ "esp32", "mpu6050" ] +m5stack_fire = [ "esp32", "mpu9250" ] diff --git a/m5stack-fire/src/main.rs b/m5stack-fire/src/main.rs index d53d9bc..581858e 100644 --- a/m5stack-fire/src/main.rs +++ b/m5stack-fire/src/main.rs @@ -3,7 +3,9 @@ // https://docs.makerfactory.io/m5stack/core/fire/ -use display_interface_spi::SPIInterfaceNoCS; +// use display_interface_spi::SPIInterfaceNoCS; +use spi_dma_displayinterface::spi_dma_displayinterface::SPIInterfaceNoCS; + use embedded_graphics::{ mono_font::{ascii::FONT_8X13, MonoTextStyle}, prelude::{DrawTarget, Point, RgbColor}, @@ -15,9 +17,11 @@ use hal::{ clock::{ClockControl, CpuClock}, i2c::I2C, peripherals::Peripherals, + dma::DmaPriority, + pdma::Dma, prelude::*, spi::{ - master::Spi, + master::{prelude::*, Spi}, SpiMode, }, Delay, Rng, IO, @@ -32,9 +36,6 @@ use mpu9250::{ImuMeasurements, Mpu9250}; #[cfg(feature = "mpu6050")] use mpu6050::Mpu6050; -#[cfg(feature = "xtensa-lx-rt")] -use xtensa_lx_rt::entry; - use embedded_graphics::pixelcolor::Rgb565; use spooky_core::{engine::Engine, spritebuf::SpriteBuf, engine::Action::{ Up, Down, Left, Right, Teleport, PlaceDynamite }}; @@ -94,35 +95,56 @@ fn main() -> ! { let peripherals = Peripherals::take(); let system = peripherals.SYSTEM.split(); - let clocks = ClockControl::configure(system.clock_control, CpuClock::Clock240MHz).freeze(); + + // With DMA we have sufficient throughput, so we can clock down the CPU to 160MHz + let clocks = ClockControl::configure(system.clock_control, CpuClock::Clock160MHz).freeze(); let mut delay = Delay::new(&clocks); let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); - let mut backlight = io.pins.gpio32.into_push_pull_output(); + let lcd_h_res = 240; + let lcd_v_res = 320; + + let lcd_sclk = io.pins.gpio18; + let lcd_mosi = io.pins.gpio23; + let lcd_miso = io.pins.gpio19; + let lcd_cs = io.pins.gpio14; + let lcd_dc = io.pins.gpio27.into_push_pull_output(); + let mut lcd_backlight = io.pins.gpio32.into_push_pull_output(); + let lcd_reset = io.pins.gpio33.into_push_pull_output(); + + let dma = Dma::new(system.dma); + let dma_channel = dma.spi2channel; + + let mut descriptors = [0u32; 8 * 3]; + let mut rx_descriptors = [0u32; 8 * 3]; let spi = Spi::new( - peripherals.SPI3, - io.pins.gpio18, // SCLK - io.pins.gpio23, // MOSI - io.pins.gpio19, // MISO - io.pins.gpio14, // CS + peripherals.SPI2, + lcd_sclk, + lcd_mosi, + lcd_miso, + lcd_cs, 60u32.MHz(), SpiMode::Mode0, &clocks, - ); + ).with_dma(dma_channel.configure( + false, + &mut descriptors, + &mut rx_descriptors, + DmaPriority::Priority0, + )); - backlight.set_high().unwrap(); + lcd_backlight.set_high().unwrap(); - let reset = io.pins.gpio33.into_push_pull_output(); - let di = SPIInterfaceNoCS::new(spi, io.pins.gpio27.into_push_pull_output()); + let di = SPIInterfaceNoCS::new(spi, lcd_dc); #[cfg(feature = "m5stack_fire")] let mut display = mipidsi::Builder::ili9341_rgb565(di) .with_display_size(320, 240) .with_color_order(mipidsi::ColorOrder::Bgr) - .init(&mut delay, Some(reset)) + .init(&mut delay, Some(lcd_reset)) .unwrap(); #[cfg(feature = "wokwi")] @@ -271,9 +293,8 @@ fn main() -> ! { universe.place_dynamite(); } } - display - .draw_iter(universe.render_frame().into_iter()) - .unwrap(); + let pixel_iterator = universe.render_frame().get_pixel_iter(); + let _ = display.set_pixels(0, 0, lcd_v_res-1, lcd_h_res, pixel_iterator); // delay.delay_ms(300u32); } } diff --git a/spi-dma-displayinterface/Cargo.toml b/spi-dma-displayinterface/Cargo.toml new file mode 100644 index 0000000..daf97b8 --- /dev/null +++ b/spi-dma-displayinterface/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "spi-dma-displayinterface" +version = "0.1.0" +edition = "2021" + +[dependencies] +byte-slice-cast = { version = "0.3.5", default-features = false } +display-interface = "0.4" +display-interface-spi = "0.4" +embedded-graphics = "0.8.0" +embedded-hal = { version = "0.2", features = ["unproven"] } +embedded-dma = "0.2.0" + +esp32-hal = { version = "0.16.0", optional = true } +esp32c3-hal = { version = "*", optional = true } +esp32c6-hal = { version = "*", optional = true } +esp32s2-hal = { version = "0.13.0", optional = true } +esp32s3-hal = { version = "0.13.0", optional = true } + +[features] +default = [] +esp32 = [ "esp32-hal" ] +esp32c3 = [ "esp32c3-hal" ] +esp32c6 = [ "esp32c6-hal" ] +esp32s2 = [ "esp32s2-hal" ] +esp32s3 = [ "esp32s3-hal" ] + diff --git a/spi-dma-displayinterface/src/lib.rs b/spi-dma-displayinterface/src/lib.rs new file mode 100644 index 0000000..daa3e82 --- /dev/null +++ b/spi-dma-displayinterface/src/lib.rs @@ -0,0 +1,2 @@ +#![cfg_attr(not(feature = "std"), no_std)] +pub mod spi_dma_displayinterface; diff --git a/spi-dma-displayinterface/src/spi_dma_displayinterface.rs b/spi-dma-displayinterface/src/spi_dma_displayinterface.rs new file mode 100644 index 0000000..c4569d5 --- /dev/null +++ b/spi-dma-displayinterface/src/spi_dma_displayinterface.rs @@ -0,0 +1,397 @@ +//! DMA SPI interface for display drivers + +use core::cell::RefCell; + +#[cfg(feature = "esp32")] +use esp32_hal as hal; +#[cfg(feature = "esp32c3")] +use esp32c3_hal as hal; +#[cfg(feature = "esp32c6")] +use esp32c6_hal as hal; +#[cfg(feature = "esp32s2")] +use esp32s2_hal as hal; +#[cfg(feature = "esp32s3")] +use esp32s3_hal as hal; + + +use display_interface::{DataFormat, DisplayError, WriteOnlyDataCommand}; +use hal::gpio::OutputPin; +use hal::spi::master::dma::SpiDmaTransfer; +use hal::spi::master::InstanceDma; +use hal::{ + dma::{ChannelTypes, SpiPeripheral}, + prelude::_esp_hal_dma_DmaTransfer, + spi::{DuplexMode, IsFullDuplex}, +}; + +const DMA_BUFFER_SIZE: usize = 2048; +type SpiDma<'d, T, C, M> = hal::spi::master::dma::SpiDma<'d, T, C, M>; + +fn send_u8<'d, T, C, M>( + spi: SpiDma<'d, T, C, M>, + words: DataFormat<'_>, +) -> Result, DisplayError> +where + T: InstanceDma, C::Rx<'d>>, + C: ChannelTypes, + C::P: SpiPeripheral, + M: DuplexMode + IsFullDuplex, +{ + match words { + DataFormat::U8(slice) => { + let send_buffer = dma_buffer1(); + send_buffer[..slice.len()].copy_from_slice(slice); + + let transfer = spi.dma_write(&send_buffer[..slice.len()]).unwrap(); + let (_, spi) = transfer.wait().unwrap(); + Ok(spi) + } + DataFormat::U16(slice) => { + use byte_slice_cast::*; + + let send_buffer = dma_buffer1(); + send_buffer[..slice.len() * 2].copy_from_slice(slice.as_byte_slice()); + + let transfer = spi.dma_write(&send_buffer[..slice.len() * 2]).unwrap(); + let (_, spi) = transfer.wait().unwrap(); + Ok(spi) + } + DataFormat::U16LE(slice) => { + use byte_slice_cast::*; + for v in slice.as_mut() { + *v = v.to_le(); + } + + let send_buffer = dma_buffer1(); + send_buffer[..slice.len() * 2].copy_from_slice(slice.as_byte_slice()); + + let transfer = spi.dma_write(&send_buffer[..slice.len() * 2]).unwrap(); + let (_, spi) = transfer.wait().unwrap(); + Ok(spi) + } + DataFormat::U16BE(slice) => { + use byte_slice_cast::*; + for v in slice.as_mut() { + *v = v.to_be(); + } + + let send_buffer = dma_buffer1(); + send_buffer[..slice.len() * 2].copy_from_slice(slice.as_byte_slice()); + + let transfer = spi.dma_write(&send_buffer[..slice.len() * 2]).unwrap(); + let (_, spi) = transfer.wait().unwrap(); + Ok(spi) + } + DataFormat::U8Iter(iter) => { + let send_buffer = dma_buffer1(); + let mut send_buffer = &mut send_buffer[..]; + let mut spi = spi; + + loop { + let mut idx = 0; + loop { + let b = iter.next(); + + match b { + Some(b) => send_buffer[idx] = b, + None => break, + } + + idx += 1; + + if idx >= DMA_BUFFER_SIZE { + break; + } + } + + if idx > 0 { + let transfer = spi.dma_write(&mut send_buffer[..idx]).unwrap(); + (send_buffer, spi) = transfer.wait().unwrap(); + } else { + break; + } + } + Ok(spi) + } + DataFormat::U16LEIter(iter) => { + let send_buffer = [ + RefCell::new(Some(&mut dma_buffer1()[..])), + RefCell::new(Some(&mut dma_buffer2()[..])), + ]; + let mut spi = Some(spi); + + let mut current_buffer = 0; + let mut transfer: Option> = None; + loop { + if let Some(transfer) = transfer { + let (relaimed_buffer, reclaimed_spi) = transfer.wait().unwrap(); + spi = Some(reclaimed_spi); + send_buffer[current_buffer].replace(Some(relaimed_buffer)); + + current_buffer = (current_buffer + 1) % send_buffer.len(); + } + + let buffer = send_buffer[current_buffer].take().unwrap(); + let mut idx = 0; + loop { + let b = iter.next(); + + match b { + Some(b) => { + let b = b.to_le_bytes(); + buffer[idx + 0] = b[0]; + buffer[idx + 1] = b[1]; + } + None => break, + } + + idx += 2; + + if idx >= DMA_BUFFER_SIZE { + break; + } + } + + if idx > 0 { + transfer = Some(spi.take().unwrap().dma_write(&mut buffer[..idx]).unwrap()); + } else { + break; + } + } + Ok(spi.unwrap()) + } + DataFormat::U16BEIter(iter) => { + let send_buffer = [ + RefCell::new(Some(&mut dma_buffer1()[..])), + RefCell::new(Some(&mut dma_buffer2()[..])), + ]; + let mut spi = Some(spi); + + let mut current_buffer = 0; + let mut transfer: Option> = None; + loop { + let buffer = send_buffer[current_buffer].take().unwrap(); + let mut idx = 0; + loop { + let b = iter.next(); + + match b { + Some(b) => { + buffer[idx + 0] = ((b & 0xff00) >> 8) as u8; + buffer[idx + 1] = (b & 0xff) as u8; + } + None => break, + } + + idx += 2; + + if idx >= DMA_BUFFER_SIZE { + break; + } + } + + if let Some(transfer) = transfer { + let (relaimed_buffer, reclaimed_spi) = transfer.wait().unwrap(); + spi = Some(reclaimed_spi); + let done_buffer = current_buffer.wrapping_sub(1) % send_buffer.len(); + send_buffer[done_buffer].replace(Some(relaimed_buffer)); + } + + if idx > 0 { + transfer = Some(spi.take().unwrap().dma_write(&mut buffer[..idx]).unwrap()); + current_buffer = (current_buffer + 1) % send_buffer.len(); + } else { + break; + } + } + Ok(spi.unwrap()) + } + _ => Err(DisplayError::DataFormatNotImplemented), + } +} + +/// SPI display interface. +/// +/// This combines the SPI peripheral and a data/command as well as a chip-select pin +pub struct SPIInterface<'d, DC, CS, T, C, M> +where + DC: OutputPin, + CS: OutputPin, + T: InstanceDma, C::Rx<'d>>, + C: ChannelTypes, + C::P: SpiPeripheral, + M: DuplexMode, +{ + spi: RefCell>>, + dc: DC, + cs: CS, +} + +#[allow(unused)] +impl<'d, DC, CS, T, C, M> SPIInterface<'d, DC, CS, T, C, M> +where + DC: OutputPin, + CS: OutputPin, + T: InstanceDma, C::Rx<'d>>, + C: ChannelTypes, + C::P: SpiPeripheral, + M: DuplexMode, +{ + pub fn new(spi: SpiDma<'d, T, C, M>, dc: DC, cs: CS) -> Self { + Self { + spi: RefCell::new(Some(spi)), + dc, + cs, + } + } + + /// Consume the display interface and return + /// the underlying peripherial driver and GPIO pins used by it + pub fn release(self) -> (SpiDma<'d, T, C, M>, DC, CS) { + (self.spi.take().unwrap(), self.dc, self.cs) + } +} + +impl<'d, DC, CS, T, C, M> WriteOnlyDataCommand for SPIInterface<'d, DC, CS, T, C, M> +where + DC: OutputPin + hal::prelude::_embedded_hal_digital_v2_OutputPin, + CS: OutputPin + hal::prelude::_embedded_hal_digital_v2_OutputPin, + T: InstanceDma, C::Rx<'d>>, + C: ChannelTypes, + C::P: SpiPeripheral, + M: DuplexMode + IsFullDuplex, +{ + fn send_commands(&mut self, cmds: DataFormat<'_>) -> Result<(), DisplayError> { + // Assert chip select pin + self.cs.set_low().map_err(|_| DisplayError::CSError)?; + + // 1 = data, 0 = command + self.dc.set_low().map_err(|_| DisplayError::DCError)?; + + // Send words over SPI + let res = send_u8(self.spi.take().unwrap(), cmds); + + // Deassert chip select pin + self.cs.set_high().ok(); + + match res { + Ok(spi) => { + self.spi.replace(Some(spi)); + Ok(()) + } + Err(err) => Err(err), + } + } + + fn send_data(&mut self, buf: DataFormat<'_>) -> Result<(), DisplayError> { + // Assert chip select pin + self.cs.set_low().map_err(|_| DisplayError::CSError)?; + + // 1 = data, 0 = command + self.dc.set_high().map_err(|_| DisplayError::DCError)?; + + // Send words over SPI + let res = send_u8(self.spi.take().unwrap(), buf); + + // Deassert chip select pin + self.cs.set_high().ok(); + + match res { + Ok(spi) => { + self.spi.replace(Some(spi)); + Ok(()) + } + Err(err) => Err(err), + } + } +} + +/// SPI display interface. +/// +/// This combines the SPI peripheral and a data/command pin +pub struct SPIInterfaceNoCS<'d, DC, T, C, M> +where + DC: OutputPin, + T: InstanceDma, C::Rx<'d>>, + C: ChannelTypes, + C::P: SpiPeripheral, + M: DuplexMode, +{ + spi: RefCell>>, + dc: DC, +} + +#[allow(unused)] +impl<'d, DC, T, C, M> SPIInterfaceNoCS<'d, DC, T, C, M> +where + DC: OutputPin, + T: InstanceDma, C::Rx<'d>>, + C: ChannelTypes, + C::P: SpiPeripheral, + M: DuplexMode, +{ + /// Create new SPI interface for communciation with a display driver + pub fn new(spi: SpiDma<'d, T, C, M>, dc: DC) -> Self { + Self { + spi: RefCell::new(Some(spi)), + dc, + } + } + + /// Consume the display interface and return + /// the underlying peripherial driver and GPIO pins used by it + pub fn release(self) -> (SpiDma<'d, T, C, M>, DC) { + (self.spi.take().unwrap(), self.dc) + } +} + +impl<'d, DC, T, C, M> WriteOnlyDataCommand for SPIInterfaceNoCS<'d, DC, T, C, M> +where + DC: OutputPin + hal::prelude::_embedded_hal_digital_v2_OutputPin, + T: InstanceDma, C::Rx<'d>>, + C: ChannelTypes, + C::P: SpiPeripheral, + M: DuplexMode + IsFullDuplex, +{ + fn send_commands(&mut self, cmds: DataFormat<'_>) -> Result<(), DisplayError> { + // 1 = data, 0 = command + self.dc.set_low().map_err(|_| DisplayError::DCError)?; + + // Send words over SPI + let res = send_u8(self.spi.take().unwrap(), cmds); + + match res { + Ok(spi) => { + self.spi.replace(Some(spi)); + Ok(()) + } + Err(err) => Err(err), + } + } + + fn send_data(&mut self, buf: DataFormat<'_>) -> Result<(), DisplayError> { + // 1 = data, 0 = command + self.dc.set_high().map_err(|_| DisplayError::DCError)?; + + // Send words over SPI + let res = send_u8(self.spi.take().unwrap(), buf); + + match res { + Ok(spi) => { + self.spi.replace(Some(spi)); + Ok(()) + } + Err(err) => Err(err), + } + } +} + +fn dma_buffer1() -> &'static mut [u8; DMA_BUFFER_SIZE] { + static mut BUFFER: [u8; DMA_BUFFER_SIZE] = [0u8; DMA_BUFFER_SIZE]; + unsafe { &mut BUFFER } +} + +fn dma_buffer2() -> &'static mut [u8; DMA_BUFFER_SIZE] { + static mut BUFFER: [u8; DMA_BUFFER_SIZE] = [0u8; DMA_BUFFER_SIZE]; + unsafe { &mut BUFFER } +} diff --git a/spooky-core/src/assets.rs b/spooky-core/src/assets.rs index f3be05d..9b4a1ba 100644 --- a/spooky-core/src/assets.rs +++ b/spooky-core/src/assets.rs @@ -1,7 +1,4 @@ - -use embedded_graphics::{ - pixelcolor::Rgb565, -}; +use embedded_graphics::pixelcolor::Rgb565; use tinybmp::Bmp; pub struct Assets<'a> { @@ -42,19 +39,38 @@ impl Assets<'static> { } pub fn load(&mut self) { - self.ground = Some(Bmp::::from_slice(include_bytes!("../../assets/img/ground.bmp")).unwrap()); - self.wall = Some(Bmp::::from_slice(include_bytes!("../../assets/img/wall.bmp")).unwrap()); - self.empty = Some(Bmp::::from_slice(include_bytes!("../../assets/img/empty.bmp")).unwrap()); - self.ghost1 = Some(Bmp::::from_slice(include_bytes!("../../assets/img/ghost1.bmp")).unwrap()); - self.ghost2 = Some(Bmp::::from_slice(include_bytes!("../../assets/img/ghost2.bmp")).unwrap()); - self.coin = Some(Bmp::::from_slice(include_bytes!("../../assets/img/coin.bmp")).unwrap()); - self.dynamite = Some(Bmp::::from_slice(include_bytes!("../../assets/img/dynamite.bmp")).unwrap()); - self.explosion1 = Some(Bmp::::from_slice(include_bytes!("../../assets/img/explosion1.bmp")).unwrap()); - self.explosion2 = Some(Bmp::::from_slice(include_bytes!("../../assets/img/explosion2.bmp")).unwrap()); - self.scorched = Some(Bmp::::from_slice(include_bytes!("../../assets/img/scorched.bmp")).unwrap()); - self.npc = Some(Bmp::::from_slice(include_bytes!("../../assets/img/npc.bmp")).unwrap()); - self.teleport = Some(Bmp::::from_slice(include_bytes!("../../assets/img/teleport.bmp")).unwrap()); - self.walker = Some(Bmp::::from_slice(include_bytes!("../../assets/img/walker.bmp")).unwrap()); - self.smiley = Some(Bmp::::from_slice(include_bytes!("../../assets/img/smiley.bmp")).unwrap()); + self.ground = + Some(Bmp::::from_slice(include_bytes!("../../assets/img/ground.bmp")).unwrap()); + self.wall = + Some(Bmp::::from_slice(include_bytes!("../../assets/img/wall.bmp")).unwrap()); + self.empty = + Some(Bmp::::from_slice(include_bytes!("../../assets/img/empty.bmp")).unwrap()); + self.ghost1 = + Some(Bmp::::from_slice(include_bytes!("../../assets/img/ghost1.bmp")).unwrap()); + self.ghost2 = + Some(Bmp::::from_slice(include_bytes!("../../assets/img/ghost2.bmp")).unwrap()); + self.coin = + Some(Bmp::::from_slice(include_bytes!("../../assets/img/coin.bmp")).unwrap()); + self.dynamite = Some( + Bmp::::from_slice(include_bytes!("../../assets/img/dynamite.bmp")).unwrap(), + ); + self.explosion1 = Some( + Bmp::::from_slice(include_bytes!("../../assets/img/explosion1.bmp")).unwrap(), + ); + self.explosion2 = Some( + Bmp::::from_slice(include_bytes!("../../assets/img/explosion2.bmp")).unwrap(), + ); + self.scorched = Some( + Bmp::::from_slice(include_bytes!("../../assets/img/scorched.bmp")).unwrap(), + ); + self.npc = + Some(Bmp::::from_slice(include_bytes!("../../assets/img/npc.bmp")).unwrap()); + self.teleport = Some( + Bmp::::from_slice(include_bytes!("../../assets/img/teleport.bmp")).unwrap(), + ); + self.walker = + Some(Bmp::::from_slice(include_bytes!("../../assets/img/walker.bmp")).unwrap()); + self.smiley = + Some(Bmp::::from_slice(include_bytes!("../../assets/img/smiley.bmp")).unwrap()); } } diff --git a/spooky-core/src/demo_movement_controller.rs b/spooky-core/src/demo_movement_controller.rs index 9e28a63..ab947c0 100644 --- a/spooky-core/src/demo_movement_controller.rs +++ b/spooky-core/src/demo_movement_controller.rs @@ -18,23 +18,19 @@ impl DemoMovementController { } } - fn get_rand(&mut self, max_range:i32) -> i32 { + fn get_rand(&mut self, max_range: i32) -> i32 { self.rng.gen_range(0..max_range) } - } impl MovementController for DemoMovementController { - - fn set_active(&mut self, _index:usize) { - } + fn set_active(&mut self, _index: usize) {} fn get_movement(&self) -> Action { self.last_action } fn tick(&mut self) { - if self.steps_remaining > 0 { self.steps_remaining -= 1; return; @@ -50,6 +46,4 @@ impl MovementController for DemoMovementController { _ => Action::None, }; } - - } diff --git a/spooky-core/src/engine.rs b/spooky-core/src/engine.rs index a28b7ea..7283e1a 100644 --- a/spooky-core/src/engine.rs +++ b/spooky-core/src/engine.rs @@ -1,15 +1,10 @@ - - use embedded_graphics::{ + image::Image, + mono_font::{ascii::FONT_8X13, MonoTextStyle}, + pixelcolor::Rgb565, prelude::{Point, RgbColor}, - mono_font::{ - ascii::FONT_8X13, - MonoTextStyle, - }, text::Text, - pixelcolor::Rgb565, Drawable, - image::Image, }; use crate::{assets::Assets, maze::Maze}; @@ -56,13 +51,12 @@ pub struct Engine { outro_counter: u32, } - -impl > Engine { - pub fn new(display:D, seed: Option<[u8; 32]>) -> Engine { +impl> Engine { + pub fn new(display: D, seed: Option<[u8; 32]>) -> Engine { Engine { start_time: 0, - ghost_x: 9*16, - ghost_y: 7*16, + ghost_x: 9 * 16, + ghost_y: 7 * 16, display, assets: None, step_size_x: 16, @@ -91,7 +85,7 @@ impl > Engine { if self.maze.coin_counter == 0 { self.game_state = GameState::Outro; } - }, + } None => {} } @@ -102,7 +96,7 @@ impl > Engine { if self.walker_counter < 10000 { self.walker_counter += 100; } - }, + } None => {} } @@ -113,7 +107,7 @@ impl > Engine { if self.dynamite_counter < 10000 { self.dynamite_counter += 1; } - }, + } None => {} } } @@ -135,7 +129,7 @@ impl > Engine { Some(_npc) => { self.relocate_coins(5); self.relocate_avatar(); - }, + } None => {} } } @@ -151,31 +145,27 @@ impl > Engine { pub fn action(&mut self, action: Action) { match self.game_state { - GameState::Demo => { - match action { - Action::None => {} - Action::Up => self.move_up(), - Action::Down => self.move_down(), - Action::Left => self.move_left(), - Action::Right => self.move_right(), - Action::Teleport => self.teleport(), - Action::PlaceDynamite => self.place_dynamite(), - Action::Start => self.switch_game_state(GameState::Playing), - _ => {} - } + GameState::Demo => match action { + Action::None => {} + Action::Up => self.move_up(), + Action::Down => self.move_down(), + Action::Left => self.move_left(), + Action::Right => self.move_right(), + Action::Teleport => self.teleport(), + Action::PlaceDynamite => self.place_dynamite(), + Action::Start => self.switch_game_state(GameState::Playing), + _ => {} }, - GameState::Playing => { - match action { - Action::None => {} - Action::Up => self.move_up(), - Action::Down => self.move_down(), - Action::Left => self.move_left(), - Action::Right => self.move_right(), - Action::Teleport => self.teleport(), - Action::PlaceDynamite => self.place_dynamite(), - Action::Stop => self.switch_game_state(GameState::Demo), - _ => {} - } + GameState::Playing => match action { + Action::None => {} + Action::Up => self.move_up(), + Action::Down => self.move_down(), + Action::Left => self.move_left(), + Action::Right => self.move_right(), + Action::Teleport => self.teleport(), + Action::PlaceDynamite => self.place_dynamite(), + Action::Stop => self.switch_game_state(GameState::Demo), + _ => {} }, GameState::Outro => { if self.outro_counter > 30 { @@ -183,7 +173,7 @@ impl > Engine { self.outro_counter = 0; self.start(); } - }, + } _ => {} } } @@ -232,7 +222,8 @@ impl > Engine { return; } - self.maze.place_dynamite(self.camera_x + self.ghost_x, self.camera_y + self.ghost_y); + self.maze + .place_dynamite(self.camera_x + self.ghost_x, self.camera_y + self.ghost_y); self.dynamite_counter -= 1; } @@ -248,26 +239,30 @@ impl > Engine { let camera_tile_x = camera_x / self.maze.tile_width as i32; let camera_tile_y = camera_y / self.maze.tile_height as i32; - for x in camera_tile_x..(camera_tile_x + (self.maze.visible_width as i32)-1) { - for y in camera_tile_y..(camera_tile_y + (self.maze.visible_height as i32)-1) { + for x in camera_tile_x..(camera_tile_x + (self.maze.visible_width as i32) - 1) { + for y in camera_tile_y..(camera_tile_y + (self.maze.visible_height as i32) - 1) { let position_x = (x as i32 * self.maze.tile_width as i32) - camera_x; let position_y = (y as i32 * self.maze.tile_height as i32) - camera_y; let position = Point::new(position_x, position_y); - if x < 0 || y < 0 || x > (self.maze.width-1) as i32 || y > (self.maze.height-1) as i32 { + if x < 0 + || y < 0 + || x > (self.maze.width - 1) as i32 + || y > (self.maze.height - 1) as i32 + { let tile = Image::new(empty, position); let _ = tile.draw(&mut self.display); } else { - let tile_index = self.maze.data[(x+y*(self.maze.width as i32)) as usize]; + let tile_index = self.maze.data[(x + y * (self.maze.width as i32)) as usize]; match tile_index { 0 => { let tile = Image::new(ground, position); let _ = tile.draw(&mut self.display); - }, + } 1 => { let tile = Image::new(wall, position); let _ = tile.draw(&mut self.display); - }, + } _ => { let tile = Image::new(scorched, position); let _ = tile.draw(&mut self.display); @@ -278,11 +273,9 @@ impl > Engine { } } - pub fn tick(&mut self) { match self.game_state { GameState::Playing | GameState::Demo => { - self.animation_step += 1; if self.animation_step > 1 { self.animation_step = 0; @@ -300,12 +293,12 @@ impl > Engine { self.maze.move_npcs(); self.check_npc_collision(); - }, + } GameState::Outro => { if self.outro_counter < 1000 { self.outro_counter += 1; } - }, + } _ => {} } } @@ -323,7 +316,7 @@ impl > Engine { self.maze.generate_npcs(); self.maze.generate_walkers(); self.maze.generate_dynamites(); - self.draw_maze(self.camera_x,self.camera_y); + self.draw_maze(self.camera_x, self.camera_y); self.game_state = GameState::Demo; } @@ -333,18 +326,20 @@ impl > Engine { fn draw_status_number(&mut self, value: u32, x: i32, y: i32) { let value_message: String<5> = String::from(value); - let _ = Text::new(&value_message, Point::new(x, y), MonoTextStyle::new(&FONT_8X13, Rgb565::WHITE)) - .draw(&mut self.display); + let _ = Text::new( + &value_message, + Point::new(x, y), + MonoTextStyle::new(&FONT_8X13, Rgb565::WHITE), + ) + .draw(&mut self.display); } pub fn draw_main_scene(&mut self) -> &mut D { - self.draw_maze(self.camera_x,self.camera_y); - + self.draw_maze(self.camera_x, self.camera_y); match self.assets { Some(ref mut assets) => { - - let coin_bmp:Bmp = assets.coin.unwrap(); + let coin_bmp: Bmp = assets.coin.unwrap(); for index in 0..100 { let coin = self.maze.coins[index]; if coin.x < 0 || coin.y < 0 { @@ -353,14 +348,18 @@ impl > Engine { let draw_x = coin.x - self.camera_x; let draw_y = coin.y - self.camera_y; - if draw_x >= 0 && draw_y >= 0 && draw_x < (self.maze.visible_width*16).try_into().unwrap() && draw_y < (self.maze.visible_height*16).try_into().unwrap() { + if draw_x >= 0 + && draw_y >= 0 + && draw_x < (self.maze.visible_width * 16).try_into().unwrap() + && draw_y < (self.maze.visible_height * 16).try_into().unwrap() + { let position = Point::new(draw_x, draw_y); let tile = Image::new(&coin_bmp, position); let _ = tile.draw(&mut self.display); } } - let npc_bmp:Bmp = assets.npc.unwrap(); + let npc_bmp: Bmp = assets.npc.unwrap(); for index in 0..5 { let item = self.maze.npcs[index]; if item.x < 0 || item.y < 0 { @@ -369,14 +368,18 @@ impl > Engine { let draw_x = item.x - self.camera_x; let draw_y = item.y - self.camera_y; - if draw_x >= 0 && draw_y >= 0 && draw_x < (self.maze.visible_width*16).try_into().unwrap() && draw_y < (self.maze.visible_height*16).try_into().unwrap() { + if draw_x >= 0 + && draw_y >= 0 + && draw_x < (self.maze.visible_width * 16).try_into().unwrap() + && draw_y < (self.maze.visible_height * 16).try_into().unwrap() + { let position = Point::new(draw_x, draw_y); let tile = Image::new(&npc_bmp, position); let _ = tile.draw(&mut self.display); } } - let walker_bmp:Bmp = assets.walker.unwrap(); + let walker_bmp: Bmp = assets.walker.unwrap(); for index in 0..5 { let item = self.maze.walkers[index]; if item.x < 0 || item.y < 0 { @@ -385,14 +388,18 @@ impl > Engine { let draw_x = item.x - self.camera_x; let draw_y = item.y - self.camera_y; - if draw_x >= 0 && draw_y >= 0 && draw_x < (self.maze.visible_width*16).try_into().unwrap() && draw_y < (self.maze.visible_height*16).try_into().unwrap() { + if draw_x >= 0 + && draw_y >= 0 + && draw_x < (self.maze.visible_width * 16).try_into().unwrap() + && draw_y < (self.maze.visible_height * 16).try_into().unwrap() + { let position = Point::new(draw_x, draw_y); let tile = Image::new(&walker_bmp, position); let _ = tile.draw(&mut self.display); } } - let dynamite_bmp:Bmp = assets.dynamite.unwrap(); + let dynamite_bmp: Bmp = assets.dynamite.unwrap(); for index in 0..1 { let item = self.maze.dynamites[index]; if item.x < 0 || item.y < 0 { @@ -401,7 +408,11 @@ impl > Engine { let draw_x = item.x - self.camera_x; let draw_y = item.y - self.camera_y; - if draw_x >= 0 && draw_y >= 0 && draw_x < (self.maze.visible_width*16).try_into().unwrap() && draw_y < (self.maze.visible_height*16).try_into().unwrap() { + if draw_x >= 0 + && draw_y >= 0 + && draw_x < (self.maze.visible_width * 16).try_into().unwrap() + && draw_y < (self.maze.visible_height * 16).try_into().unwrap() + { let position = Point::new(draw_x, draw_y); let tile = Image::new(&dynamite_bmp, position); let _ = tile.draw(&mut self.display); @@ -410,16 +421,27 @@ impl > Engine { match self.animation_step { 0 => { - let bmp:Bmp = assets.ghost1.unwrap(); - let ghost1 = Image::new(&bmp, Point::new(self.ghost_x.try_into().unwrap(), self.ghost_y.try_into().unwrap())); + let bmp: Bmp = assets.ghost1.unwrap(); + let ghost1 = Image::new( + &bmp, + Point::new( + self.ghost_x.try_into().unwrap(), + self.ghost_y.try_into().unwrap(), + ), + ); let _ = ghost1.draw(&mut self.display); - }, + } _ => { - let bmp:Bmp = assets.ghost2.unwrap(); - let ghost2 = Image::new(&bmp, Point::new(self.ghost_x.try_into().unwrap(), self.ghost_y.try_into().unwrap())); + let bmp: Bmp = assets.ghost2.unwrap(); + let ghost2 = Image::new( + &bmp, + Point::new( + self.ghost_x.try_into().unwrap(), + self.ghost_y.try_into().unwrap(), + ), + ); let _ = ghost2.draw(&mut self.display); - }, - + } } // Status bar - coins, teleport, walk time, dynamite @@ -427,24 +449,23 @@ impl > Engine { let tile = Image::new(&coin_bmp, position); let _ = tile.draw(&mut self.display); - let teleport_bmp:Bmp = assets.teleport.unwrap(); + let teleport_bmp: Bmp = assets.teleport.unwrap(); let position = Point::new(5, 28); let tile = Image::new(&teleport_bmp, position); let _ = tile.draw(&mut self.display); - let walker_bmp:Bmp = assets.walker.unwrap(); + let walker_bmp: Bmp = assets.walker.unwrap(); let position = Point::new(5, 50); let tile = Image::new(&walker_bmp, position); let _ = tile.draw(&mut self.display); - let dynamite_bmp:Bmp = assets.dynamite.unwrap(); + let dynamite_bmp: Bmp = assets.dynamite.unwrap(); let position = Point::new(5, 72); let tile = Image::new(&dynamite_bmp, position); let _ = tile.draw(&mut self.display); - // display.flush().unwrap(); - }, + } None => { panic!("Assets not loaded"); } @@ -459,15 +480,22 @@ impl > Engine { } pub fn draw_demo_text(&mut self) -> &mut D { - let _ = Text::new("Demo. Press any key...", Point::new(80, 150), MonoTextStyle::new(&FONT_8X13, Rgb565::WHITE)) - .draw(&mut self.display); + let _ = Text::new( + "Demo. Press any key...", + Point::new(80, 150), + MonoTextStyle::new(&FONT_8X13, Rgb565::WHITE), + ) + .draw(&mut self.display); &mut self.display } pub fn draw_outro_scene(&mut self) -> &mut D { let assets = self.assets.as_ref().unwrap(); - let bmp:Bmp = assets.smiley.unwrap(); - let (x,y) = (self.maze.get_rand() + self.maze.get_rand() % 70, self.maze.get_rand() % 240); + let bmp: Bmp = assets.smiley.unwrap(); + let (x, y) = ( + self.maze.get_rand() + self.maze.get_rand() % 70, + self.maze.get_rand() % 240, + ); let outro = Image::new(&bmp, Point::new(x, y)); let _ = outro.draw(&mut self.display); &mut self.display @@ -478,20 +506,10 @@ impl > Engine { GameState::Demo => { self.draw_main_scene(); self.draw_demo_text() - }, - GameState::Playing => { - self.draw_main_scene() - }, - GameState::Outro => { - self.draw_outro_scene() - }, - _ => { - &mut self.display } + GameState::Playing => self.draw_main_scene(), + GameState::Outro => self.draw_outro_scene(), + _ => &mut self.display, } } - - } - - diff --git a/spooky-core/src/maze.rs b/spooky-core/src/maze.rs index cccf8ef..66cef1f 100644 --- a/spooky-core/src/maze.rs +++ b/spooky-core/src/maze.rs @@ -24,13 +24,12 @@ pub struct Npc { pub vector_y: i32, } - pub struct Maze { pub width: u32, pub height: u32, pub visible_width: u32, pub visible_height: u32, - pub data: [u8; 64*64], + pub data: [u8; 64 * 64], pub coins: [Coin; 100], pub coin_counter: u32, pub npcs: [Npc; 5], @@ -51,84 +50,172 @@ impl Maze { visible_width: 21, visible_height: 16, #[cfg(feature = "dynamic_maze")] - data: [1; 64*64], + data: [1; 64 * 64], #[cfg(feature = "static_maze")] - data: [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,1, - 1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1, - 1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,1,1, - 1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1, - 1,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,1, - 1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,1, - 1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,1,1, - 1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1, - 1,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,1, - 1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1, - 1,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,1,1, - 1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1, - 1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,1,1, - 1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1, - 1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,1, - 1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1, - 1,0,1,0,0,0,0,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,1, - 1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,1, - 1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,1, - 1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,1, - 1,0,0,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,1, - 1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1, - 1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,1, - 1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,1, - 1,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,1,1, - 1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,1, - 1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1,1, - 1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1, - 1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,1, - 1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1, - 1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,1, - 1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1, - 1,0,0,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,1, - 1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1, - 1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,1,1, - 1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,1, - 1,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,1, - 1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,1, - 1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,1,1, - 1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1, - 1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,1,1, - 1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,1, - 1,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,1,1, - 1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1, - 1,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,1,1, - 1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1, - 1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,1,1, - 1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,1, - 1,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,1,1, - 1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,1, - 1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,1, - 1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1, - 1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,1,1, - 1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,1, - 1,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,1,1, - 1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,1, - 1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,1, - 1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,1, - 1,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,1,1, - 1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,1, - 1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,1, - 1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,1, - 1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1 + data: [ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, + 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, + 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, + 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, + 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, + 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, + 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, + 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, + 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, + 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, + 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, + 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, + 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, + 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, + 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, + 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, + 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, + 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, + 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, + 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, + 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, + 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, + 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, + 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, + 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, + 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, + 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, + 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, + 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, + 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, + 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, + 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, + 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, + 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, + 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, + 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, + 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, + 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, + 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, + 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, + 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, + 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, + 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, + 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, + 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, + 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, + 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, + 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, + 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, + 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, + 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, + 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, + 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, + 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, + 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, + 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, + 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, + 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, + 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, + 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, + 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, + 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, + 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, + 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, + 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, + 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, + 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, + 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, + 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, + 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, + 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, + 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, + 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, + 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, + 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, + 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, + 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 1, 1, ], - - offset: width+1, + offset: width + 1, tile_width: 16, tile_height: 16, - coins: [Coin {x: -1, y: -1}; 100], + coins: [Coin { x: -1, y: -1 }; 100], coin_counter: 100, - npcs: [Npc {x: -1, y: -1, vector_x: 0, vector_y: 0}; 5], - walkers: [Coin {x: -1, y: -1}; 5], - dynamites: [Coin {x: -1, y: -1}; 1], - rng: match seed { + npcs: [Npc { + x: -1, + y: -1, + vector_x: 0, + vector_y: 0, + }; 5], + walkers: [Coin { x: -1, y: -1 }; 5], + dynamites: [Coin { x: -1, y: -1 }; 1], + rng: match seed { // None => ChaChaRng::from_entropy(), - from_entropy is not present in latest rand None => ChaChaRng::from_seed([42; 32]), Some(seed) => ChaChaRng::from_seed(seed), @@ -141,14 +228,22 @@ impl Maze { } pub fn check_boundary_collision(&self, x: i32, y: i32) -> bool { - if x < 0 || y < 0 || x >= (self.width * self.tile_width) as i32 || y >= (self.height * self.tile_height) as i32 { + if x < 0 + || y < 0 + || x >= (self.width * self.tile_width) as i32 + || y >= (self.height * self.tile_height) as i32 + { return true; } false } pub fn check_wall_collision(&self, x: i32, y: i32) -> bool { - if x < 0 || y < 0 || x >= (self.width * self.tile_width) as i32 || y >= (self.height * self.tile_height) as i32 { + if x < 0 + || y < 0 + || x >= (self.width * self.tile_width) as i32 + || y >= (self.height * self.tile_height) as i32 + { return true; } let tile_x = x / self.tile_width as i32; @@ -168,14 +263,13 @@ impl Maze { } pub fn generate_coins(&mut self) { - for index in 0..100 { (self.coins[index].x, self.coins[index].y) = self.get_random_coordinates(); } self.coin_counter = 100; } - pub fn relocate_coins(&mut self, amount:u32) { + pub fn relocate_coins(&mut self, amount: u32) { let mut relocate_counter = 0; for index in 0..100 { if self.coins[index].x == -1 && self.coins[index].y == -1 { @@ -323,14 +417,13 @@ impl Maze { } #[cfg(feature = "static_maze")] - pub fn generate_maze(&mut self, _graph_width: usize, _graph_height: usize) { - } + pub fn generate_maze(&mut self, _graph_width: usize, _graph_height: usize) {} #[cfg(feature = "dynamic_maze")] pub fn generate_maze(&mut self, graph_width: usize, graph_height: usize) { // let mut rng = Rng::new(peripherals.RNG); // let mut rng = Rng::new( 0x12345678 ); - let seed_buffer = [0u8;32]; + let seed_buffer = [0u8; 32]; // match &self.rng { // Some(rng) => rng.fill_bytes(&mut seed_buffer), // None => {} @@ -339,12 +432,17 @@ impl Maze { // getrandom::getrandom(&mut seed_buffer).unwrap(); let mut generator = RbGenerator::new(Some(seed_buffer)); - let maze_graph = generator.generate(graph_width as i32, graph_height as i32).unwrap(); + let maze_graph = generator + .generate(graph_width as i32, graph_height as i32) + .unwrap(); for y in 1usize..graph_height { for x in 1usize..graph_width { - let field = maze_graph.get_field(&(x.try_into().unwrap(),y.try_into().unwrap()).into()).unwrap(); - let tile_index = (x-1)*2+(y-1)*2*(self.width as usize)+(self.offset as usize); + let field = maze_graph + .get_field(&(x.try_into().unwrap(), y.try_into().unwrap()).into()) + .unwrap(); + let tile_index = + (x - 1) * 2 + (y - 1) * 2 * (self.width as usize) + (self.offset as usize); self.data[tile_index] = 0; @@ -357,6 +455,5 @@ impl Maze { } } } - } } diff --git a/spooky-core/src/movement_controller.rs b/spooky-core/src/movement_controller.rs index d0540e9..7507557 100644 --- a/spooky-core/src/movement_controller.rs +++ b/spooky-core/src/movement_controller.rs @@ -1,7 +1,7 @@ use crate::engine::Action; pub trait MovementController { - fn set_active(&mut self, index:usize); + fn set_active(&mut self, index: usize); fn tick(&mut self); fn get_movement(&self) -> Action; } diff --git a/spooky-core/src/nomovement_controller.rs b/spooky-core/src/nomovement_controller.rs index edbb38a..b3b0b45 100644 --- a/spooky-core/src/nomovement_controller.rs +++ b/spooky-core/src/nomovement_controller.rs @@ -12,10 +12,9 @@ impl NoMovementController { impl MovementController for NoMovementController { fn tick(&mut self) {} - fn set_active(&mut self, _index:usize) { - } + fn set_active(&mut self, _index: usize) {} fn get_movement(&self) -> Action { Action::None } -} \ No newline at end of file +} diff --git a/spooky-core/src/spritebuf.rs b/spooky-core/src/spritebuf.rs index 0eda2e4..b4628dc 100644 --- a/spooky-core/src/spritebuf.rs +++ b/spooky-core/src/spritebuf.rs @@ -1,13 +1,13 @@ // Based on https://github.com/bernii/embedded-graphics-framebuf +use embedded_graphics::pixelcolor::Rgb565; use embedded_graphics::{ - prelude::{RgbColor}, - prelude::{Point, DrawTarget, Size}, geometry::OriginDimensions, + prelude::RgbColor, + prelude::{DrawTarget, Point, Size}, Pixel, }; -use embedded_graphics::{pixelcolor::Rgb565}; -use embedded_graphics_framebuf::{FrameBuf, backends::FrameBufferBackend, PixelIterator}; +use embedded_graphics_framebuf::{backends::FrameBufferBackend, FrameBuf, PixelIterator}; pub struct SpriteBuf> { pub fbuf: FrameBuf, @@ -20,10 +20,8 @@ impl> OriginDimensions for SpriteBuf { } impl> SpriteBuf { - pub fn new(fbuf:FrameBuf) -> Self { - Self { - fbuf, - } + pub fn new(fbuf: FrameBuf) -> Self { + Self { fbuf } } /// Get the framebuffers width. @@ -49,7 +47,7 @@ impl> SpriteBuf { impl<'a, B: FrameBufferBackend> IntoIterator for &'a SpriteBuf { type Item = Pixel; - type IntoIter = PixelIterator<'a, Rgb565, B>; + type IntoIter = PixelIterator<'a, Rgb565, B>; fn into_iter(self) -> Self::IntoIter { self.fbuf.into_iter() @@ -79,3 +77,21 @@ impl> DrawTarget for SpriteBuf { Ok(()) } } + +// impl SpriteBuf +// where +// B: FrameBufferBackend, +// { +// pub fn get_pixel_iter(&self) -> impl Iterator> + '_ { +// self.fbuf.into_iter() +// } +// } + +impl SpriteBuf +where + B: FrameBufferBackend, +{ + pub fn get_pixel_iter(&self) -> impl Iterator + '_ { + self.fbuf.into_iter().map(|pixel| pixel.1) + } +} diff --git a/spooky-core/src/universe.rs b/spooky-core/src/universe.rs index cc4feaa..4404c95 100644 --- a/spooky-core/src/universe.rs +++ b/spooky-core/src/universe.rs @@ -1,9 +1,6 @@ -use crate::engine::{Engine, Action}; +use crate::engine::{Action, Engine}; use crate::movement_controller::MovementController; -use embedded_graphics::{ - prelude::DrawTarget, - pixelcolor::Rgb565, -}; +use embedded_graphics::{pixelcolor::Rgb565, prelude::DrawTarget}; pub struct Universe where @@ -22,7 +19,7 @@ impl, M: MovementController> Universe { } } - pub fn set_active(&mut self, index:usize) { + pub fn set_active(&mut self, index: usize) { self.movement_controller.set_active(index); } diff --git a/spooky-embedded/src/button_keyboard.rs b/spooky-embedded/src/button_keyboard.rs index a11bf33..58dfca4 100644 --- a/spooky-embedded/src/button_keyboard.rs +++ b/spooky-embedded/src/button_keyboard.rs @@ -11,7 +11,14 @@ pub enum ButtonEvent { NoEvent, } -pub struct ButtonKeyboard { +pub struct ButtonKeyboard< + Up: InputPin, + Down: InputPin, + Left: InputPin, + Right: InputPin, + Dyn: InputPin, + Tel: InputPin, +> { pub up_button: Up, pub down_button: Down, pub left_button: Left, @@ -29,7 +36,14 @@ where Dy: InputPin, T: InputPin, { - pub fn new(up_button: U, down_button: D, left_button: L, right_button: R, dynamite_button: Dy, teleport_button: T) -> Self { + pub fn new( + up_button: U, + down_button: D, + left_button: L, + right_button: R, + dynamite_button: Dy, + teleport_button: T, + ) -> Self { Self { up_button, down_button, diff --git a/spooky-embedded/src/button_movement_controller.rs b/spooky-embedded/src/button_movement_controller.rs index 48b2dbe..47698ff 100644 --- a/spooky-embedded/src/button_movement_controller.rs +++ b/spooky-embedded/src/button_movement_controller.rs @@ -28,8 +28,7 @@ impl ButtonMovementController { } impl MovementController for ButtonMovementController { - fn set_active(&mut self, _index: usize) { - } + fn set_active(&mut self, _index: usize) {} fn get_movement(&self) -> Action { self.last_action diff --git a/spooky-embedded/src/embedded_movement_controller.rs b/spooky-embedded/src/embedded_movement_controller.rs index 5b05e34..cceb2c5 100644 --- a/spooky-embedded/src/embedded_movement_controller.rs +++ b/spooky-embedded/src/embedded_movement_controller.rs @@ -1,8 +1,8 @@ -use spooky_core::movement_controller::MovementController; -use spooky_core::engine::Action; -use spooky_core::demo_movement_controller::DemoMovementController; use crate::button_keyboard::{ButtonEvent, ButtonKeyboard}; use embedded_hal::digital::v2::InputPin; +use spooky_core::demo_movement_controller::DemoMovementController; +use spooky_core::engine::Action; +use spooky_core::movement_controller::MovementController; pub struct EmbeddedMovementController where @@ -58,7 +58,8 @@ where } } -impl MovementController for EmbeddedMovementController +impl MovementController + for EmbeddedMovementController where Up: InputPin, Down: InputPin, @@ -76,9 +77,9 @@ where self.last_action = Action::Start; } self.demo_movement_controller.tick(); - }, + } 1 => self.poll_keyboard(), - _ => {}, + _ => {} } } @@ -97,5 +98,4 @@ where fn set_active(&mut self, index: usize) { self.active_index = index; } - } diff --git a/spooky-embedded/src/lib.rs b/spooky-embedded/src/lib.rs index 1644ed2..6519914 100644 --- a/spooky-embedded/src/lib.rs +++ b/spooky-embedded/src/lib.rs @@ -1,4 +1,4 @@ #![cfg_attr(not(feature = "std"), no_std)] pub mod button_keyboard; pub mod button_movement_controller; -pub mod embedded_movement_controller; \ No newline at end of file +pub mod embedded_movement_controller;