aboutsummaryrefslogtreecommitdiff
path: root/examples/rp
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2022-02-16 03:54:39 +0100
committerDario Nieuwenhuis <[email protected]>2022-03-11 00:38:07 +0100
commit9bad9365dcf31dd558aca05f60d244beb9e5e697 (patch)
tree3d54927ce409975c58dff4409b8a140a4b68abd1 /examples/rp
parent828cdb295183b8733ec636a80e0d35e6f8e41827 (diff)
Update rust nightly, embedded-hal 1.0, embedded-hal-async.
Diffstat (limited to 'examples/rp')
-rw-r--r--examples/rp/Cargo.toml7
-rw-r--r--examples/rp/src/bin/spi_display.rs375
2 files changed, 287 insertions, 95 deletions
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index c067fbbcf..830e54174 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2authors = ["Dario Nieuwenhuis <[email protected]>"] 2authors = ["Dario Nieuwenhuis <[email protected]>"]
3edition = "2018" 3edition = "2021"
4name = "embassy-rp-examples" 4name = "embassy-rp-examples"
5version = "0.1.0" 5version = "0.1.0"
6 6
@@ -15,9 +15,12 @@ defmt-rtt = "0.3"
15 15
16cortex-m = "0.7.3" 16cortex-m = "0.7.3"
17cortex-m-rt = "0.7.0" 17cortex-m-rt = "0.7.0"
18embedded-hal = "0.2.6"
19panic-probe = { version = "0.3", features = ["print-defmt"] } 18panic-probe = { version = "0.3", features = ["print-defmt"] }
20futures = { version = "0.3.17", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] } 19futures = { version = "0.3.17", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] }
21display-interface-spi = "0.4.1" 20display-interface-spi = "0.4.1"
22embedded-graphics = "0.7.1" 21embedded-graphics = "0.7.1"
23st7789 = "0.6.1" 22st7789 = "0.6.1"
23
24embedded-hal = { version = "1.0.0-alpha.7", git = "https://github.com/embassy-rs/embedded-hal", branch = "embassy2" }
25display-interface = "0.4.1"
26byte-slice-cast = { version = "1.2.0", default-features = false }
diff --git a/examples/rp/src/bin/spi_display.rs b/examples/rp/src/bin/spi_display.rs
index 01149c250..b2854afcb 100644
--- a/examples/rp/src/bin/spi_display.rs
+++ b/examples/rp/src/bin/spi_display.rs
@@ -6,16 +6,14 @@
6mod example_common; 6mod example_common;
7 7
8use core::cell::RefCell; 8use core::cell::RefCell;
9use core::fmt::Debug;
10 9
11use defmt::*; 10use defmt::*;
12use display_interface_spi::SPIInterfaceNoCS;
13use embassy::executor::Spawner; 11use embassy::executor::Spawner;
14use embassy::time::Delay; 12use embassy::time::Delay;
15use embassy_rp::peripherals; 13use embassy_rp::gpio::{Level, Output};
16use embassy_rp::spi; 14use embassy_rp::spi;
17use embassy_rp::spi::Spi; 15use embassy_rp::spi::Spi;
18use embassy_rp::{gpio, Peripherals}; 16use embassy_rp::Peripherals;
19use embedded_graphics::image::{Image, ImageRawLE}; 17use embedded_graphics::image::{Image, ImageRawLE};
20use embedded_graphics::mono_font::ascii::FONT_10X20; 18use embedded_graphics::mono_font::ascii::FONT_10X20;
21use embedded_graphics::mono_font::MonoTextStyle; 19use embedded_graphics::mono_font::MonoTextStyle;
@@ -23,9 +21,15 @@ use embedded_graphics::pixelcolor::Rgb565;
23use embedded_graphics::prelude::*; 21use embedded_graphics::prelude::*;
24use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle}; 22use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle};
25use embedded_graphics::text::Text; 23use embedded_graphics::text::Text;
26use gpio::{Level, Output};
27use st7789::{Orientation, ST7789}; 24use st7789::{Orientation, ST7789};
28 25
26use crate::my_display_interface::SPIDeviceInterface;
27use crate::shared_spi::SpiDeviceWithCs;
28use crate::touch::Touch;
29
30//const DISPLAY_FREQ: u32 = 64_000_000;
31const TOUCH_FREQ: u32 = 200_000;
32
29#[embassy::main] 33#[embassy::main]
30async fn main(_spawner: Spawner, p: Peripherals) { 34async fn main(_spawner: Spawner, p: Peripherals) {
31 info!("Hello World!"); 35 info!("Hello World!");
@@ -42,17 +46,16 @@ async fn main(_spawner: Spawner, p: Peripherals) {
42 46
43 // create SPI 47 // create SPI
44 let mut config = spi::Config::default(); 48 let mut config = spi::Config::default();
45 config.frequency = DISPLAY_FREQ; 49 config.frequency = TOUCH_FREQ; // use the lowest freq
46 config.phase = spi::Phase::CaptureOnSecondTransition; 50 config.phase = spi::Phase::CaptureOnSecondTransition;
47 config.polarity = spi::Polarity::IdleHigh; 51 config.polarity = spi::Polarity::IdleHigh;
48 52
49 let spi = RefCell::new(SpiState { 53 let spi_bus = RefCell::new(Spi::new(p.SPI1, clk, mosi, miso, config));
50 last_mode: SpiMode::Display,
51 spi: Spi::new(p.SPI1, clk, mosi, miso, config),
52 display_cs: Output::new(display_cs, Level::Low),
53 });
54 54
55 let mut touch = Touch::new(TouchSpi(&spi), Output::new(touch_cs, Level::High)); 55 let display_spi = SpiDeviceWithCs::new(&spi_bus, Output::new(display_cs, Level::High));
56 let touch_spi = SpiDeviceWithCs::new(&spi_bus, Output::new(touch_cs, Level::High));
57
58 let mut touch = Touch::new(touch_spi);
56 59
57 let dcx = Output::new(dcx, Level::Low); 60 let dcx = Output::new(dcx, Level::Low);
58 let rst = Output::new(rst, Level::Low); 61 let rst = Output::new(rst, Level::Low);
@@ -62,7 +65,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
62 let _bl = Output::new(bl, Level::High); 65 let _bl = Output::new(bl, Level::High);
63 66
64 // display interface abstraction from SPI and DC 67 // display interface abstraction from SPI and DC
65 let di = SPIInterfaceNoCS::new(DisplaySpi(&spi), dcx); 68 let di = SPIDeviceInterface::new(display_spi, dcx);
66 69
67 // create driver 70 // create driver
68 let mut display = ST7789::new(di, rst, 240, 320); 71 let mut display = ST7789::new(di, rst, 240, 320);
@@ -104,107 +107,293 @@ async fn main(_spawner: Spawner, p: Peripherals) {
104 } 107 }
105} 108}
106 109
107#[derive(Debug, Clone, Copy, PartialEq, Eq)] 110mod shared_spi {
108enum SpiMode { 111 use core::cell::RefCell;
109 Display, 112 use core::fmt::Debug;
110 Touch,
111}
112 113
113struct SpiState { 114 use embedded_hal::digital::blocking::OutputPin;
114 spi: Spi<'static, peripherals::SPI1>, 115 use embedded_hal::spi;
115 display_cs: Output<'static, peripherals::PIN_9>, 116 use embedded_hal::spi::blocking::SpiDevice;
116 117
117 last_mode: SpiMode, 118 #[derive(Copy, Clone, Eq, PartialEq, Debug)]
118} 119 pub enum SpiDeviceWithCsError<BUS, CS> {
120 #[allow(unused)] // will probably use in the future when adding a flush() to SpiBus
121 Spi(BUS),
122 Cs(CS),
123 }
119 124
120const DISPLAY_FREQ: u32 = 64_000_000; 125 impl<BUS, CS> spi::Error for SpiDeviceWithCsError<BUS, CS>
121const TOUCH_FREQ: u32 = 200_000; 126 where
127 BUS: spi::Error + Debug,
128 CS: Debug,
129 {
130 fn kind(&self) -> spi::ErrorKind {
131 match self {
132 Self::Spi(e) => e.kind(),
133 Self::Cs(_) => spi::ErrorKind::Other,
134 }
135 }
136 }
122 137
123struct DisplaySpi<'a>(&'a RefCell<SpiState>); 138 pub struct SpiDeviceWithCs<'a, BUS, CS> {
124impl<'a> embedded_hal::blocking::spi::Write<u8> for DisplaySpi<'a> { 139 bus: &'a RefCell<BUS>,
125 type Error = core::convert::Infallible; 140 cs: CS,
141 }
126 142
127 fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { 143 impl<'a, BUS, CS> SpiDeviceWithCs<'a, BUS, CS> {
128 let this = &mut *self.0.borrow_mut(); 144 pub fn new(bus: &'a RefCell<BUS>, cs: CS) -> Self {
129 if this.last_mode != SpiMode::Display { 145 Self { bus, cs }
130 this.spi.set_frequency(DISPLAY_FREQ);
131 this.display_cs.set_low();
132 this.last_mode = SpiMode::Display;
133 } 146 }
134 this.spi.write(words).unwrap();
135 Ok(())
136 } 147 }
137}
138 148
139struct TouchSpi<'a>(&'a RefCell<SpiState>); 149 impl<'a, BUS, CS> spi::ErrorType for SpiDeviceWithCs<'a, BUS, CS>
140impl<'a> embedded_hal::blocking::spi::Transfer<u8> for TouchSpi<'a> { 150 where
141 type Error = core::convert::Infallible; 151 BUS: spi::ErrorType,
152 CS: OutputPin,
153 {
154 type Error = SpiDeviceWithCsError<BUS::Error, CS::Error>;
155 }
156
157 impl<'a, BUS, CS> SpiDevice for SpiDeviceWithCs<'a, BUS, CS>
158 where
159 BUS: spi::blocking::SpiBusFlush,
160 CS: OutputPin,
161 {
162 type Bus = BUS;
163
164 fn transaction<R>(
165 &mut self,
166 f: impl FnOnce(&mut Self::Bus) -> Result<R, BUS::Error>,
167 ) -> Result<R, Self::Error> {
168 let mut bus = self.bus.borrow_mut();
169 self.cs.set_low().map_err(SpiDeviceWithCsError::Cs)?;
142 170
143 fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { 171 let f_res = f(&mut bus);
144 let this = &mut *self.0.borrow_mut(); 172
145 if this.last_mode != SpiMode::Touch { 173 // On failure, it's important to still flush and deassert CS.
146 this.spi.set_frequency(TOUCH_FREQ); 174 let flush_res = bus.flush();
147 this.display_cs.set_high(); 175 let cs_res = self.cs.set_high();
148 this.last_mode = SpiMode::Touch; 176
177 let f_res = f_res.map_err(SpiDeviceWithCsError::Spi)?;
178 flush_res.map_err(SpiDeviceWithCsError::Spi)?;
179 cs_res.map_err(SpiDeviceWithCsError::Cs)?;
180
181 Ok(f_res)
149 } 182 }
150 this.spi.transfer(words).unwrap();
151 Ok(words)
152 } 183 }
153} 184}
154 185
155struct Calibration { 186/// Driver for the XPT2046 resistive touchscreen sensor
156 x1: i32, 187mod touch {
157 x2: i32, 188 use embedded_hal::spi::blocking::{SpiBus, SpiBusRead, SpiBusWrite, SpiDevice};
158 y1: i32, 189
159 y2: i32, 190 struct Calibration {
160 sx: i32, 191 x1: i32,
161 sy: i32, 192 x2: i32,
162} 193 y1: i32,
194 y2: i32,
195 sx: i32,
196 sy: i32,
197 }
198
199 const CALIBRATION: Calibration = Calibration {
200 x1: 3880,
201 x2: 340,
202 y1: 262,
203 y2: 3850,
204 sx: 320,
205 sy: 240,
206 };
207
208 pub struct Touch<SPI: SpiDevice> {
209 spi: SPI,
210 }
211
212 impl<SPI> Touch<SPI>
213 where
214 SPI: SpiDevice,
215 SPI::Bus: SpiBus,
216 {
217 pub fn new(spi: SPI) -> Self {
218 Self { spi }
219 }
220
221 pub fn read(&mut self) -> Option<(i32, i32)> {
222 let mut x = [0; 2];
223 let mut y = [0; 2];
224 self.spi
225 .transaction(|bus| {
226 bus.write(&[0x90])?;
227 bus.read(&mut x)?;
228 bus.write(&[0xd0])?;
229 bus.read(&mut y)?;
230 Ok(())
231 })
232 .unwrap();
233
234 let x = (u16::from_be_bytes(x) >> 3) as i32;
235 let y = (u16::from_be_bytes(y) >> 3) as i32;
236
237 let cal = &CALIBRATION;
163 238
164const CALIBRATION: Calibration = Calibration { 239 let x = ((x - cal.x1) * cal.sx / (cal.x2 - cal.x1)).clamp(0, cal.sx);
165 x1: 3880, 240 let y = ((y - cal.y1) * cal.sy / (cal.y2 - cal.y1)).clamp(0, cal.sy);
166 x2: 340, 241 if x == 0 && y == 0 {
167 y1: 262, 242 None
168 y2: 3850, 243 } else {
169 sx: 320, 244 Some((x, y))
170 sy: 240, 245 }
171}; 246 }
172 247 }
173struct Touch<
174 SPI: embedded_hal::blocking::spi::Transfer<u8>,
175 CS: embedded_hal::digital::v2::OutputPin,
176> {
177 spi: SPI,
178 cs: CS,
179} 248}
180 249
181impl<SPI: embedded_hal::blocking::spi::Transfer<u8>, CS: embedded_hal::digital::v2::OutputPin> 250mod my_display_interface {
182 Touch<SPI, CS> 251 use display_interface::{DataFormat, DisplayError, WriteOnlyDataCommand};
183where 252 use embedded_hal::digital::blocking::OutputPin;
184 SPI::Error: Debug, 253 use embedded_hal::spi::blocking::{SpiBusWrite, SpiDevice};
185 CS::Error: Debug, 254
186{ 255 /// SPI display interface.
187 pub fn new(spi: SPI, cs: CS) -> Self { 256 ///
188 Self { spi, cs } 257 /// This combines the SPI peripheral and a data/command pin
258 pub struct SPIDeviceInterface<SPI, DC> {
259 spi: SPI,
260 dc: DC,
189 } 261 }
190 262
191 pub fn read(&mut self) -> Option<(i32, i32)> { 263 impl<SPI, DC> SPIDeviceInterface<SPI, DC>
192 self.cs.set_low().unwrap(); 264 where
193 let mut buf = [0x90, 0x00, 0x00, 0xd0, 0x00, 0x00]; 265 SPI: SpiDevice,
194 self.spi.transfer(&mut buf).unwrap(); 266 SPI::Bus: SpiBusWrite,
195 self.cs.set_high().unwrap(); 267 DC: OutputPin,
268 {
269 /// Create new SPI interface for communciation with a display driver
270 pub fn new(spi: SPI, dc: DC) -> Self {
271 Self { spi, dc }
272 }
273 }
196 274
197 let x = ((buf[1] as u32) << 5 | (buf[2] as u32) >> 3) as i32; 275 impl<SPI, DC> WriteOnlyDataCommand for SPIDeviceInterface<SPI, DC>
198 let y = ((buf[4] as u32) << 5 | (buf[5] as u32) >> 3) as i32; 276 where
277 SPI: SpiDevice,
278 SPI::Bus: SpiBusWrite,
279 DC: OutputPin,
280 {
281 fn send_commands(&mut self, cmds: DataFormat<'_>) -> Result<(), DisplayError> {
282 let r = self.spi.transaction(|bus| {
283 // 1 = data, 0 = command
284 if let Err(_) = self.dc.set_low() {
285 return Ok(Err(DisplayError::DCError));
286 }
287
288 // Send words over SPI
289 send_u8(bus, cmds)?;
290
291 Ok(Ok(()))
292 });
293 r.map_err(|_| DisplayError::BusWriteError)?
294 }
199 295
200 let cal = &CALIBRATION; 296 fn send_data(&mut self, buf: DataFormat<'_>) -> Result<(), DisplayError> {
297 let r = self.spi.transaction(|bus| {
298 // 1 = data, 0 = command
299 if let Err(_) = self.dc.set_high() {
300 return Ok(Err(DisplayError::DCError));
301 }
302
303 // Send words over SPI
304 send_u8(bus, buf)?;
305
306 Ok(Ok(()))
307 });
308 r.map_err(|_| DisplayError::BusWriteError)?
309 }
310 }
201 311
202 let x = ((x - cal.x1) * cal.sx / (cal.x2 - cal.x1)).clamp(0, cal.sx); 312 fn send_u8<T: SpiBusWrite>(spi: &mut T, words: DataFormat<'_>) -> Result<(), T::Error> {
203 let y = ((y - cal.y1) * cal.sy / (cal.y2 - cal.y1)).clamp(0, cal.sy); 313 match words {
204 if x == 0 && y == 0 { 314 DataFormat::U8(slice) => spi.write(slice),
205 None 315 DataFormat::U16(slice) => {
206 } else { 316 use byte_slice_cast::*;
207 Some((x, y)) 317 spi.write(slice.as_byte_slice())
318 }
319 DataFormat::U16LE(slice) => {
320 use byte_slice_cast::*;
321 for v in slice.as_mut() {
322 *v = v.to_le();
323 }
324 spi.write(slice.as_byte_slice())
325 }
326 DataFormat::U16BE(slice) => {
327 use byte_slice_cast::*;
328 for v in slice.as_mut() {
329 *v = v.to_be();
330 }
331 spi.write(slice.as_byte_slice())
332 }
333 DataFormat::U8Iter(iter) => {
334 let mut buf = [0; 32];
335 let mut i = 0;
336
337 for v in iter.into_iter() {
338 buf[i] = v;
339 i += 1;
340
341 if i == buf.len() {
342 spi.write(&buf)?;
343 i = 0;
344 }
345 }
346
347 if i > 0 {
348 spi.write(&buf[..i])?;
349 }
350
351 Ok(())
352 }
353 DataFormat::U16LEIter(iter) => {
354 use byte_slice_cast::*;
355 let mut buf = [0; 32];
356 let mut i = 0;
357
358 for v in iter.map(u16::to_le) {
359 buf[i] = v;
360 i += 1;
361
362 if i == buf.len() {
363 spi.write(&buf.as_byte_slice())?;
364 i = 0;
365 }
366 }
367
368 if i > 0 {
369 spi.write(&buf[..i].as_byte_slice())?;
370 }
371
372 Ok(())
373 }
374 DataFormat::U16BEIter(iter) => {
375 use byte_slice_cast::*;
376 let mut buf = [0; 64];
377 let mut i = 0;
378 let len = buf.len();
379
380 for v in iter.map(u16::to_be) {
381 buf[i] = v;
382 i += 1;
383
384 if i == len {
385 spi.write(&buf.as_byte_slice())?;
386 i = 0;
387 }
388 }
389
390 if i > 0 {
391 spi.write(&buf[..i].as_byte_slice())?;
392 }
393
394 Ok(())
395 }
396 _ => unimplemented!(),
208 } 397 }
209 } 398 }
210} 399}