1#![no_std]
2
3pub extern crate rp2040_hal as hal;
4
5pub use hal::pac;
6
7use display_interface::{DataFormat, DisplayError, WriteOnlyDataCommand};
8use embedded_hal_0_2::digital::v2::OutputPin;
9use fugit::HertzU32;
10use hal::dma::{single_buffer, Channel, ChannelIndex, WriteTarget};
11use hal::gpio::PinId;
12use hal::pio::{
13 Buffers, PIOBuilder, PIOExt, PinDir, PinState, StateMachineIndex, Tx, UninitStateMachine,
14};
15use pio_proc::pio_file;
16
17#[cfg(feature = "rt")]
18pub use rp2040_hal::entry;
19
20#[cfg(feature = "boot2")]
23#[link_section = ".boot2"]
24#[no_mangle]
25#[used]
26pub static BOOT2_FIRMWARE: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080;
27
28hal::bsp_pins!(
29 Gpio0 {
30 name: gpio0,
31 aliases: {
32 FunctionUart, PullNone: UartTx
34 }
35 },
36 Gpio1 {
37 name: gpio1,
38 aliases: {
39 FunctionUart, PullNone: UartRx
41 }
42 },
43 Gpio2 { name: lcd_backlight },
44 Gpio3 { name: i2c_int },
45 Gpio4 {
46 name: gpio4,
47 aliases: {
48 FunctionI2C, PullUp: I2cSda
50 }
51 },
52 Gpio5 {
53 name: gpio5,
54 aliases: {
55 FunctionI2C, PullUp: I2cScl
57 }
58 },
59 Gpio6 { name: sw_down },
60 Gpio7 { name: sw_a },
61 Gpio8 { name: sw_b },
62 Gpio9 { name: sw_c },
63 Gpio10 { name: lcd_cs },
64 Gpio11 { name: lcd_dc },
65 Gpio12 { name: lcd_wr },
66 Gpio13 { name: lcd_rd },
67 Gpio14 { name: lcd_db0 },
68 Gpio15 { name: lcd_db1 },
69 Gpio16 { name: lcd_db2 },
70 Gpio17 { name: lcd_db3 },
71 Gpio18 { name: lcd_db4 },
72 Gpio19 { name: lcd_db5 },
73 Gpio20 { name: lcd_db6 },
74 Gpio21 { name: lcd_db7 },
75 Gpio22 { name: sw_up },
76 Gpio23 { name: user_sw },
77 Gpio24 { name: vbus_detect },
78 Gpio25 { name: led },
79 Gpio26 { name: light_sense },
80 Gpio27 { name: sensor_power },
81 Gpio28 { name: vref_1v24 },
82 Gpio29 { name: vbat_sense },
83);
84
85pub const XOSC_CRYSTAL_FREQ: u32 = 12_000_000;
86
87#[inline]
88fn set_pin_bit<P: OutputPin>(pin: &mut P, bit: u8, value: u8) -> Result<(), DisplayError> {
89 pin.set_state(((bit & value) != 0).into())
90 .map_err(|_| DisplayError::BusWriteError)
91}
92
93struct WriteBytes<T>(T);
94
95unsafe impl<T: WriteTarget> WriteTarget for WriteBytes<T> {
99 type TransmittedWord = u8;
100
101 #[inline]
102 fn tx_treq() -> Option<u8> {
103 T::tx_treq()
104 }
105
106 #[inline]
107 fn tx_address_count(&mut self) -> (u32, u32) {
108 self.0.tx_address_count()
109 }
110
111 #[inline]
112 fn tx_increment(&self) -> bool {
113 self.0.tx_increment()
114 }
115}
116
117pub trait DisplayDataLines {
118 fn flush(&mut self) {}
119
120 fn write_u8(&mut self, value: u8) -> Result<(), DisplayError>;
121
122 fn write_slice(&mut self, data: &[u8]) -> Result<(), DisplayError> {
123 for b in data.iter().copied() {
124 self.write_u8(b)?;
125 }
126
127 Ok(())
128 }
129
130 fn write_format(&mut self, data: DataFormat<'_>) -> Result<(), DisplayError> {
131 match data {
132 DataFormat::U8(bytes) => self.write_slice(bytes)?,
133 DataFormat::U16(items) => {
134 for value in items.iter().copied() {
135 self.write_u8(value as u8)?;
136 self.write_u8((value >> 8) as u8)?;
137 }
138 }
139 DataFormat::U16BE(items) => {
140 for value in items.iter().copied() {
141 self.write_u8((value >> 8) as u8)?;
142 self.write_u8(value as u8)?;
143 }
144 }
145 DataFormat::U16LE(items) => {
146 for value in items.iter().copied() {
147 self.write_u8(value as u8)?;
148 self.write_u8((value >> 8) as u8)?;
149 }
150 }
151 DataFormat::U8Iter(iter) => {
152 for value in iter {
153 self.write_u8(value)?;
154 }
155 }
156 DataFormat::U16BEIter(iter) => {
157 for value in iter {
158 self.write_u8((value >> 8) as u8)?;
159 self.write_u8(value as u8)?;
160 }
161 }
162 DataFormat::U16LEIter(iter) => {
163 for value in iter {
164 self.write_u8(value as u8)?;
165 self.write_u8((value >> 8) as u8)?;
166 }
167 }
168 _ => unimplemented!(),
169 }
170
171 Ok(())
172 }
173}
174
175pub struct GpioDataLines<WR, D0, D1, D2, D3, D4, D5, D6, D7> {
176 pub wr: WR,
177 pub d0: D0,
178 pub d1: D1,
179 pub d2: D2,
180 pub d3: D3,
181 pub d4: D4,
182 pub d5: D5,
183 pub d6: D6,
184 pub d7: D7,
185}
186
187impl<
188 WR: OutputPin,
189 D0: OutputPin,
190 D1: OutputPin,
191 D2: OutputPin,
192 D3: OutputPin,
193 D4: OutputPin,
194 D5: OutputPin,
195 D6: OutputPin,
196 D7: OutputPin,
197 > GpioDataLines<WR, D0, D1, D2, D3, D4, D5, D6, D7>
198{
199 #[inline]
200 fn write_u8_inner(&mut self, value: u8) -> Result<(), DisplayError> {
201 set_pin_bit(&mut self.d0, value, 1 << 0)?;
202 set_pin_bit(&mut self.d1, value, 1 << 1)?;
203 set_pin_bit(&mut self.d2, value, 1 << 2)?;
204 set_pin_bit(&mut self.d3, value, 1 << 3)?;
205 set_pin_bit(&mut self.d4, value, 1 << 4)?;
206 set_pin_bit(&mut self.d5, value, 1 << 5)?;
207 set_pin_bit(&mut self.d6, value, 1 << 6)?;
208 set_pin_bit(&mut self.d7, value, 1 << 7)?;
209 Ok(())
210 }
211}
212
213impl<
214 WR: OutputPin,
215 D0: OutputPin,
216 D1: OutputPin,
217 D2: OutputPin,
218 D3: OutputPin,
219 D4: OutputPin,
220 D5: OutputPin,
221 D6: OutputPin,
222 D7: OutputPin,
223 > DisplayDataLines for GpioDataLines<WR, D0, D1, D2, D3, D4, D5, D6, D7>
224{
225 fn write_u8(&mut self, value: u8) -> Result<(), DisplayError> {
226 self.wr.set_low().map_err(|_| DisplayError::BusWriteError)?;
227 let err = self.write_u8_inner(value);
228 self.wr.set_high().ok();
229 err
230 }
231}
232
233type PioTx<P, SM, CH> = (Tx<(P, SM)>, Channel<CH>);
234
235pub struct PioDataLines<P: PIOExt, SM: StateMachineIndex, CH: ChannelIndex> {
236 tx: Option<PioTx<P, SM, CH>>,
237}
238
239impl<P: PIOExt, SM: StateMachineIndex, CH: ChannelIndex> PioDataLines<P, SM, CH> {
240 pub fn new(
241 pio: &mut hal::pio::PIO<P>,
242 sys_freq: HertzU32,
243 wr: impl PinId,
244 d0: impl PinId,
245 sm: UninitStateMachine<(P, SM)>,
246 ch: Channel<CH>,
247 ) -> PioDataLines<P, SM, CH> {
248 let d0 = d0.as_dyn().num;
249 let wr = wr.as_dyn().num;
250
251 let max_pio_clk = HertzU32::MHz(32);
252 let divider = (sys_freq + max_pio_clk - HertzU32::Hz(1)) / max_pio_clk;
253
254 let program = pio_file!("./src/st7789_parallel.pio");
255 let program = pio.install(&program.program).unwrap();
256 let (mut sm, _rx, tx) = PIOBuilder::from_installed_program(program)
257 .out_pins(d0, 8)
258 .side_set_pin_base(wr)
259 .buffers(Buffers::OnlyTx)
260 .pull_threshold(8)
261 .autopull(true)
262 .clock_divisor_fixed_point(divider as u16, 0)
263 .build(sm);
264 sm.set_pindirs([
265 (d0, PinDir::Output),
266 (d0 + 1, PinDir::Output),
267 (d0 + 2, PinDir::Output),
268 (d0 + 3, PinDir::Output),
269 (d0 + 4, PinDir::Output),
270 (d0 + 5, PinDir::Output),
271 (d0 + 6, PinDir::Output),
272 (d0 + 7, PinDir::Output),
273 (wr, PinDir::Output),
274 ]);
275 sm.set_pins([(wr, PinState::High)]);
276 sm.start();
277
278 PioDataLines { tx: Some((tx, ch)) }
279 }
280}
281
282impl<P: PIOExt, SM: StateMachineIndex, CH: ChannelIndex> DisplayDataLines
283 for PioDataLines<P, SM, CH>
284{
285 fn flush(&mut self) {
286 if let Some((tx, _)) = self.tx.as_mut() {
287 while !tx.is_empty() {}
288 }
289 }
290
291 fn write_u8(&mut self, value: u8) -> Result<(), DisplayError> {
292 if let Some((tx, _)) = self.tx.as_mut() {
293 while !tx.write(value as u32) {}
294 Ok(())
295 } else {
296 Err(DisplayError::BusWriteError)
297 }
298 }
299
300 fn write_slice(&mut self, data: &[u8]) -> Result<(), DisplayError> {
301 let data: &'static [u8] = unsafe { core::mem::transmute(data) };
303
304 let (tx, ch) = self.tx.take().expect("DMA already in use");
305 let xfer = single_buffer::Config::new(ch, data, WriteBytes(tx)).start();
306 let (ch, _, WriteBytes(tx)) = xfer.wait();
307 self.tx = Some((tx, ch));
308 Ok(())
309 }
310}
311
312pub struct ParallelDisplayInterface<CS, DC, D> {
313 cs: CS,
314 dc: DC,
315 data_lines: D,
316}
317
318impl<CS: OutputPin, DC: OutputPin, D: DisplayDataLines> ParallelDisplayInterface<CS, DC, D> {
319 pub fn new(cs: CS, dc: DC, data_lines: D) -> ParallelDisplayInterface<CS, DC, D> {
320 ParallelDisplayInterface { cs, dc, data_lines }
321 }
322}
323
324impl<CS: OutputPin, DC: OutputPin, D: DisplayDataLines> WriteOnlyDataCommand
325 for ParallelDisplayInterface<CS, DC, D>
326{
327 fn send_commands(&mut self, cmds: DataFormat<'_>) -> Result<(), DisplayError> {
328 self.cs.set_low().map_err(|_| DisplayError::CSError)?;
329 self.dc.set_low().map_err(|_| DisplayError::DCError)?;
330
331 let err = self.data_lines.write_format(cmds);
332 self.data_lines.flush();
333
334 err
335 }
336
337 fn send_data(&mut self, buf: DataFormat<'_>) -> Result<(), DisplayError> {
338 self.dc.set_high().map_err(|_| DisplayError::DCError)?;
339
340 let err = self.data_lines.write_format(buf);
341 self.data_lines.flush();
342
343 err
344 }
345}
346
347pub struct DummyPin;
348
349impl OutputPin for DummyPin {
350 type Error = ();
351
352 fn set_high(&mut self) -> Result<(), Self::Error> {
353 Ok(())
354 }
355
356 fn set_low(&mut self) -> Result<(), Self::Error> {
357 Ok(())
358 }
359}