diff options
| author | Georges Palauqui <[email protected]> | 2024-10-27 09:50:57 +0100 |
|---|---|---|
| committer | Georges Palauqui <[email protected]> | 2024-10-27 09:50:57 +0100 |
| commit | 66205fdd859b4c8607d0b6be9e4fcb27e8096493 (patch) | |
| tree | b1655fa4899c37bd28107270d39b149611697ef2 /examples/rp | |
| parent | b31648f2e59a68748e1c0f1408d1658a2e5e6a08 (diff) | |
update spi_display example for rp
Diffstat (limited to 'examples/rp')
| -rw-r--r-- | examples/rp/Cargo.toml | 8 | ||||
| -rw-r--r-- | examples/rp/src/bin/spi_display.rs | 165 |
2 files changed, 19 insertions, 154 deletions
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 6a2c99716..b55b20c63 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml | |||
| @@ -37,10 +37,10 @@ cortex-m = { version = "0.7.6", features = ["inline-asm"] } | |||
| 37 | cortex-m-rt = "0.7.0" | 37 | cortex-m-rt = "0.7.0" |
| 38 | critical-section = "1.1" | 38 | critical-section = "1.1" |
| 39 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 39 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 40 | display-interface-spi = "0.4.1" | 40 | display-interface-spi = "0.5.0" |
| 41 | embedded-graphics = "0.7.1" | 41 | embedded-graphics = "0.8.1" |
| 42 | st7789 = "0.6.1" | 42 | mipidsi = "0.8.0" |
| 43 | display-interface = "0.4.1" | 43 | display-interface = "0.5.0" |
| 44 | byte-slice-cast = { version = "1.2.0", default-features = false } | 44 | byte-slice-cast = { version = "1.2.0", default-features = false } |
| 45 | smart-leds = "0.4.0" | 45 | smart-leds = "0.4.0" |
| 46 | heapless = "0.8" | 46 | heapless = "0.8" |
diff --git a/examples/rp/src/bin/spi_display.rs b/examples/rp/src/bin/spi_display.rs index e937b9d0a..dd114a4ae 100644 --- a/examples/rp/src/bin/spi_display.rs +++ b/examples/rp/src/bin/spi_display.rs | |||
| @@ -9,11 +9,12 @@ | |||
| 9 | use core::cell::RefCell; | 9 | use core::cell::RefCell; |
| 10 | 10 | ||
| 11 | use defmt::*; | 11 | use defmt::*; |
| 12 | use display_interface_spi::SPIInterface; | ||
| 12 | use embassy_embedded_hal::shared_bus::blocking::spi::SpiDeviceWithConfig; | 13 | use embassy_embedded_hal::shared_bus::blocking::spi::SpiDeviceWithConfig; |
| 13 | use embassy_executor::Spawner; | 14 | use embassy_executor::Spawner; |
| 14 | use embassy_rp::gpio::{Level, Output}; | 15 | use embassy_rp::gpio::{Level, Output}; |
| 15 | use embassy_rp::spi; | 16 | use embassy_rp::spi; |
| 16 | use embassy_rp::spi::{Blocking, Spi}; | 17 | use embassy_rp::spi::Spi; |
| 17 | use embassy_sync::blocking_mutex::raw::NoopRawMutex; | 18 | use embassy_sync::blocking_mutex::raw::NoopRawMutex; |
| 18 | use embassy_sync::blocking_mutex::Mutex; | 19 | use embassy_sync::blocking_mutex::Mutex; |
| 19 | use embassy_time::Delay; | 20 | use embassy_time::Delay; |
| @@ -24,10 +25,11 @@ use embedded_graphics::pixelcolor::Rgb565; | |||
| 24 | use embedded_graphics::prelude::*; | 25 | use embedded_graphics::prelude::*; |
| 25 | use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle}; | 26 | use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle}; |
| 26 | use embedded_graphics::text::Text; | 27 | use embedded_graphics::text::Text; |
| 27 | use st7789::{Orientation, ST7789}; | 28 | use mipidsi::models::ST7789; |
| 29 | use mipidsi::options::{Orientation, Rotation}; | ||
| 30 | use mipidsi::Builder; | ||
| 28 | use {defmt_rtt as _, panic_probe as _}; | 31 | use {defmt_rtt as _, panic_probe as _}; |
| 29 | 32 | ||
| 30 | use crate::my_display_interface::SPIDeviceInterface; | ||
| 31 | use crate::touch::Touch; | 33 | use crate::touch::Touch; |
| 32 | 34 | ||
| 33 | const DISPLAY_FREQ: u32 = 64_000_000; | 35 | const DISPLAY_FREQ: u32 = 64_000_000; |
| @@ -58,7 +60,7 @@ async fn main(_spawner: Spawner) { | |||
| 58 | touch_config.phase = spi::Phase::CaptureOnSecondTransition; | 60 | touch_config.phase = spi::Phase::CaptureOnSecondTransition; |
| 59 | touch_config.polarity = spi::Polarity::IdleHigh; | 61 | touch_config.polarity = spi::Polarity::IdleHigh; |
| 60 | 62 | ||
| 61 | let spi: Spi<'_, _, Blocking> = Spi::new_blocking(p.SPI1, clk, mosi, miso, touch_config.clone()); | 63 | let spi = Spi::new_blocking(p.SPI1, clk, mosi, miso, touch_config.clone()); |
| 62 | let spi_bus: Mutex<NoopRawMutex, _> = Mutex::new(RefCell::new(spi)); | 64 | let spi_bus: Mutex<NoopRawMutex, _> = Mutex::new(RefCell::new(spi)); |
| 63 | 65 | ||
| 64 | let display_spi = SpiDeviceWithConfig::new(&spi_bus, Output::new(display_cs, Level::High), display_config); | 66 | let display_spi = SpiDeviceWithConfig::new(&spi_bus, Output::new(display_cs, Level::High), display_config); |
| @@ -74,17 +76,15 @@ async fn main(_spawner: Spawner) { | |||
| 74 | let _bl = Output::new(bl, Level::High); | 76 | let _bl = Output::new(bl, Level::High); |
| 75 | 77 | ||
| 76 | // display interface abstraction from SPI and DC | 78 | // display interface abstraction from SPI and DC |
| 77 | let di = SPIDeviceInterface::new(display_spi, dcx); | 79 | let di = SPIInterface::new(display_spi, dcx); |
| 78 | 80 | ||
| 79 | // create driver | 81 | // Define the display from the display interface and initialize it |
| 80 | let mut display = ST7789::new(di, rst, 240, 320); | 82 | let mut display = Builder::new(ST7789, di) |
| 81 | 83 | .display_size(240, 320) | |
| 82 | // initialize | 84 | .reset_pin(rst) |
| 83 | display.init(&mut Delay).unwrap(); | 85 | .orientation(Orientation::new().rotate(Rotation::Deg90)) |
| 84 | 86 | .init(&mut Delay) | |
| 85 | // set default orientation | 87 | .unwrap(); |
| 86 | display.set_orientation(Orientation::Landscape).unwrap(); | ||
| 87 | |||
| 88 | display.clear(Rgb565::BLACK).unwrap(); | 88 | display.clear(Rgb565::BLACK).unwrap(); |
| 89 | 89 | ||
| 90 | let raw_image_data = ImageRawLE::new(include_bytes!("../../assets/ferris.raw"), 86); | 90 | let raw_image_data = ImageRawLE::new(include_bytes!("../../assets/ferris.raw"), 86); |
| @@ -175,138 +175,3 @@ mod touch { | |||
| 175 | } | 175 | } |
| 176 | } | 176 | } |
| 177 | } | 177 | } |
| 178 | |||
| 179 | mod my_display_interface { | ||
| 180 | use display_interface::{DataFormat, DisplayError, WriteOnlyDataCommand}; | ||
| 181 | use embedded_hal_1::digital::OutputPin; | ||
| 182 | use embedded_hal_1::spi::SpiDevice; | ||
| 183 | |||
| 184 | /// SPI display interface. | ||
| 185 | /// | ||
| 186 | /// This combines the SPI peripheral and a data/command pin | ||
| 187 | pub struct SPIDeviceInterface<SPI, DC> { | ||
| 188 | spi: SPI, | ||
| 189 | dc: DC, | ||
| 190 | } | ||
| 191 | |||
| 192 | impl<SPI, DC> SPIDeviceInterface<SPI, DC> | ||
| 193 | where | ||
| 194 | SPI: SpiDevice, | ||
| 195 | DC: OutputPin, | ||
| 196 | { | ||
| 197 | /// Create new SPI interface for communciation with a display driver | ||
| 198 | pub fn new(spi: SPI, dc: DC) -> Self { | ||
| 199 | Self { spi, dc } | ||
| 200 | } | ||
| 201 | } | ||
| 202 | |||
| 203 | impl<SPI, DC> WriteOnlyDataCommand for SPIDeviceInterface<SPI, DC> | ||
| 204 | where | ||
| 205 | SPI: SpiDevice, | ||
| 206 | DC: OutputPin, | ||
| 207 | { | ||
| 208 | fn send_commands(&mut self, cmds: DataFormat<'_>) -> Result<(), DisplayError> { | ||
| 209 | // 1 = data, 0 = command | ||
| 210 | self.dc.set_low().map_err(|_| DisplayError::DCError)?; | ||
| 211 | |||
| 212 | send_u8(&mut self.spi, cmds).map_err(|_| DisplayError::BusWriteError)?; | ||
| 213 | Ok(()) | ||
| 214 | } | ||
| 215 | |||
| 216 | fn send_data(&mut self, buf: DataFormat<'_>) -> Result<(), DisplayError> { | ||
| 217 | // 1 = data, 0 = command | ||
| 218 | self.dc.set_high().map_err(|_| DisplayError::DCError)?; | ||
| 219 | |||
| 220 | send_u8(&mut self.spi, buf).map_err(|_| DisplayError::BusWriteError)?; | ||
| 221 | Ok(()) | ||
| 222 | } | ||
| 223 | } | ||
| 224 | |||
| 225 | fn send_u8<T: SpiDevice>(spi: &mut T, words: DataFormat<'_>) -> Result<(), T::Error> { | ||
| 226 | match words { | ||
| 227 | DataFormat::U8(slice) => spi.write(slice), | ||
| 228 | DataFormat::U16(slice) => { | ||
| 229 | use byte_slice_cast::*; | ||
| 230 | spi.write(slice.as_byte_slice()) | ||
| 231 | } | ||
| 232 | DataFormat::U16LE(slice) => { | ||
| 233 | use byte_slice_cast::*; | ||
| 234 | for v in slice.as_mut() { | ||
| 235 | *v = v.to_le(); | ||
| 236 | } | ||
| 237 | spi.write(slice.as_byte_slice()) | ||
| 238 | } | ||
| 239 | DataFormat::U16BE(slice) => { | ||
| 240 | use byte_slice_cast::*; | ||
| 241 | for v in slice.as_mut() { | ||
| 242 | *v = v.to_be(); | ||
| 243 | } | ||
| 244 | spi.write(slice.as_byte_slice()) | ||
| 245 | } | ||
| 246 | DataFormat::U8Iter(iter) => { | ||
| 247 | let mut buf = [0; 32]; | ||
| 248 | let mut i = 0; | ||
| 249 | |||
| 250 | for v in iter.into_iter() { | ||
| 251 | buf[i] = v; | ||
| 252 | i += 1; | ||
| 253 | |||
| 254 | if i == buf.len() { | ||
| 255 | spi.write(&buf)?; | ||
| 256 | i = 0; | ||
| 257 | } | ||
| 258 | } | ||
| 259 | |||
| 260 | if i > 0 { | ||
| 261 | spi.write(&buf[..i])?; | ||
| 262 | } | ||
| 263 | |||
| 264 | Ok(()) | ||
| 265 | } | ||
| 266 | DataFormat::U16LEIter(iter) => { | ||
| 267 | use byte_slice_cast::*; | ||
| 268 | let mut buf = [0; 32]; | ||
| 269 | let mut i = 0; | ||
| 270 | |||
| 271 | for v in iter.map(u16::to_le) { | ||
| 272 | buf[i] = v; | ||
| 273 | i += 1; | ||
| 274 | |||
| 275 | if i == buf.len() { | ||
| 276 | spi.write(&buf.as_byte_slice())?; | ||
| 277 | i = 0; | ||
| 278 | } | ||
| 279 | } | ||
| 280 | |||
| 281 | if i > 0 { | ||
| 282 | spi.write(&buf[..i].as_byte_slice())?; | ||
| 283 | } | ||
| 284 | |||
| 285 | Ok(()) | ||
| 286 | } | ||
| 287 | DataFormat::U16BEIter(iter) => { | ||
| 288 | use byte_slice_cast::*; | ||
| 289 | let mut buf = [0; 64]; | ||
| 290 | let mut i = 0; | ||
| 291 | let len = buf.len(); | ||
| 292 | |||
| 293 | for v in iter.map(u16::to_be) { | ||
| 294 | buf[i] = v; | ||
| 295 | i += 1; | ||
| 296 | |||
| 297 | if i == len { | ||
| 298 | spi.write(&buf.as_byte_slice())?; | ||
| 299 | i = 0; | ||
| 300 | } | ||
| 301 | } | ||
| 302 | |||
| 303 | if i > 0 { | ||
| 304 | spi.write(&buf[..i].as_byte_slice())?; | ||
| 305 | } | ||
| 306 | |||
| 307 | Ok(()) | ||
| 308 | } | ||
| 309 | _ => unimplemented!(), | ||
| 310 | } | ||
| 311 | } | ||
| 312 | } | ||
