diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index e45bf5943..4c4f983fc 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -30,3 +30,6 @@ cortex-m-rt = "0.6.13"
 embedded-hal    = { version = "0.2.4" }
 panic-probe = { version = "0.2.0", features = ["print-defmt"] }
 futures = { version = "0.3.8", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] }
+display-interface-spi = "0.4.1"
+embedded-graphics = "0.7.1"
+st7789 = "0.6.1"
diff --git a/examples/rp/assets/ferris.raw b/examples/rp/assets/ferris.raw
new file mode 100644
index 000000000..9733889c5
Binary files /dev/null and b/examples/rp/assets/ferris.raw differ
diff --git a/examples/rp/src/bin/spi_display.rs b/examples/rp/src/bin/spi_display.rs
new file mode 100644
index 000000000..467cdf426
--- /dev/null
+++ b/examples/rp/src/bin/spi_display.rs
@@ -0,0 +1,215 @@
+#![no_std]
+#![no_main]
+#![feature(asm)]
+#![feature(min_type_alias_impl_trait)]
+#![feature(impl_trait_in_bindings)]
+#![feature(type_alias_impl_trait)]
+#![allow(incomplete_features)]
+
+#[path = "../example_common.rs"]
+mod example_common;
+
+use core::cell::RefCell;
+use core::fmt::Debug;
+
+use defmt::*;
+use display_interface_spi::SPIInterfaceNoCS;
+use embassy::executor::Spawner;
+use embassy::time::Delay;
+use embassy_rp::gpio::NoPin;
+use embassy_rp::peripherals;
+use embassy_rp::spi;
+use embassy_rp::spi::Spi;
+use embassy_rp::{gpio, Peripherals};
+use embedded_graphics::image::{Image, ImageRawLE};
+use embedded_graphics::mono_font::ascii::FONT_10X20;
+use embedded_graphics::mono_font::MonoTextStyle;
+use embedded_graphics::pixelcolor::Rgb565;
+use embedded_graphics::prelude::*;
+use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle};
+use embedded_graphics::text::Text;
+use gpio::{Level, Output};
+use st7789::{Orientation, ST7789};
+
+#[embassy::main]
+async fn main(_spawner: Spawner, p: Peripherals) {
+    info!("Hello World!");
+
+    let bl = p.PIN_13;
+    let rst = p.PIN_15;
+    let display_cs = p.PIN_9;
+    let dcx = p.PIN_8;
+    let miso = p.PIN_12;
+    let mosi = p.PIN_11;
+    let clk = p.PIN_10;
+    let touch_cs = p.PIN_16;
+    //let touch_irq = p.PIN_17;
+
+    // create SPI
+    let mut config = spi::Config::default();
+    config.frequency = DISPLAY_FREQ;
+    config.phase = spi::Phase::CaptureOnSecondTransition;
+    config.polarity = spi::Polarity::IdleHigh;
+
+    let spi = RefCell::new(SpiState {
+        last_mode: SpiMode::Display,
+        spi: Spi::new(p.SPI1, clk, mosi, miso, NoPin, config),
+        display_cs: Output::new(display_cs, Level::Low),
+    });
+
+    let mut touch = Touch::new(TouchSpi(&spi), Output::new(touch_cs, Level::High));
+
+    let dcx = Output::new(dcx, Level::Low);
+    let rst = Output::new(rst, Level::Low);
+    // dcx: 0 = command, 1 = data
+
+    // Enable LCD backlight
+    let _bl = Output::new(bl, Level::High);
+
+    // display interface abstraction from SPI and DC
+    let di = SPIInterfaceNoCS::new(DisplaySpi(&spi), dcx);
+
+    // create driver
+    let mut display = ST7789::new(di, rst, 240, 320);
+
+    // initialize
+    display.init(&mut Delay).unwrap();
+
+    // set default orientation
+    display.set_orientation(Orientation::Landscape).unwrap();
+
+    display.clear(Rgb565::BLACK).unwrap();
+
+    let raw_image_data = ImageRawLE::new(include_bytes!("../../assets/ferris.raw"), 86);
+    let ferris = Image::new(&raw_image_data, Point::new(34, 68));
+
+    // Display the image
+    ferris.draw(&mut display).unwrap();
+
+    let style = MonoTextStyle::new(&FONT_10X20, Rgb565::GREEN);
+    Text::new(
+        "Hello embedded_graphics \n + embassy + RP2040!",
+        Point::new(20, 200),
+        style,
+    )
+    .draw(&mut display)
+    .unwrap();
+
+    loop {
+        if let Some((x, y)) = touch.read() {
+            let style = PrimitiveStyleBuilder::new()
+                .fill_color(Rgb565::BLUE)
+                .build();
+
+            Rectangle::new(Point::new(x - 1, y - 1), Size::new(3, 3))
+                .into_styled(style)
+                .draw(&mut display)
+                .unwrap();
+        }
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+enum SpiMode {
+    Display,
+    Touch,
+}
+
+struct SpiState {
+    spi: Spi<'static, peripherals::SPI1>,
+    display_cs: Output<'static, peripherals::PIN_9>,
+
+    last_mode: SpiMode,
+}
+
+const DISPLAY_FREQ: u32 = 64_000_000;
+const TOUCH_FREQ: u32 = 200_000;
+
+struct DisplaySpi<'a>(&'a RefCell<SpiState>);
+impl<'a> embedded_hal::blocking::spi::Write<u8> for DisplaySpi<'a> {
+    type Error = core::convert::Infallible;
+
+    fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
+        let this = &mut *self.0.borrow_mut();
+        if this.last_mode != SpiMode::Display {
+            this.spi.set_frequency(DISPLAY_FREQ);
+            this.display_cs.set_low();
+            this.last_mode = SpiMode::Display;
+        }
+        this.spi.write(words);
+        Ok(())
+    }
+}
+
+struct TouchSpi<'a>(&'a RefCell<SpiState>);
+impl<'a> embedded_hal::blocking::spi::Transfer<u8> for TouchSpi<'a> {
+    type Error = core::convert::Infallible;
+
+    fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
+        let this = &mut *self.0.borrow_mut();
+        if this.last_mode != SpiMode::Touch {
+            this.spi.set_frequency(TOUCH_FREQ);
+            this.display_cs.set_high();
+            this.last_mode = SpiMode::Touch;
+        }
+        this.spi.transfer(words);
+        Ok(words)
+    }
+}
+
+struct Calibration {
+    x1: i32,
+    x2: i32,
+    y1: i32,
+    y2: i32,
+    sx: i32,
+    sy: i32,
+}
+
+const CALIBRATION: Calibration = Calibration {
+    x1: 3880,
+    x2: 340,
+    y1: 262,
+    y2: 3850,
+    sx: 320,
+    sy: 240,
+};
+
+struct Touch<
+    SPI: embedded_hal::blocking::spi::Transfer<u8>,
+    CS: embedded_hal::digital::v2::OutputPin,
+> {
+    spi: SPI,
+    cs: CS,
+}
+
+impl<SPI: embedded_hal::blocking::spi::Transfer<u8>, CS: embedded_hal::digital::v2::OutputPin>
+    Touch<SPI, CS>
+where
+    SPI::Error: Debug,
+    CS::Error: Debug,
+{
+    pub fn new(spi: SPI, cs: CS) -> Self {
+        Self { spi, cs }
+    }
+
+    pub fn read(&mut self) -> Option<(i32, i32)> {
+        self.cs.set_low().unwrap();
+        let mut buf = [0x90, 0x00, 0x00, 0xd0, 0x00, 0x00];
+        self.spi.transfer(&mut buf).unwrap();
+        self.cs.set_high().unwrap();
+
+        let x = ((buf[1] as u32) << 5 | (buf[2] as u32) >> 3) as i32;
+        let y = ((buf[4] as u32) << 5 | (buf[5] as u32) >> 3) as i32;
+
+        let cal = &CALIBRATION;
+
+        let x = ((x - cal.x1) * cal.sx / (cal.x2 - cal.x1)).clamp(0, cal.sx);
+        let y = ((y - cal.y1) * cal.sy / (cal.y2 - cal.y1)).clamp(0, cal.sy);
+        if x == 0 && y == 0 {
+            None
+        } else {
+            Some((x, y))
+        }
+    }
+}