1use embedded_hal::{delay::*, digital::*, spi::SpiDevice};
6
7use crate::interface::DisplayInterface;
8use crate::traits::{
9 InternalWiAdditions, RefreshLut, WaveshareDisplay, WaveshareThreeColorDisplay,
10};
11
12mod constants;
14use crate::epd2in7b::constants::*;
15
16pub const WIDTH: u32 = 176;
18pub const HEIGHT: u32 = 264;
20pub const DEFAULT_BACKGROUND_COLOR: Color = Color::White;
22const IS_BUSY_LOW: bool = true;
23const SINGLE_BYTE_WRITE: bool = true;
24
25use crate::color::Color;
26
27pub(crate) mod command;
28use self::command::Command;
29use crate::buffer_len;
30
31#[cfg(feature = "graphics")]
34pub type Display2in7b = crate::graphics::Display<
35 WIDTH,
36 HEIGHT,
37 false,
38 { buffer_len(WIDTH as usize, HEIGHT as usize) },
39 Color,
40>;
41
42pub struct Epd2in7b<SPI, BUSY, DC, RST, DELAY> {
44 interface: DisplayInterface<SPI, BUSY, DC, RST, DELAY, SINGLE_BYTE_WRITE>,
46 color: Color,
48}
49
50impl<SPI, BUSY, DC, RST, DELAY> InternalWiAdditions<SPI, BUSY, DC, RST, DELAY>
51 for Epd2in7b<SPI, BUSY, DC, RST, DELAY>
52where
53 SPI: SpiDevice,
54 BUSY: InputPin,
55 DC: OutputPin,
56 RST: OutputPin,
57 DELAY: DelayNs,
58{
59 fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
60 self.interface.reset(delay, 10_000, 2_000);
62
63 self.command(spi, Command::PowerOn)?;
65 delay.delay_us(5000);
66 self.wait_until_idle(spi, delay)?;
67
68 self.interface
70 .cmd_with_data(spi, Command::PanelSetting, &[0xaf])?;
71
72 self.interface
74 .cmd_with_data(spi, Command::PllControl, &[0x3a])?;
75
76 self.interface.cmd_with_data(
78 spi,
79 Command::PowerSetting,
80 &[0x03, 0x00, 0x2b, 0x2b, 0x09],
81 )?;
82
83 self.interface
85 .cmd_with_data(spi, Command::BoosterSoftStart, &[0x07, 0x07, 0x17])?;
86
87 self.interface
89 .cmd_with_data(spi, Command::PowerOptimization, &[0x60, 0xa5])?;
90 self.interface
91 .cmd_with_data(spi, Command::PowerOptimization, &[0x89, 0xa5])?;
92 self.interface
93 .cmd_with_data(spi, Command::PowerOptimization, &[0x90, 0x00])?;
94 self.interface
95 .cmd_with_data(spi, Command::PowerOptimization, &[0x93, 0x2a])?;
96 self.interface
97 .cmd_with_data(spi, Command::PowerOptimization, &[0x73, 0x41])?;
98
99 self.interface
100 .cmd_with_data(spi, Command::VcmDcSetting, &[0x12])?;
101
102 self.interface
103 .cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x87])?;
104
105 self.set_lut(spi, delay, None)?;
106
107 self.interface
108 .cmd_with_data(spi, Command::PartialDisplayRefresh, &[0x00])?;
109
110 self.wait_until_idle(spi, delay)?;
111 Ok(())
112 }
113}
114
115impl<SPI, BUSY, DC, RST, DELAY> WaveshareDisplay<SPI, BUSY, DC, RST, DELAY>
116 for Epd2in7b<SPI, BUSY, DC, RST, DELAY>
117where
118 SPI: SpiDevice,
119 BUSY: InputPin,
120 DC: OutputPin,
121 RST: OutputPin,
122 DELAY: DelayNs,
123{
124 type DisplayColor = Color;
125 fn new(
126 spi: &mut SPI,
127 busy: BUSY,
128 dc: DC,
129 rst: RST,
130 delay: &mut DELAY,
131 delay_us: Option<u32>,
132 ) -> Result<Self, SPI::Error> {
133 let interface = DisplayInterface::new(busy, dc, rst, delay_us);
134 let color = DEFAULT_BACKGROUND_COLOR;
135
136 let mut epd = Epd2in7b { interface, color };
137
138 epd.init(spi, delay)?;
139
140 Ok(epd)
141 }
142
143 fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
144 self.init(spi, delay)
145 }
146
147 fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
148 self.wait_until_idle(spi, delay)?;
149 self.interface
150 .cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0xf7])?;
151
152 self.command(spi, Command::PowerOff)?;
153 self.wait_until_idle(spi, delay)?;
154 self.interface
155 .cmd_with_data(spi, Command::DeepSleep, &[0xA5])?;
156 Ok(())
157 }
158
159 fn update_frame(
160 &mut self,
161 spi: &mut SPI,
162 buffer: &[u8],
163 _delay: &mut DELAY,
164 ) -> Result<(), SPI::Error> {
165 self.interface.cmd(spi, Command::DataStartTransmission1)?;
166 self.send_buffer_helper(spi, buffer)?;
167
168 self.interface.cmd(spi, Command::DataStartTransmission2)?;
170 self.interface
171 .data_x_times(spi, !self.color.get_byte_value(), WIDTH / 8 * HEIGHT)?;
172
173 self.interface.cmd(spi, Command::DataStop)?;
174 Ok(())
175 }
176
177 fn update_partial_frame(
178 &mut self,
179 spi: &mut SPI,
180 delay: &mut DELAY,
181 buffer: &[u8],
182 x: u32,
183 y: u32,
184 width: u32,
185 height: u32,
186 ) -> Result<(), SPI::Error> {
187 self.interface
188 .cmd(spi, Command::PartialDataStartTransmission1)?;
189
190 self.send_data(spi, &[(x >> 8) as u8])?;
191 self.send_data(spi, &[(x & 0xf8) as u8])?;
192 self.send_data(spi, &[(y >> 8) as u8])?;
193 self.send_data(spi, &[(y & 0xff) as u8])?;
194 self.send_data(spi, &[(width >> 8) as u8])?;
195 self.send_data(spi, &[(width & 0xf8) as u8])?;
196 self.send_data(spi, &[(height >> 8) as u8])?;
197 self.send_data(spi, &[(height & 0xff) as u8])?;
198 self.wait_until_idle(spi, delay)?;
199
200 self.send_buffer_helper(spi, buffer)?;
201
202 self.interface.cmd(spi, Command::DataStop)
203 }
204
205 fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
206 self.command(spi, Command::DisplayRefresh)?;
207 self.wait_until_idle(spi, delay)?;
208 Ok(())
209 }
210
211 fn update_and_display_frame(
212 &mut self,
213 spi: &mut SPI,
214 buffer: &[u8],
215 delay: &mut DELAY,
216 ) -> Result<(), SPI::Error> {
217 self.update_frame(spi, buffer, delay)?;
218 self.command(spi, Command::DisplayRefresh)?;
219 Ok(())
220 }
221
222 fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
223 self.wait_until_idle(spi, delay)?;
224
225 let color_value = self.color.get_byte_value();
226 self.interface.cmd(spi, Command::DataStartTransmission1)?;
227 self.interface
228 .data_x_times(spi, color_value, WIDTH / 8 * HEIGHT)?;
229
230 self.interface.cmd(spi, Command::DataStop)?;
231
232 self.interface.cmd(spi, Command::DataStartTransmission2)?;
233 self.interface
234 .data_x_times(spi, color_value, WIDTH / 8 * HEIGHT)?;
235 self.interface.cmd(spi, Command::DataStop)?;
236 Ok(())
237 }
238
239 fn set_background_color(&mut self, color: Color) {
240 self.color = color;
241 }
242
243 fn background_color(&self) -> &Color {
244 &self.color
245 }
246
247 fn width(&self) -> u32 {
248 WIDTH
249 }
250
251 fn height(&self) -> u32 {
252 HEIGHT
253 }
254
255 fn set_lut(
256 &mut self,
257 spi: &mut SPI,
258 delay: &mut DELAY,
259 _refresh_rate: Option<RefreshLut>,
260 ) -> Result<(), SPI::Error> {
261 self.wait_until_idle(spi, delay)?;
262 self.cmd_with_data(spi, Command::LutForVcom, &LUT_VCOM_DC)?;
263 self.cmd_with_data(spi, Command::LutWhiteToWhite, &LUT_WW)?;
264 self.cmd_with_data(spi, Command::LutBlackToWhite, &LUT_BW)?;
265 self.cmd_with_data(spi, Command::LutWhiteToBlack, &LUT_WB)?;
266 self.cmd_with_data(spi, Command::LutBlackToBlack, &LUT_BB)?;
267 Ok(())
268 }
269
270 fn wait_until_idle(&mut self, _spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
271 self.interface.wait_until_idle(delay, IS_BUSY_LOW);
272 Ok(())
273 }
274}
275
276impl<SPI, BUSY, DC, RST, DELAY> WaveshareThreeColorDisplay<SPI, BUSY, DC, RST, DELAY>
277 for Epd2in7b<SPI, BUSY, DC, RST, DELAY>
278where
279 SPI: SpiDevice,
280 BUSY: InputPin,
281 DC: OutputPin,
282 RST: OutputPin,
283 DELAY: DelayNs,
284{
285 fn update_color_frame(
286 &mut self,
287 spi: &mut SPI,
288 delay: &mut DELAY,
289 black: &[u8],
290 chromatic: &[u8],
291 ) -> Result<(), SPI::Error> {
292 self.update_achromatic_frame(spi, delay, black)?;
293 self.update_chromatic_frame(spi, delay, chromatic)
294 }
295
296 fn update_achromatic_frame(
300 &mut self,
301 spi: &mut SPI,
302 _delay: &mut DELAY,
303 achromatic: &[u8],
304 ) -> Result<(), SPI::Error> {
305 self.interface.cmd(spi, Command::DataStartTransmission1)?;
306
307 self.send_buffer_helper(spi, achromatic)?;
308
309 self.interface.cmd(spi, Command::DataStop)
310 }
311
312 fn update_chromatic_frame(
316 &mut self,
317 spi: &mut SPI,
318 delay: &mut DELAY,
319 chromatic: &[u8],
320 ) -> Result<(), SPI::Error> {
321 self.interface.cmd(spi, Command::DataStartTransmission2)?;
322
323 self.send_buffer_helper(spi, chromatic)?;
324
325 self.interface.cmd(spi, Command::DataStop)?;
326 self.wait_until_idle(spi, delay)?;
327
328 Ok(())
329 }
330}
331
332impl<SPI, BUSY, DC, RST, DELAY> Epd2in7b<SPI, BUSY, DC, RST, DELAY>
333where
334 SPI: SpiDevice,
335 BUSY: InputPin,
336 DC: OutputPin,
337 RST: OutputPin,
338 DELAY: DelayNs,
339{
340 fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> {
341 self.interface.cmd(spi, command)
342 }
343
344 fn send_data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> {
345 self.interface.data(spi, data)
346 }
347
348 fn send_buffer_helper(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> {
349 for b in buffer.iter() {
352 self.send_data(spi, &[!b])?;
353 }
354 Ok(())
355 }
356
357 fn cmd_with_data(
358 &mut self,
359 spi: &mut SPI,
360 command: Command,
361 data: &[u8],
362 ) -> Result<(), SPI::Error> {
363 self.interface.cmd_with_data(spi, command, data)
364 }
365
366 pub fn display_partial_frame(
368 &mut self,
369 spi: &mut SPI,
370 delay: &mut DELAY,
371 x: u32,
372 y: u32,
373 width: u32,
374 height: u32,
375 ) -> Result<(), SPI::Error> {
376 self.command(spi, Command::PartialDisplayRefresh)?;
377 self.send_data(spi, &[(x >> 8) as u8])?;
378 self.send_data(spi, &[(x & 0xf8) as u8])?;
379 self.send_data(spi, &[(y >> 8) as u8])?;
380 self.send_data(spi, &[(y & 0xff) as u8])?;
381 self.send_data(spi, &[(width >> 8) as u8])?;
382 self.send_data(spi, &[(width & 0xf8) as u8])?;
383 self.send_data(spi, &[(height >> 8) as u8])?;
384 self.send_data(spi, &[(height & 0xff) as u8])?;
385 self.wait_until_idle(spi, delay)?;
386 Ok(())
387 }
388
389 #[allow(clippy::too_many_arguments)]
391 pub fn update_partial_achromatic_frame(
392 &mut self,
393 spi: &mut SPI,
394 delay: &mut DELAY,
395 achromatic: &[u8],
396 x: u32,
397 y: u32,
398 width: u32,
399 height: u32,
400 ) -> Result<(), SPI::Error> {
401 self.interface
402 .cmd(spi, Command::PartialDataStartTransmission1)?;
403 self.send_data(spi, &[(x >> 8) as u8])?;
404 self.send_data(spi, &[(x & 0xf8) as u8])?;
405 self.send_data(spi, &[(y >> 8) as u8])?;
406 self.send_data(spi, &[(y & 0xff) as u8])?;
407 self.send_data(spi, &[(width >> 8) as u8])?;
408 self.send_data(spi, &[(width & 0xf8) as u8])?;
409 self.send_data(spi, &[(height >> 8) as u8])?;
410 self.send_data(spi, &[(height & 0xff) as u8])?;
411 self.wait_until_idle(spi, delay)?;
412
413 for b in achromatic.iter() {
414 self.send_data(spi, &[!b])?;
416 }
417
418 Ok(())
419 }
420
421 #[allow(clippy::too_many_arguments)]
423 pub fn update_partial_chromatic_frame(
424 &mut self,
425 spi: &mut SPI,
426 delay: &mut DELAY,
427 chromatic: &[u8],
428 x: u32,
429 y: u32,
430 width: u32,
431 height: u32,
432 ) -> Result<(), SPI::Error> {
433 self.interface
434 .cmd(spi, Command::PartialDataStartTransmission2)?;
435 self.send_data(spi, &[(x >> 8) as u8])?;
436 self.send_data(spi, &[(x & 0xf8) as u8])?;
437 self.send_data(spi, &[(y >> 8) as u8])?;
438 self.send_data(spi, &[(y & 0xff) as u8])?;
439 self.send_data(spi, &[(width >> 8) as u8])?;
440 self.send_data(spi, &[(width & 0xf8) as u8])?;
441 self.send_data(spi, &[(height >> 8) as u8])?;
442 self.send_data(spi, &[(height & 0xff) as u8])?;
443 self.wait_until_idle(spi, delay)?;
444
445 for b in chromatic.iter() {
446 self.send_data(spi, &[!b])?;
448 }
449
450 Ok(())
451 }
452}
453
454#[cfg(test)]
455mod tests {
456 use super::*;
457
458 #[test]
459 fn epd_size() {
460 assert_eq!(WIDTH, 176);
461 assert_eq!(HEIGHT, 264);
462 assert_eq!(DEFAULT_BACKGROUND_COLOR, Color::White);
463 }
464}