diff --git a/mipidsi/examples/spi-st7789-rpi-zero-w/.cargo/config.toml b/mipidsi/examples/spi-st7789-rpi-zero-w/.cargo/config.toml new file mode 100644 index 0000000..6fb7d4c --- /dev/null +++ b/mipidsi/examples/spi-st7789-rpi-zero-w/.cargo/config.toml @@ -0,0 +1,2 @@ +[target.arm-unknown-linux-musleabihf] +linker = "arm-linux-musleabihf-gcc" diff --git a/mipidsi/examples/spi-st7789-rpi-zero-w/.gitignore b/mipidsi/examples/spi-st7789-rpi-zero-w/.gitignore new file mode 100644 index 0000000..96ef6c0 --- /dev/null +++ b/mipidsi/examples/spi-st7789-rpi-zero-w/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/mipidsi/examples/spi-st7789-rpi-zero-w/Cargo.toml b/mipidsi/examples/spi-st7789-rpi-zero-w/Cargo.toml new file mode 100644 index 0000000..e28c5a8 --- /dev/null +++ b/mipidsi/examples/spi-st7789-rpi-zero-w/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "spi-st7789-rpi-zero-w" +version = "0.1.0" +edition = "2021" + +[dependencies] +display-interface-spi = "0.4.1" +embedded-graphics = "0.8.0" +mipidsi = "0.7.1" +rppal = { version = "0.14.1", features = ["hal"] } + +[workspace] diff --git a/mipidsi/examples/spi-st7789-rpi-zero-w/README.md b/mipidsi/examples/spi-st7789-rpi-zero-w/README.md new file mode 100644 index 0000000..3f5aa83 --- /dev/null +++ b/mipidsi/examples/spi-st7789-rpi-zero-w/README.md @@ -0,0 +1,50 @@ +# SPI ST7789 on a Raspberry Pi Zero W Example + +This example demonstrates how to use the [Display HAT Mini by Pomoroni](https://shop.pimoroni.com/products/display-hat-mini?variant=39496084717651) on a Raspberry Pi Zero W. + +The example shows a scrolling text and a pulsing RGB LED. + +Buttons: + +- A: change LED color +- B: exit +- X: move text up +- Y: move text down + +## Pre-requisite + +**Enable SPI** by any of this options: + +- `sudo raspi-config` +- `sudo raspi-config nonint do_spi 0` +- manually adding `dtparam=spi=on` to /boot/config.txt +- the graphical Raspberry Pi Configuration UI + +[More info about SPI](https://docs.golemparts.com/rppal/0.14.1/rppal/spi/index.html#spi0) + +## Build, strip, copy, and run + +### Mac OS + +Pre-requisite: musl-cross (Homebrew users: `brew install FiloSottile/musl-cross/musl-cross --without-x86_64 --with-arm-hf`) + +```bash +# build for rpi zero w +cargo build --release --target=arm-unknown-linux-musleabihf +# look at the size of the bin file +ls -lh target/arm-unknown-linux-musleabihf/release/spi-st7789-rpi-zero-w +# strip it +arm-linux-musleabihf-strip target/arm-unknown-linux-musleabihf/release/spi-st7789-rpi-zero-w +# look at it now ;) +ls -lh target/arm-unknown-linux-musleabihf/release/spi-st7789-rpi-zero-w +# copy over ssh +scp target/arm-unknown-linux-musleabihf/release/spi-st7789-rpi-zero-w pi@raspberrypi.local:~/ +# ssh into the rpi to run it +ssh pi@raspberrypi.local +# run it +./spi-st7789-rpi-zero-w +``` + +### Linux + +Not tested. Follow this article [Raspberry Pi Zero Raspbian/Rust Primer](https://dev.to/jeikabu/raspberry-pi-zero-raspbian-rust-primer-3aj6). diff --git a/mipidsi/examples/spi-st7789-rpi-zero-w/src/main.rs b/mipidsi/examples/spi-st7789-rpi-zero-w/src/main.rs new file mode 100644 index 0000000..e489346 --- /dev/null +++ b/mipidsi/examples/spi-st7789-rpi-zero-w/src/main.rs @@ -0,0 +1,158 @@ +/* +# SPI ST7789 on a Raspberry Pi Zero W Example + +This example demonstrates how to use the [Display HAT Mini by Pomoroni](https://shop.pimoroni.com/products/display-hat-mini?variant=39496084717651) +on a Raspberry Pi Zero W. + +The example shows a scrolling text and a pulsing RGB LED. + +Buttons: + +- A: change LED color +- B: exit +- X: move text up +- Y: move text down + +Read the README.md for more information. +*/ + +use display_interface_spi::SPIInterfaceNoCS; +use embedded_graphics::{ + mono_font::{ascii::FONT_10X20, MonoTextStyle}, + pixelcolor::Rgb565, + prelude::*, + text::Text, +}; +use mipidsi::Builder; +use rppal::gpio::{Gpio, OutputPin}; +use rppal::hal::Delay; +use rppal::spi::{Bus, Mode, SlaveSelect, Spi}; +use std::process::ExitCode; + +// Pins + +const SPI_DC: u8 = 9; +const BACKLIGHT: u8 = 13; + +const BUTTON_A: u8 = 5; +const BUTTON_B: u8 = 6; +const BUTTON_X: u8 = 16; +const BUTTON_Y: u8 = 24; + +const LED_R: u8 = 17; +const LED_G: u8 = 27; +const LED_B: u8 = 22; + +// Display +const W: i32 = 320; +const H: i32 = 240; + +fn main() -> ExitCode { + // GPIO + let gpio = Gpio::new().unwrap(); + let dc = gpio.get(SPI_DC).unwrap().into_output(); + let mut backlight = gpio.get(BACKLIGHT).unwrap().into_output(); + + // LEDs + let mut led_r = gpio.get(LED_R).unwrap().into_output(); + let mut led_g = gpio.get(LED_G).unwrap().into_output(); + let mut led_b = gpio.get(LED_B).unwrap().into_output(); + + // Buttons + let button_a = gpio.get(BUTTON_A).unwrap().into_input_pullup(); + let button_b = gpio.get(BUTTON_B).unwrap().into_input_pullup(); + let button_x = gpio.get(BUTTON_X).unwrap().into_input_pullup(); + let button_y = gpio.get(BUTTON_Y).unwrap().into_input_pullup(); + + // SPI Display + let spi = Spi::new(Bus::Spi0, SlaveSelect::Ss1, 60_000_000_u32, Mode::Mode0).unwrap(); + let di = SPIInterfaceNoCS::new(spi, dc); + let mut delay = Delay::new(); + let mut display = Builder::st7789(di) + // width and height are switched on purpose because of the orientation + .with_display_size(H as u16, W as u16) + // this orientation applies for the Display HAT Mini by Pimoroni + .with_orientation(mipidsi::Orientation::LandscapeInverted(true)) + .with_invert_colors(mipidsi::ColorInversion::Inverted) + .init(&mut delay, None::) + .unwrap(); + + // Text + let char_w = 10; + let char_h = 20; + let text_style = MonoTextStyle::new(&FONT_10X20, Rgb565::WHITE); + let text = "Hello World ^_^;"; + let mut text_x = W; + let mut text_y = H / 2; + + // Alternating color + let colors = [Rgb565::RED, Rgb565::GREEN, Rgb565::BLUE]; + + // Clear the display initially + display.clear(colors[0]).unwrap(); + + // Turn on backlight + backlight.set_high(); + + // Set LEDs to PWM mode + led_r.set_pwm_frequency(50., 1.).unwrap(); + led_g.set_pwm_frequency(50., 1.).unwrap(); + led_b.set_pwm_frequency(50., 1.).unwrap(); + + let start = std::time::Instant::now(); + let mut last = std::time::Instant::now(); + let mut led_flags = 0b000; + let mut counter = 0; + loop { + let elapsed = last.elapsed().as_secs_f64(); + if elapsed < 0.125 { + continue; + } + last = std::time::Instant::now(); + counter += 1; + + // X: move text up + if button_x.is_low() { + text_y -= char_h; + } + // Y: move text down + if button_y.is_low() { + text_y += char_h; + } + // A: change led color + if button_a.is_low() { + led_flags = (led_flags + 1) % 8; + } + // B: exit + if button_b.is_low() { + break; + } + + // Fill the display with alternating colors every 8 frames + display.clear(colors[(counter / 8) % colors.len()]).unwrap(); + + // Draw text + let right = Text::new(text, Point::new(text_x, text_y), text_style) + .draw(&mut display) + .unwrap(); + text_x = if right.x <= 0 { W } else { text_x - char_w }; + + // Led + let y = ((start.elapsed().as_secs_f64().sin() + 1.) * 50.).round() / 100.; + led_r + .set_pwm_frequency(50., if led_flags & 0b100 != 0 { y } else { 1. }) + .unwrap(); + led_g + .set_pwm_frequency(50., if led_flags & 0b010 != 0 { y } else { 1. }) + .unwrap(); + led_b + .set_pwm_frequency(50., if led_flags & 0b001 != 0 { y } else { 1. }) + .unwrap(); + } + + // Turn off backlight and clear the display + backlight.set_low(); + display.clear(Rgb565::BLACK).unwrap(); + + ExitCode::SUCCESS +}