aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorUlf Lilleengen <[email protected]>2024-11-05 16:37:35 +0000
committerGitHub <[email protected]>2024-11-05 16:37:35 +0000
commit5b075077090ec1436437c82011554649e909c8ee (patch)
treeffe648241457dda9f50cf046b602bc1fadfbe57f /examples
parentf55ebef380b49d109216e2cd6821fa1c35202748 (diff)
parent7733b99e0960d41d7b7d88f4d94adb6b21eb17b4 (diff)
Merge pull request #3467 from Georges760/upd-ex-spi-display
Update example spi_display for RP/RP23 to use mipidsi instead of ST7789 crate
Diffstat (limited to 'examples')
-rw-r--r--examples/rp/Cargo.toml8
-rw-r--r--examples/rp/src/bin/spi_display.rs165
-rw-r--r--examples/rp23/Cargo.toml8
-rw-r--r--examples/rp23/src/bin/spi_display.rs163
4 files changed, 37 insertions, 307 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"] }
37cortex-m-rt = "0.7.0" 37cortex-m-rt = "0.7.0"
38critical-section = "1.1" 38critical-section = "1.1"
39panic-probe = { version = "0.3", features = ["print-defmt"] } 39panic-probe = { version = "0.3", features = ["print-defmt"] }
40display-interface-spi = "0.4.1" 40display-interface-spi = "0.5.0"
41embedded-graphics = "0.7.1" 41embedded-graphics = "0.8.1"
42st7789 = "0.6.1" 42mipidsi = "0.8.0"
43display-interface = "0.4.1" 43display-interface = "0.5.0"
44byte-slice-cast = { version = "1.2.0", default-features = false } 44byte-slice-cast = { version = "1.2.0", default-features = false }
45smart-leds = "0.4.0" 45smart-leds = "0.4.0"
46heapless = "0.8" 46heapless = "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 @@
9use core::cell::RefCell; 9use core::cell::RefCell;
10 10
11use defmt::*; 11use defmt::*;
12use display_interface_spi::SPIInterface;
12use embassy_embedded_hal::shared_bus::blocking::spi::SpiDeviceWithConfig; 13use embassy_embedded_hal::shared_bus::blocking::spi::SpiDeviceWithConfig;
13use embassy_executor::Spawner; 14use embassy_executor::Spawner;
14use embassy_rp::gpio::{Level, Output}; 15use embassy_rp::gpio::{Level, Output};
15use embassy_rp::spi; 16use embassy_rp::spi;
16use embassy_rp::spi::{Blocking, Spi}; 17use embassy_rp::spi::Spi;
17use embassy_sync::blocking_mutex::raw::NoopRawMutex; 18use embassy_sync::blocking_mutex::raw::NoopRawMutex;
18use embassy_sync::blocking_mutex::Mutex; 19use embassy_sync::blocking_mutex::Mutex;
19use embassy_time::Delay; 20use embassy_time::Delay;
@@ -24,10 +25,11 @@ use embedded_graphics::pixelcolor::Rgb565;
24use embedded_graphics::prelude::*; 25use embedded_graphics::prelude::*;
25use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle}; 26use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle};
26use embedded_graphics::text::Text; 27use embedded_graphics::text::Text;
27use st7789::{Orientation, ST7789}; 28use mipidsi::models::ST7789;
29use mipidsi::options::{Orientation, Rotation};
30use mipidsi::Builder;
28use {defmt_rtt as _, panic_probe as _}; 31use {defmt_rtt as _, panic_probe as _};
29 32
30use crate::my_display_interface::SPIDeviceInterface;
31use crate::touch::Touch; 33use crate::touch::Touch;
32 34
33const DISPLAY_FREQ: u32 = 64_000_000; 35const 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
179mod 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}
diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml
index 5527a1e0a..eec12a9ab 100644
--- a/examples/rp23/Cargo.toml
+++ b/examples/rp23/Cargo.toml
@@ -38,10 +38,10 @@ cortex-m = { version = "0.7.6", features = ["inline-asm"] }
38cortex-m-rt = "0.7.0" 38cortex-m-rt = "0.7.0"
39critical-section = "1.1" 39critical-section = "1.1"
40panic-probe = { version = "0.3", features = ["print-defmt"] } 40panic-probe = { version = "0.3", features = ["print-defmt"] }
41display-interface-spi = "0.4.1" 41display-interface-spi = "0.5.0"
42embedded-graphics = "0.7.1" 42embedded-graphics = "0.8.1"
43st7789 = "0.6.1" 43mipidsi = "0.8.0"
44display-interface = "0.4.1" 44display-interface = "0.5.0"
45byte-slice-cast = { version = "1.2.0", default-features = false } 45byte-slice-cast = { version = "1.2.0", default-features = false }
46smart-leds = "0.3.0" 46smart-leds = "0.3.0"
47heapless = "0.8" 47heapless = "0.8"
diff --git a/examples/rp23/src/bin/spi_display.rs b/examples/rp23/src/bin/spi_display.rs
index 195db5a97..6b7c0781f 100644
--- a/examples/rp23/src/bin/spi_display.rs
+++ b/examples/rp23/src/bin/spi_display.rs
@@ -1,4 +1,4 @@
1//! This example shows how to use SPI (Serial Peripheral Interface) in the RP2040 chip. 1//! This example shows how to use SPI (Serial Peripheral Interface) in the RP2350 chip.
2//! 2//!
3//! Example written for a display using the ST7789 chip. Possibly the Waveshare Pico-ResTouch 3//! Example written for a display using the ST7789 chip. Possibly the Waveshare Pico-ResTouch
4//! (https://www.waveshare.com/wiki/Pico-ResTouch-LCD-2.8) 4//! (https://www.waveshare.com/wiki/Pico-ResTouch-LCD-2.8)
@@ -9,6 +9,7 @@
9use core::cell::RefCell; 9use core::cell::RefCell;
10 10
11use defmt::*; 11use defmt::*;
12use display_interface_spi::SPIInterface;
12use embassy_embedded_hal::shared_bus::blocking::spi::SpiDeviceWithConfig; 13use embassy_embedded_hal::shared_bus::blocking::spi::SpiDeviceWithConfig;
13use embassy_executor::Spawner; 14use embassy_executor::Spawner;
14use embassy_rp::block::ImageDef; 15use embassy_rp::block::ImageDef;
@@ -25,14 +26,15 @@ use embedded_graphics::pixelcolor::Rgb565;
25use embedded_graphics::prelude::*; 26use embedded_graphics::prelude::*;
26use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle}; 27use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle};
27use embedded_graphics::text::Text; 28use embedded_graphics::text::Text;
28use st7789::{Orientation, ST7789}; 29use mipidsi::models::ST7789;
30use mipidsi::options::{Orientation, Rotation};
31use mipidsi::Builder;
29use {defmt_rtt as _, panic_probe as _}; 32use {defmt_rtt as _, panic_probe as _};
30 33
31#[link_section = ".start_block"] 34#[link_section = ".start_block"]
32#[used] 35#[used]
33pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); 36pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
34 37
35use crate::my_display_interface::SPIDeviceInterface;
36use crate::touch::Touch; 38use crate::touch::Touch;
37 39
38const DISPLAY_FREQ: u32 = 64_000_000; 40const DISPLAY_FREQ: u32 = 64_000_000;
@@ -79,17 +81,15 @@ async fn main(_spawner: Spawner) {
79 let _bl = Output::new(bl, Level::High); 81 let _bl = Output::new(bl, Level::High);
80 82
81 // display interface abstraction from SPI and DC 83 // display interface abstraction from SPI and DC
82 let di = SPIDeviceInterface::new(display_spi, dcx); 84 let di = SPIInterface::new(display_spi, dcx);
83 85
84 // create driver 86 // Define the display from the display interface and initialize it
85 let mut display = ST7789::new(di, rst, 240, 320); 87 let mut display = Builder::new(ST7789, di)
86 88 .display_size(240, 320)
87 // initialize 89 .reset_pin(rst)
88 display.init(&mut Delay).unwrap(); 90 .orientation(Orientation::new().rotate(Rotation::Deg90))
89 91 .init(&mut Delay)
90 // set default orientation 92 .unwrap();
91 display.set_orientation(Orientation::Landscape).unwrap();
92
93 display.clear(Rgb565::BLACK).unwrap(); 93 display.clear(Rgb565::BLACK).unwrap();
94 94
95 let raw_image_data = ImageRawLE::new(include_bytes!("../../assets/ferris.raw"), 86); 95 let raw_image_data = ImageRawLE::new(include_bytes!("../../assets/ferris.raw"), 86);
@@ -180,138 +180,3 @@ mod touch {
180 } 180 }
181 } 181 }
182} 182}
183
184mod my_display_interface {
185 use display_interface::{DataFormat, DisplayError, WriteOnlyDataCommand};
186 use embedded_hal_1::digital::OutputPin;
187 use embedded_hal_1::spi::SpiDevice;
188
189 /// SPI display interface.
190 ///
191 /// This combines the SPI peripheral and a data/command pin
192 pub struct SPIDeviceInterface<SPI, DC> {
193 spi: SPI,
194 dc: DC,
195 }
196
197 impl<SPI, DC> SPIDeviceInterface<SPI, DC>
198 where
199 SPI: SpiDevice,
200 DC: OutputPin,
201 {
202 /// Create new SPI interface for communciation with a display driver
203 pub fn new(spi: SPI, dc: DC) -> Self {
204 Self { spi, dc }
205 }
206 }
207
208 impl<SPI, DC> WriteOnlyDataCommand for SPIDeviceInterface<SPI, DC>
209 where
210 SPI: SpiDevice,
211 DC: OutputPin,
212 {
213 fn send_commands(&mut self, cmds: DataFormat<'_>) -> Result<(), DisplayError> {
214 // 1 = data, 0 = command
215 self.dc.set_low().map_err(|_| DisplayError::DCError)?;
216
217 send_u8(&mut self.spi, cmds).map_err(|_| DisplayError::BusWriteError)?;
218 Ok(())
219 }
220
221 fn send_data(&mut self, buf: DataFormat<'_>) -> Result<(), DisplayError> {
222 // 1 = data, 0 = command
223 self.dc.set_high().map_err(|_| DisplayError::DCError)?;
224
225 send_u8(&mut self.spi, buf).map_err(|_| DisplayError::BusWriteError)?;
226 Ok(())
227 }
228 }
229
230 fn send_u8<T: SpiDevice>(spi: &mut T, words: DataFormat<'_>) -> Result<(), T::Error> {
231 match words {
232 DataFormat::U8(slice) => spi.write(slice),
233 DataFormat::U16(slice) => {
234 use byte_slice_cast::*;
235 spi.write(slice.as_byte_slice())
236 }
237 DataFormat::U16LE(slice) => {
238 use byte_slice_cast::*;
239 for v in slice.as_mut() {
240 *v = v.to_le();
241 }
242 spi.write(slice.as_byte_slice())
243 }
244 DataFormat::U16BE(slice) => {
245 use byte_slice_cast::*;
246 for v in slice.as_mut() {
247 *v = v.to_be();
248 }
249 spi.write(slice.as_byte_slice())
250 }
251 DataFormat::U8Iter(iter) => {
252 let mut buf = [0; 32];
253 let mut i = 0;
254
255 for v in iter.into_iter() {
256 buf[i] = v;
257 i += 1;
258
259 if i == buf.len() {
260 spi.write(&buf)?;
261 i = 0;
262 }
263 }
264
265 if i > 0 {
266 spi.write(&buf[..i])?;
267 }
268
269 Ok(())
270 }
271 DataFormat::U16LEIter(iter) => {
272 use byte_slice_cast::*;
273 let mut buf = [0; 32];
274 let mut i = 0;
275
276 for v in iter.map(u16::to_le) {
277 buf[i] = v;
278 i += 1;
279
280 if i == buf.len() {
281 spi.write(&buf.as_byte_slice())?;
282 i = 0;
283 }
284 }
285
286 if i > 0 {
287 spi.write(&buf[..i].as_byte_slice())?;
288 }
289
290 Ok(())
291 }
292 DataFormat::U16BEIter(iter) => {
293 use byte_slice_cast::*;
294 let mut buf = [0; 64];
295 let mut i = 0;
296 let len = buf.len();
297
298 for v in iter.map(u16::to_be) {
299 buf[i] = v;
300 i += 1;
301
302 if i == len {
303 spi.write(&buf.as_byte_slice())?;
304 i = 0;
305 }
306 }
307
308 if i > 0 {
309 spi.write(&buf[..i].as_byte_slice())?;
310 }
311
312 Ok(())
313 }
314 _ => unimplemented!(),
315 }
316 }
317}