aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2021-07-20 10:06:57 +0200
committerDario Nieuwenhuis <[email protected]>2021-07-20 10:06:57 +0200
commit451e3429611710c145916b2e87f534493eae85a5 (patch)
tree24fad8667396f7754df9b8cdfcb984adeba4dee3 /examples
parentda33b3a4d2fbb188c1c867e9092e7fec10b3a88e (diff)
rp/examples: add spi_display example
Diffstat (limited to 'examples')
-rw-r--r--examples/rp/Cargo.toml3
-rw-r--r--examples/rp/assets/ferris.rawbin0 -> 11008 bytes
-rw-r--r--examples/rp/src/bin/spi_display.rs215
3 files changed, 218 insertions, 0 deletions
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"
30embedded-hal = { version = "0.2.4" } 30embedded-hal = { version = "0.2.4" }
31panic-probe = { version = "0.2.0", features = ["print-defmt"] } 31panic-probe = { version = "0.2.0", features = ["print-defmt"] }
32futures = { version = "0.3.8", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] } 32futures = { version = "0.3.8", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] }
33display-interface-spi = "0.4.1"
34embedded-graphics = "0.7.1"
35st7789 = "0.6.1"
diff --git a/examples/rp/assets/ferris.raw b/examples/rp/assets/ferris.raw
new file mode 100644
index 000000000..9733889c5
--- /dev/null
+++ b/examples/rp/assets/ferris.raw
Binary files 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 @@
1#![no_std]
2#![no_main]
3#![feature(asm)]
4#![feature(min_type_alias_impl_trait)]
5#![feature(impl_trait_in_bindings)]
6#![feature(type_alias_impl_trait)]
7#![allow(incomplete_features)]
8
9#[path = "../example_common.rs"]
10mod example_common;
11
12use core::cell::RefCell;
13use core::fmt::Debug;
14
15use defmt::*;
16use display_interface_spi::SPIInterfaceNoCS;
17use embassy::executor::Spawner;
18use embassy::time::Delay;
19use embassy_rp::gpio::NoPin;
20use embassy_rp::peripherals;
21use embassy_rp::spi;
22use embassy_rp::spi::Spi;
23use embassy_rp::{gpio, Peripherals};
24use embedded_graphics::image::{Image, ImageRawLE};
25use embedded_graphics::mono_font::ascii::FONT_10X20;
26use embedded_graphics::mono_font::MonoTextStyle;
27use embedded_graphics::pixelcolor::Rgb565;
28use embedded_graphics::prelude::*;
29use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle};
30use embedded_graphics::text::Text;
31use gpio::{Level, Output};
32use st7789::{Orientation, ST7789};
33
34#[embassy::main]
35async fn main(_spawner: Spawner, p: Peripherals) {
36 info!("Hello World!");
37
38 let bl = p.PIN_13;
39 let rst = p.PIN_15;
40 let display_cs = p.PIN_9;
41 let dcx = p.PIN_8;
42 let miso = p.PIN_12;
43 let mosi = p.PIN_11;
44 let clk = p.PIN_10;
45 let touch_cs = p.PIN_16;
46 //let touch_irq = p.PIN_17;
47
48 // create SPI
49 let mut config = spi::Config::default();
50 config.frequency = DISPLAY_FREQ;
51 config.phase = spi::Phase::CaptureOnSecondTransition;
52 config.polarity = spi::Polarity::IdleHigh;
53
54 let spi = RefCell::new(SpiState {
55 last_mode: SpiMode::Display,
56 spi: Spi::new(p.SPI1, clk, mosi, miso, NoPin, config),
57 display_cs: Output::new(display_cs, Level::Low),
58 });
59
60 let mut touch = Touch::new(TouchSpi(&spi), Output::new(touch_cs, Level::High));
61
62 let dcx = Output::new(dcx, Level::Low);
63 let rst = Output::new(rst, Level::Low);
64 // dcx: 0 = command, 1 = data
65
66 // Enable LCD backlight
67 let _bl = Output::new(bl, Level::High);
68
69 // display interface abstraction from SPI and DC
70 let di = SPIInterfaceNoCS::new(DisplaySpi(&spi), dcx);
71
72 // create driver
73 let mut display = ST7789::new(di, rst, 240, 320);
74
75 // initialize
76 display.init(&mut Delay).unwrap();
77
78 // set default orientation
79 display.set_orientation(Orientation::Landscape).unwrap();
80
81 display.clear(Rgb565::BLACK).unwrap();
82
83 let raw_image_data = ImageRawLE::new(include_bytes!("../../assets/ferris.raw"), 86);
84 let ferris = Image::new(&raw_image_data, Point::new(34, 68));
85
86 // Display the image
87 ferris.draw(&mut display).unwrap();
88
89 let style = MonoTextStyle::new(&FONT_10X20, Rgb565::GREEN);
90 Text::new(
91 "Hello embedded_graphics \n + embassy + RP2040!",
92 Point::new(20, 200),
93 style,
94 )
95 .draw(&mut display)
96 .unwrap();
97
98 loop {
99 if let Some((x, y)) = touch.read() {
100 let style = PrimitiveStyleBuilder::new()
101 .fill_color(Rgb565::BLUE)
102 .build();
103
104 Rectangle::new(Point::new(x - 1, y - 1), Size::new(3, 3))
105 .into_styled(style)
106 .draw(&mut display)
107 .unwrap();
108 }
109 }
110}
111
112#[derive(Debug, Clone, Copy, PartialEq, Eq)]
113enum SpiMode {
114 Display,
115 Touch,
116}
117
118struct SpiState {
119 spi: Spi<'static, peripherals::SPI1>,
120 display_cs: Output<'static, peripherals::PIN_9>,
121
122 last_mode: SpiMode,
123}
124
125const DISPLAY_FREQ: u32 = 64_000_000;
126const TOUCH_FREQ: u32 = 200_000;
127
128struct DisplaySpi<'a>(&'a RefCell<SpiState>);
129impl<'a> embedded_hal::blocking::spi::Write<u8> for DisplaySpi<'a> {
130 type Error = core::convert::Infallible;
131
132 fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
133 let this = &mut *self.0.borrow_mut();
134 if this.last_mode != SpiMode::Display {
135 this.spi.set_frequency(DISPLAY_FREQ);
136 this.display_cs.set_low();
137 this.last_mode = SpiMode::Display;
138 }
139 this.spi.write(words);
140 Ok(())
141 }
142}
143
144struct TouchSpi<'a>(&'a RefCell<SpiState>);
145impl<'a> embedded_hal::blocking::spi::Transfer<u8> for TouchSpi<'a> {
146 type Error = core::convert::Infallible;
147
148 fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
149 let this = &mut *self.0.borrow_mut();
150 if this.last_mode != SpiMode::Touch {
151 this.spi.set_frequency(TOUCH_FREQ);
152 this.display_cs.set_high();
153 this.last_mode = SpiMode::Touch;
154 }
155 this.spi.transfer(words);
156 Ok(words)
157 }
158}
159
160struct Calibration {
161 x1: i32,
162 x2: i32,
163 y1: i32,
164 y2: i32,
165 sx: i32,
166 sy: i32,
167}
168
169const CALIBRATION: Calibration = Calibration {
170 x1: 3880,
171 x2: 340,
172 y1: 262,
173 y2: 3850,
174 sx: 320,
175 sy: 240,
176};
177
178struct Touch<
179 SPI: embedded_hal::blocking::spi::Transfer<u8>,
180 CS: embedded_hal::digital::v2::OutputPin,
181> {
182 spi: SPI,
183 cs: CS,
184}
185
186impl<SPI: embedded_hal::blocking::spi::Transfer<u8>, CS: embedded_hal::digital::v2::OutputPin>
187 Touch<SPI, CS>
188where
189 SPI::Error: Debug,
190 CS::Error: Debug,
191{
192 pub fn new(spi: SPI, cs: CS) -> Self {
193 Self { spi, cs }
194 }
195
196 pub fn read(&mut self) -> Option<(i32, i32)> {
197 self.cs.set_low().unwrap();
198 let mut buf = [0x90, 0x00, 0x00, 0xd0, 0x00, 0x00];
199 self.spi.transfer(&mut buf).unwrap();
200 self.cs.set_high().unwrap();
201
202 let x = ((buf[1] as u32) << 5 | (buf[2] as u32) >> 3) as i32;
203 let y = ((buf[4] as u32) << 5 | (buf[5] as u32) >> 3) as i32;
204
205 let cal = &CALIBRATION;
206
207 let x = ((x - cal.x1) * cal.sx / (cal.x2 - cal.x1)).clamp(0, cal.sx);
208 let y = ((y - cal.y1) * cal.sy / (cal.y2 - cal.y1)).clamp(0, cal.sy);
209 if x == 0 && y == 0 {
210 None
211 } else {
212 Some((x, y))
213 }
214 }
215}