diff options
| author | Dario Nieuwenhuis <[email protected]> | 2021-07-20 10:11:58 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2021-07-20 10:11:58 +0200 |
| commit | 25b870d811d9ac3955a69996ddf7a68a2af252f5 (patch) | |
| tree | ce7daa4a3a92cedba5f5cf188a803b841813af7c /examples | |
| parent | b04dc7e7837161bc8d9c6cf3cf40d876f2f82c9a (diff) | |
| parent | 451e3429611710c145916b2e87f534493eae85a5 (diff) | |
Merge pull request #302 from embassy-rs/rp-spi-fixes
Rp spi fixes
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/rp/Cargo.toml | 3 | ||||
| -rw-r--r-- | examples/rp/assets/ferris.raw | bin | 0 -> 11008 bytes | |||
| -rw-r--r-- | examples/rp/src/bin/spi_display.rs | 215 |
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" | |||
| 30 | embedded-hal = { version = "0.2.4" } | 30 | embedded-hal = { version = "0.2.4" } |
| 31 | panic-probe = { version = "0.2.0", features = ["print-defmt"] } | 31 | panic-probe = { version = "0.2.0", features = ["print-defmt"] } |
| 32 | futures = { version = "0.3.8", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] } | 32 | futures = { version = "0.3.8", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] } |
| 33 | display-interface-spi = "0.4.1" | ||
| 34 | embedded-graphics = "0.7.1" | ||
| 35 | 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 --- /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"] | ||
| 10 | mod example_common; | ||
| 11 | |||
| 12 | use core::cell::RefCell; | ||
| 13 | use core::fmt::Debug; | ||
| 14 | |||
| 15 | use defmt::*; | ||
| 16 | use display_interface_spi::SPIInterfaceNoCS; | ||
| 17 | use embassy::executor::Spawner; | ||
| 18 | use embassy::time::Delay; | ||
| 19 | use embassy_rp::gpio::NoPin; | ||
| 20 | use embassy_rp::peripherals; | ||
| 21 | use embassy_rp::spi; | ||
| 22 | use embassy_rp::spi::Spi; | ||
| 23 | use embassy_rp::{gpio, Peripherals}; | ||
| 24 | use embedded_graphics::image::{Image, ImageRawLE}; | ||
| 25 | use embedded_graphics::mono_font::ascii::FONT_10X20; | ||
| 26 | use embedded_graphics::mono_font::MonoTextStyle; | ||
| 27 | use embedded_graphics::pixelcolor::Rgb565; | ||
| 28 | use embedded_graphics::prelude::*; | ||
| 29 | use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle}; | ||
| 30 | use embedded_graphics::text::Text; | ||
| 31 | use gpio::{Level, Output}; | ||
| 32 | use st7789::{Orientation, ST7789}; | ||
| 33 | |||
| 34 | #[embassy::main] | ||
| 35 | async 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)] | ||
| 113 | enum SpiMode { | ||
| 114 | Display, | ||
| 115 | Touch, | ||
| 116 | } | ||
| 117 | |||
| 118 | struct SpiState { | ||
| 119 | spi: Spi<'static, peripherals::SPI1>, | ||
| 120 | display_cs: Output<'static, peripherals::PIN_9>, | ||
| 121 | |||
| 122 | last_mode: SpiMode, | ||
| 123 | } | ||
| 124 | |||
| 125 | const DISPLAY_FREQ: u32 = 64_000_000; | ||
| 126 | const TOUCH_FREQ: u32 = 200_000; | ||
| 127 | |||
| 128 | struct DisplaySpi<'a>(&'a RefCell<SpiState>); | ||
| 129 | impl<'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 | |||
| 144 | struct TouchSpi<'a>(&'a RefCell<SpiState>); | ||
| 145 | impl<'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 | |||
| 160 | struct Calibration { | ||
| 161 | x1: i32, | ||
| 162 | x2: i32, | ||
| 163 | y1: i32, | ||
| 164 | y2: i32, | ||
| 165 | sx: i32, | ||
| 166 | sy: i32, | ||
| 167 | } | ||
| 168 | |||
| 169 | const CALIBRATION: Calibration = Calibration { | ||
| 170 | x1: 3880, | ||
| 171 | x2: 340, | ||
| 172 | y1: 262, | ||
| 173 | y2: 3850, | ||
| 174 | sx: 320, | ||
| 175 | sy: 240, | ||
| 176 | }; | ||
| 177 | |||
| 178 | struct 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 | |||
| 186 | impl<SPI: embedded_hal::blocking::spi::Transfer<u8>, CS: embedded_hal::digital::v2::OutputPin> | ||
| 187 | Touch<SPI, CS> | ||
| 188 | where | ||
| 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 | } | ||
