1pub const WIDTH: u32 = 128;
46pub const HEIGHT: u32 = 296;
48pub const DEFAULT_BACKGROUND_COLOR: Color = Color::White;
50const IS_BUSY_LOW: bool = false;
51const SINGLE_BYTE_WRITE: bool = true;
52
53use embedded_hal::{delay::*, digital::*, spi::SpiDevice};
54
55use crate::type_a::{
56 command::Command,
57 constants::{LUT_FULL_UPDATE, LUT_PARTIAL_UPDATE},
58};
59
60use crate::color::Color;
61
62use crate::traits::*;
63
64use crate::buffer_len;
65use crate::interface::DisplayInterface;
66
67#[cfg(feature = "graphics")]
69pub type Display2in9 = crate::graphics::Display<
70 WIDTH,
71 HEIGHT,
72 false,
73 { buffer_len(WIDTH as usize, HEIGHT as usize) },
74 Color,
75>;
76
77pub struct Epd2in9<SPI, BUSY, DC, RST, DELAY> {
80 interface: DisplayInterface<SPI, BUSY, DC, RST, DELAY, SINGLE_BYTE_WRITE>,
82 background_color: Color,
84 refresh: RefreshLut,
86}
87
88impl<SPI, BUSY, DC, RST, DELAY> Epd2in9<SPI, BUSY, DC, RST, DELAY>
89where
90 SPI: SpiDevice,
91 BUSY: InputPin,
92 DC: OutputPin,
93 RST: OutputPin,
94 DELAY: DelayNs,
95{
96 fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
97 self.interface.reset(delay, 10_000, 10_000);
98
99 self.wait_until_idle(spi, delay)?;
100
101 self.interface
107 .cmd_with_data(spi, Command::DriverOutputControl, &[0x27, 0x01, 0x00])?;
108
109 self.interface
115 .cmd_with_data(spi, Command::BoosterSoftStartControl, &[0xD7, 0xD6, 0x9D])?;
116
117 self.interface
119 .cmd_with_data(spi, Command::WriteVcomRegister, &[0xA8])?;
120
121 self.interface
123 .cmd_with_data(spi, Command::SetDummyLinePeriod, &[0x1A])?;
124
125 self.interface
127 .cmd_with_data(spi, Command::SetGateLineWidth, &[0x08])?;
128
129 self.interface
132 .cmd_with_data(spi, Command::DataEntryModeSetting, &[0x03])?;
133
134 self.set_lut(spi, delay, None)
135 }
136}
137
138impl<SPI, BUSY, DC, RST, DELAY> WaveshareDisplay<SPI, BUSY, DC, RST, DELAY>
139 for Epd2in9<SPI, BUSY, DC, RST, DELAY>
140where
141 SPI: SpiDevice,
142 BUSY: InputPin,
143 DC: OutputPin,
144 RST: OutputPin,
145 DELAY: DelayNs,
146{
147 type DisplayColor = Color;
148 fn width(&self) -> u32 {
149 WIDTH
150 }
151
152 fn height(&self) -> u32 {
153 HEIGHT
154 }
155
156 fn new(
157 spi: &mut SPI,
158 busy: BUSY,
159 dc: DC,
160 rst: RST,
161 delay: &mut DELAY,
162 delay_us: Option<u32>,
163 ) -> Result<Self, SPI::Error> {
164 let interface = DisplayInterface::new(busy, dc, rst, delay_us);
165
166 let mut epd = Epd2in9 {
167 interface,
168 background_color: DEFAULT_BACKGROUND_COLOR,
169 refresh: RefreshLut::Full,
170 };
171
172 epd.init(spi, delay)?;
173
174 Ok(epd)
175 }
176
177 fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
178 self.wait_until_idle(spi, delay)?;
179 self.interface
182 .cmd_with_data(spi, Command::DeepSleepMode, &[0x00])?;
183 Ok(())
184 }
185
186 fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
187 self.wait_until_idle(spi, delay)?;
188 self.init(spi, delay)?;
189 Ok(())
190 }
191
192 fn update_frame(
193 &mut self,
194 spi: &mut SPI,
195 buffer: &[u8],
196 delay: &mut DELAY,
197 ) -> Result<(), SPI::Error> {
198 self.wait_until_idle(spi, delay)?;
199 self.use_full_frame(spi, delay)?;
200
201 self.interface
202 .cmd_with_data(spi, Command::WriteRam, buffer)?;
203 Ok(())
204 }
205
206 fn update_partial_frame(
208 &mut self,
209 spi: &mut SPI,
210 delay: &mut DELAY,
211 buffer: &[u8],
212 x: u32,
213 y: u32,
214 width: u32,
215 height: u32,
216 ) -> Result<(), SPI::Error> {
217 self.wait_until_idle(spi, delay)?;
218 self.set_ram_area(spi, x, y, x + width, y + height)?;
219 self.set_ram_counter(spi, delay, x, y)?;
220
221 self.interface
222 .cmd_with_data(spi, Command::WriteRam, buffer)?;
223 Ok(())
224 }
225
226 fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
227 self.wait_until_idle(spi, delay)?;
228 self.interface
231 .cmd_with_data(spi, Command::DisplayUpdateControl2, &[0xC4])?;
232
233 self.interface.cmd(spi, Command::MasterActivation)?;
234 self.interface.cmd(spi, Command::Nop)?;
237 Ok(())
238 }
239
240 fn update_and_display_frame(
241 &mut self,
242 spi: &mut SPI,
243 buffer: &[u8],
244 delay: &mut DELAY,
245 ) -> Result<(), SPI::Error> {
246 self.update_frame(spi, buffer, delay)?;
247 self.display_frame(spi, delay)?;
248 Ok(())
249 }
250
251 fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
252 self.wait_until_idle(spi, delay)?;
253 self.use_full_frame(spi, delay)?;
254
255 let color = self.background_color.get_byte_value();
257
258 self.interface.cmd(spi, Command::WriteRam)?;
259 self.interface
260 .data_x_times(spi, color, WIDTH / 8 * HEIGHT)?;
261 Ok(())
262 }
263
264 fn set_background_color(&mut self, background_color: Color) {
265 self.background_color = background_color;
266 }
267
268 fn background_color(&self) -> &Color {
269 &self.background_color
270 }
271
272 fn set_lut(
273 &mut self,
274 spi: &mut SPI,
275 delay: &mut DELAY,
276 refresh_rate: Option<RefreshLut>,
277 ) -> Result<(), SPI::Error> {
278 if let Some(refresh_lut) = refresh_rate {
279 self.refresh = refresh_lut;
280 }
281 match self.refresh {
282 RefreshLut::Full => self.set_lut_helper(spi, delay, &LUT_FULL_UPDATE),
283 RefreshLut::Quick => self.set_lut_helper(spi, delay, &LUT_PARTIAL_UPDATE),
284 }
285 }
286
287 fn wait_until_idle(&mut self, _spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
288 self.interface.wait_until_idle(delay, IS_BUSY_LOW);
289 Ok(())
290 }
291}
292
293impl<SPI, BUSY, DC, RST, DELAY> Epd2in9<SPI, BUSY, DC, RST, DELAY>
294where
295 SPI: SpiDevice,
296 BUSY: InputPin,
297 DC: OutputPin,
298 RST: OutputPin,
299 DELAY: DelayNs,
300{
301 fn use_full_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
302 self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1)?;
304
305 self.set_ram_counter(spi, delay, 0, 0)
307 }
308
309 fn set_ram_area(
310 &mut self,
311 spi: &mut SPI,
312 start_x: u32,
313 start_y: u32,
314 end_x: u32,
315 end_y: u32,
316 ) -> Result<(), SPI::Error> {
317 assert!(start_x < end_x);
318 assert!(start_y < end_y);
319
320 self.interface.cmd_with_data(
323 spi,
324 Command::SetRamXAddressStartEndPosition,
325 &[(start_x >> 3) as u8, (end_x >> 3) as u8],
326 )?;
327
328 self.interface.cmd_with_data(
330 spi,
331 Command::SetRamYAddressStartEndPosition,
332 &[
333 start_y as u8,
334 (start_y >> 8) as u8,
335 end_y as u8,
336 (end_y >> 8) as u8,
337 ],
338 )
339 }
340
341 fn set_ram_counter(
342 &mut self,
343 spi: &mut SPI,
344 delay: &mut DELAY,
345 x: u32,
346 y: u32,
347 ) -> Result<(), SPI::Error> {
348 self.wait_until_idle(spi, delay)?;
349 self.interface
352 .cmd_with_data(spi, Command::SetRamXAddressCounter, &[(x >> 3) as u8])?;
353
354 self.interface.cmd_with_data(
356 spi,
357 Command::SetRamYAddressCounter,
358 &[y as u8, (y >> 8) as u8],
359 )?;
360 Ok(())
361 }
362
363 fn set_lut_helper(
365 &mut self,
366 spi: &mut SPI,
367 delay: &mut DELAY,
368 buffer: &[u8],
369 ) -> Result<(), SPI::Error> {
370 self.wait_until_idle(spi, delay)?;
371 assert!(buffer.len() == 30);
372 self.interface
373 .cmd_with_data(spi, Command::WriteLutRegister, buffer)?;
374 Ok(())
375 }
376}
377
378#[cfg(test)]
379mod tests {
380 use super::*;
381
382 #[test]
383 fn epd_size() {
384 assert_eq!(WIDTH, 128);
385 assert_eq!(HEIGHT, 296);
386 assert_eq!(DEFAULT_BACKGROUND_COLOR, Color::White);
387 }
388}