1use embedded_hal::{
14 delay::DelayNs,
15 digital::{InputPin, OutputPin},
16 spi::SpiDevice,
17};
18
19use crate::color::TriColor;
20use crate::interface::DisplayInterface;
21use crate::traits::{
22 InternalWiAdditions, RefreshLut, WaveshareDisplay, WaveshareThreeColorDisplay,
23};
24
25pub(crate) mod command;
26use self::command::Command;
27use crate::buffer_len;
28
29#[cfg(feature = "graphics")]
31pub type Display7in5 = crate::graphics::Display<
32 WIDTH,
33 HEIGHT,
34 false,
35 { buffer_len(WIDTH as usize, HEIGHT as usize * 2) },
36 TriColor,
37>;
38
39pub const WIDTH: u32 = 800;
41pub const HEIGHT: u32 = 480;
43pub const DEFAULT_BACKGROUND_COLOR: TriColor = TriColor::White;
45
46const NUM_DISPLAY_BITS: usize = WIDTH as usize / 8 * HEIGHT as usize;
48const IS_BUSY_LOW: bool = true;
49const SINGLE_BYTE_WRITE: bool = false;
50
51pub struct Epd7in5<SPI, BUSY, DC, RST, DELAY> {
54 interface: DisplayInterface<SPI, BUSY, DC, RST, DELAY, SINGLE_BYTE_WRITE>,
56 color: TriColor,
58}
59
60impl<SPI, BUSY, DC, RST, DELAY> InternalWiAdditions<SPI, BUSY, DC, RST, DELAY>
61 for Epd7in5<SPI, BUSY, DC, RST, DELAY>
62where
63 SPI: SpiDevice,
64 BUSY: InputPin,
65 DC: OutputPin,
66 RST: OutputPin,
67 DELAY: DelayNs,
68{
69 fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
70 self.interface.reset(delay, 200_000, 2_000);
73
74 self.cmd_with_data(spi, Command::PowerSetting, &[0x07, 0x07, 0x3F, 0x3F])?;
80 self.command(spi, Command::PowerOn)?;
81 self.wait_until_idle(spi, delay)?;
83 self.cmd_with_data(spi, Command::PanelSetting, &[0x0F])?;
86 self.cmd_with_data(spi, Command::TconResolution, &[0x03, 0x20, 0x01, 0xE0])?;
89 self.cmd_with_data(spi, Command::DualSpi, &[0x00])?;
91 self.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x11, 0x07])?;
100 self.cmd_with_data(spi, Command::TconSetting, &[0x22])?;
102 self.cmd_with_data(spi, Command::SpiFlashControl, &[0x00, 0x00, 0x00, 0x00])?;
103 self.wait_until_idle(spi, delay)?;
105 Ok(())
106 }
107}
108
109impl<SPI, BUSY, DC, RST, DELAY> WaveshareThreeColorDisplay<SPI, BUSY, DC, RST, DELAY>
110 for Epd7in5<SPI, BUSY, DC, RST, DELAY>
111where
112 SPI: SpiDevice,
113 BUSY: InputPin,
114 DC: OutputPin,
115 RST: OutputPin,
116 DELAY: DelayNs,
117{
118 fn update_color_frame(
119 &mut self,
120 spi: &mut SPI,
121 delay: &mut DELAY,
122 black: &[u8],
123 chromatic: &[u8],
124 ) -> Result<(), SPI::Error> {
125 self.update_achromatic_frame(spi, delay, black)?;
126 self.update_chromatic_frame(spi, delay, chromatic)
127 }
128
129 fn update_achromatic_frame(
133 &mut self,
134 spi: &mut SPI,
135 _delay: &mut DELAY,
136 black: &[u8],
137 ) -> Result<(), SPI::Error> {
138 self.interface.cmd(spi, Command::DataStartTransmission1)?;
139 self.interface.data(spi, black)?;
140 self.interface.cmd(spi, Command::DataStop)?;
141 Ok(())
142 }
143
144 fn update_chromatic_frame(
148 &mut self,
149 spi: &mut SPI,
150 delay: &mut DELAY,
151 chromatic: &[u8],
152 ) -> Result<(), SPI::Error> {
153 self.interface.cmd(spi, Command::DataStartTransmission2)?;
154 self.interface.data(spi, chromatic)?;
155 self.interface.cmd(spi, Command::DataStop)?;
156
157 self.wait_until_idle(spi, delay)?;
158 Ok(())
159 }
160}
161
162impl<SPI, BUSY, DC, RST, DELAY> WaveshareDisplay<SPI, BUSY, DC, RST, DELAY>
163 for Epd7in5<SPI, BUSY, DC, RST, DELAY>
164where
165 SPI: SpiDevice,
166 BUSY: InputPin,
167 DC: OutputPin,
168 RST: OutputPin,
169 DELAY: DelayNs,
170{
171 type DisplayColor = TriColor;
172 fn new(
173 spi: &mut SPI,
174 busy: BUSY,
175 dc: DC,
176 rst: RST,
177 delay: &mut DELAY,
178 delay_us: Option<u32>,
179 ) -> Result<Self, SPI::Error> {
180 let interface = DisplayInterface::new(busy, dc, rst, delay_us);
181 let color = DEFAULT_BACKGROUND_COLOR;
182
183 let mut epd = Epd7in5 { interface, color };
184
185 epd.init(spi, delay)?;
186
187 Ok(epd)
188 }
189
190 fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
191 self.init(spi, delay)
192 }
193
194 fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
195 self.wait_until_idle(spi, delay)?;
196 self.command(spi, Command::PowerOff)?;
197 self.wait_until_idle(spi, delay)?;
198 self.cmd_with_data(spi, Command::DeepSleep, &[0xA5])?;
199 Ok(())
200 }
201
202 fn update_frame(
203 &mut self,
204 spi: &mut SPI,
205 buffer: &[u8],
206 delay: &mut DELAY,
207 ) -> Result<(), SPI::Error> {
208 self.wait_until_idle(spi, delay)?;
209 self.cmd_with_data(
211 spi,
212 Command::DataStartTransmission1,
213 &buffer[..NUM_DISPLAY_BITS],
214 )?;
215 self.cmd_with_data(
216 spi,
217 Command::DataStartTransmission2,
218 &buffer[NUM_DISPLAY_BITS..],
219 )?;
220 self.interface.cmd(spi, Command::DataStop)?;
221 Ok(())
222 }
223
224 fn update_partial_frame(
225 &mut self,
226 _spi: &mut SPI,
227 _delay: &mut DELAY,
228 _buffer: &[u8],
229 _x: u32,
230 _y: u32,
231 _width: u32,
232 _height: u32,
233 ) -> Result<(), SPI::Error> {
234 unimplemented!()
235 }
236
237 fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
238 self.wait_until_idle(spi, delay)?;
239 self.command(spi, Command::DisplayRefresh)?;
240 Ok(())
241 }
242
243 fn update_and_display_frame(
244 &mut self,
245 spi: &mut SPI,
246 buffer: &[u8],
247 delay: &mut DELAY,
248 ) -> Result<(), SPI::Error> {
249 self.update_frame(spi, buffer, delay)?;
250 self.command(spi, Command::DisplayRefresh)?;
251 Ok(())
252 }
253
254 fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
255 self.wait_until_idle(spi, delay)?;
256 self.send_resolution(spi)?;
257
258 self.command(spi, Command::DataStartTransmission1)?;
259 self.interface.data_x_times(spi, 0xFF, WIDTH / 8 * HEIGHT)?;
260
261 self.command(spi, Command::DataStartTransmission2)?;
262 self.interface.data_x_times(spi, 0x00, WIDTH / 8 * HEIGHT)?;
263
264 self.interface.cmd(spi, Command::DataStop)?;
265
266 self.command(spi, Command::DisplayRefresh)?;
267
268 Ok(())
269 }
270
271 fn set_background_color(&mut self, color: Self::DisplayColor) {
272 self.color = color;
273 }
274
275 fn background_color(&self) -> &Self::DisplayColor {
276 &self.color
277 }
278
279 fn width(&self) -> u32 {
280 WIDTH
281 }
282
283 fn height(&self) -> u32 {
284 HEIGHT
285 }
286
287 fn set_lut(
288 &mut self,
289 _spi: &mut SPI,
290 _delay: &mut DELAY,
291 _refresh_rate: Option<RefreshLut>,
292 ) -> Result<(), SPI::Error> {
293 unimplemented!();
294 }
295
296 fn wait_until_idle(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
298 self.interface
299 .wait_until_idle_with_cmd(spi, delay, IS_BUSY_LOW, Command::GetStatus)
300 }
301}
302
303impl<SPI, BUSY, DC, RST, DELAY> Epd7in5<SPI, BUSY, DC, RST, DELAY>
304where
305 SPI: SpiDevice,
306 BUSY: InputPin,
307 DC: OutputPin,
308 RST: OutputPin,
309 DELAY: DelayNs,
310{
311 #[allow(clippy::too_many_arguments)]
313 pub fn update_partial_frame2(
314 &mut self,
315 spi: &mut SPI,
316 buffer: &[u8],
317 x: u32,
318 y: u32,
319 width: u32,
320 height: u32,
321 delay: &mut DELAY,
322 ) -> Result<(), SPI::Error> {
323 self.wait_until_idle(spi, delay)?;
324 if buffer.len() as u32 != width / 8 * height {
325 }
327
328 let hrst_upper = (x / 8) as u8 >> 5;
329 let hrst_lower = ((x / 8) << 3) as u8;
330 let hred_upper = ((x + width) / 8 - 1) as u8 >> 5;
331 let hred_lower = (((x + width) / 8 - 1) << 3) as u8 | 0b111;
332 let vrst_upper = (y >> 8) as u8;
333 let vrst_lower = y as u8;
334 let vred_upper = ((y + height - 1) >> 8) as u8;
335 let vred_lower = (y + height - 1) as u8;
336 let pt_scan = 0x01; self.command(spi, Command::PartialIn)?;
339 self.cmd_with_data(
340 spi,
341 Command::PartialWindow,
342 &[
343 hrst_upper, hrst_lower, hred_upper, hred_lower, vrst_upper, vrst_lower, vred_upper,
344 vred_lower, pt_scan,
345 ],
346 )?;
347 let half = buffer.len() / 2;
348 self.cmd_with_data(spi, Command::DataStartTransmission1, &buffer[..half])?;
349 self.cmd_with_data(spi, Command::DataStartTransmission2, &buffer[half..])?;
350
351 self.command(spi, Command::DisplayRefresh)?;
352 self.wait_until_idle(spi, delay)?;
353
354 self.command(spi, Command::PartialOut)?;
355 Ok(())
356 }
357
358 fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> {
359 self.interface.cmd(spi, command)
360 }
361
362 fn send_data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> {
363 self.interface.data(spi, data)
364 }
365
366 fn cmd_with_data(
367 &mut self,
368 spi: &mut SPI,
369 command: Command,
370 data: &[u8],
371 ) -> Result<(), SPI::Error> {
372 self.interface.cmd_with_data(spi, command, data)
373 }
374
375 fn send_resolution(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
376 let w = self.width();
377 let h = self.height();
378
379 self.command(spi, Command::TconResolution)?;
380 self.send_data(spi, &[(w >> 8) as u8])?;
381 self.send_data(spi, &[w as u8])?;
382 self.send_data(spi, &[(h >> 8) as u8])?;
383 self.send_data(spi, &[h as u8])
384 }
385}
386
387#[cfg(test)]
388mod tests {
389 use super::*;
390
391 #[test]
392 fn epd_size() {
393 assert_eq!(WIDTH, 800);
394 assert_eq!(HEIGHT, 480);
395 assert_eq!(DEFAULT_BACKGROUND_COLOR, TriColor::White);
396 }
397}