1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
|
//! This example shows how to use SPI (Serial Peripheral Interface) in the RP2350 chip.
//!
//! Example written for a display using the ST7789 chip. Possibly the Waveshare Pico-ResTouch
//! (https://www.waveshare.com/wiki/Pico-ResTouch-LCD-2.8)
#![no_std]
#![no_main]
use core::cell::RefCell;
use defmt::*;
use display_interface_spi::SPIInterface;
use embassy_embedded_hal::shared_bus::blocking::spi::SpiDeviceWithConfig;
use embassy_executor::Spawner;
use embassy_rp::gpio::{Level, Output};
use embassy_rp::spi;
use embassy_rp::spi::{Blocking, Spi};
use embassy_sync::blocking_mutex::Mutex;
use embassy_sync::blocking_mutex::raw::NoopRawMutex;
use embassy_time::Delay;
use embedded_graphics::image::{Image, ImageRawLE};
use embedded_graphics::mono_font::MonoTextStyle;
use embedded_graphics::mono_font::ascii::FONT_10X20;
use embedded_graphics::pixelcolor::Rgb565;
use embedded_graphics::prelude::*;
use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle};
use embedded_graphics::text::Text;
use mipidsi::Builder;
use mipidsi::models::ST7789;
use mipidsi::options::{Orientation, Rotation};
use {defmt_rtt as _, panic_probe as _};
use crate::touch::Touch;
const DISPLAY_FREQ: u32 = 64_000_000;
const TOUCH_FREQ: u32 = 200_000;
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_rp::init(Default::default());
info!("Hello World!");
let bl = p.PIN_13;
let rst = p.PIN_15;
let display_cs = p.PIN_9;
let dcx = p.PIN_8;
let miso = p.PIN_12;
let mosi = p.PIN_11;
let clk = p.PIN_10;
let touch_cs = p.PIN_16;
//let touch_irq = p.PIN_17;
// create SPI
let mut display_config = spi::Config::default();
display_config.frequency = DISPLAY_FREQ;
display_config.phase = spi::Phase::CaptureOnSecondTransition;
display_config.polarity = spi::Polarity::IdleHigh;
let mut touch_config = spi::Config::default();
touch_config.frequency = TOUCH_FREQ;
touch_config.phase = spi::Phase::CaptureOnSecondTransition;
touch_config.polarity = spi::Polarity::IdleHigh;
let spi: Spi<'_, _, Blocking> = Spi::new_blocking(p.SPI1, clk, mosi, miso, touch_config.clone());
let spi_bus: Mutex<NoopRawMutex, _> = Mutex::new(RefCell::new(spi));
let display_spi = SpiDeviceWithConfig::new(&spi_bus, Output::new(display_cs, Level::High), display_config);
let touch_spi = SpiDeviceWithConfig::new(&spi_bus, Output::new(touch_cs, Level::High), touch_config);
let mut touch = Touch::new(touch_spi);
let dcx = Output::new(dcx, Level::Low);
let rst = Output::new(rst, Level::Low);
// dcx: 0 = command, 1 = data
// Enable LCD backlight
let _bl = Output::new(bl, Level::High);
// display interface abstraction from SPI and DC
let di = SPIInterface::new(display_spi, dcx);
// Define the display from the display interface and initialize it
let mut display = Builder::new(ST7789, di)
.display_size(240, 320)
.reset_pin(rst)
.orientation(Orientation::new().rotate(Rotation::Deg90))
.init(&mut Delay)
.unwrap();
display.clear(Rgb565::BLACK).unwrap();
let raw_image_data = ImageRawLE::new(include_bytes!("../../assets/ferris.raw"), 86);
let ferris = Image::new(&raw_image_data, Point::new(34, 68));
// Display the image
ferris.draw(&mut display).unwrap();
let style = MonoTextStyle::new(&FONT_10X20, Rgb565::GREEN);
Text::new(
"Hello embedded_graphics \n + embassy + RP235x!",
Point::new(20, 200),
style,
)
.draw(&mut display)
.unwrap();
loop {
if let Some((x, y)) = touch.read() {
let style = PrimitiveStyleBuilder::new().fill_color(Rgb565::BLUE).build();
Rectangle::new(Point::new(x - 1, y - 1), Size::new(3, 3))
.into_styled(style)
.draw(&mut display)
.unwrap();
}
}
}
/// Driver for the XPT2046 resistive touchscreen sensor
mod touch {
use embedded_hal_1::spi::{Operation, SpiDevice};
struct Calibration {
x1: i32,
x2: i32,
y1: i32,
y2: i32,
sx: i32,
sy: i32,
}
const CALIBRATION: Calibration = Calibration {
x1: 3880,
x2: 340,
y1: 262,
y2: 3850,
sx: 320,
sy: 240,
};
pub struct Touch<SPI: SpiDevice> {
spi: SPI,
}
impl<SPI> Touch<SPI>
where
SPI: SpiDevice,
{
pub fn new(spi: SPI) -> Self {
Self { spi }
}
pub fn read(&mut self) -> Option<(i32, i32)> {
let mut x = [0; 2];
let mut y = [0; 2];
self.spi
.transaction(&mut [
Operation::Write(&[0x90]),
Operation::Read(&mut x),
Operation::Write(&[0xd0]),
Operation::Read(&mut y),
])
.unwrap();
let x = (u16::from_be_bytes(x) >> 3) as i32;
let y = (u16::from_be_bytes(y) >> 3) as i32;
let cal = &CALIBRATION;
let x = ((x - cal.x1) * cal.sx / (cal.x2 - cal.x1)).clamp(0, cal.sx);
let y = ((y - cal.y1) * cal.sy / (cal.y2 - cal.y1)).clamp(0, cal.sy);
if x == 0 && y == 0 { None } else { Some((x, y)) }
}
}
}
|