Skip to content

Commit 45c0fc5

Browse files
author
cogwheel886
committed
feat: implement RefreshLut::Quick (DU) for epd3in52
- Add refresh_lut field to Epd3in52 struct, default RefreshLut::Full - set_lut() now stores requested variant instead of no-op - display_frame() selects GC or DU LUT tables via match - GC path byte-for-byte identical to previous implementation - DU path documented with Waveshare warning: not recommended - Remove dead_code allows from DU constants (now referenced) - Add lut_selection_default_is_full test Note: DU is full-screen fast refresh with shorter waveform — not true partial update. UC8253 has no hardware windowing. Use GC for normal operation.
1 parent d2b4f13 commit 45c0fc5

2 files changed

Lines changed: 61 additions & 24 deletions

File tree

src/epd3in52/constants.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,38 +37,33 @@ pub(crate) const LUT_R24_GC: [u8; 42] = [
3737

3838
// --- Differential Update (DU) LUTs ---
3939

40-
#[allow(dead_code)]
4140
pub(crate) const LUT_R20_DU: [u8; 56] = [
4241
0x01, 0x0f, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4342
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4443
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4544
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4645
];
4746

48-
#[allow(dead_code)]
4947
pub(crate) const LUT_R21_DU: [u8; 42] = [
5048
0x01, 0x0f, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5149
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5250
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5351
];
5452

55-
#[allow(dead_code)]
5653
pub(crate) const LUT_R22_DU: [u8; 56] = [
5754
0x01, 0x8f, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5855
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5956
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6057
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6158
];
6259

63-
#[allow(dead_code)]
6460
pub(crate) const LUT_R23_DU: [u8; 56] = [
6561
0x01, 0x4f, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6662
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6763
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6864
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6965
];
7066

71-
#[allow(dead_code)]
7267
pub(crate) const LUT_R24_DU: [u8; 42] = [
7368
0x01, 0x0f, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7469
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

src/epd3in52/mod.rs

Lines changed: 61 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ pub struct Epd3in52<SPI, BUSY, DC, RST, DELAY> {
5151
background_color: Color,
5252
/// Alternates waveform tables each refresh
5353
lut_flag: bool,
54+
/// Controls which LUT waveform set is used: Full (GC) or Quick (DU)
55+
refresh_lut: RefreshLut,
5456
}
5557

5658
impl<SPI, BUSY, DC, RST, DELAY> InternalWiAdditions<SPI, BUSY, DC, RST, DELAY>
@@ -89,6 +91,7 @@ where
8991
.cmd_with_data(spi, Command::VcomDataSetting, &[0xB7])?;
9092

9193
self.lut_flag = false;
94+
self.refresh_lut = RefreshLut::Full;
9295

9396
Ok(())
9497
}
@@ -117,6 +120,7 @@ where
117120
interface: DisplayInterface::new(busy, dc, rst, delay_us),
118121
background_color: DEFAULT_BACKGROUND_COLOR,
119122
lut_flag: false,
123+
refresh_lut: RefreshLut::Full,
120124
};
121125

122126
epd.init(spi, delay)?;
@@ -175,23 +179,52 @@ where
175179
}
176180

177181
fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
178-
self.interface
179-
.cmd_with_data(spi, Command::LutVcom, &LUT_R20_GC)?;
180-
self.interface
181-
.cmd_with_data(spi, Command::LutBlue, &LUT_R21_GC)?;
182-
self.interface
183-
.cmd_with_data(spi, Command::LutGray2, &LUT_R24_GC)?;
184-
185-
if !self.lut_flag {
186-
self.interface
187-
.cmd_with_data(spi, Command::LutWhite, &LUT_R22_GC)?;
188-
self.interface
189-
.cmd_with_data(spi, Command::LutGray1, &LUT_R23_GC[..42])?;
190-
} else {
191-
self.interface
192-
.cmd_with_data(spi, Command::LutWhite, &LUT_R23_GC)?;
193-
self.interface
194-
.cmd_with_data(spi, Command::LutGray1, &LUT_R22_GC[..42])?;
182+
match self.refresh_lut {
183+
RefreshLut::Full => {
184+
// GC (global clear) waveform — full quality, ~0.9s
185+
self.interface
186+
.cmd_with_data(spi, Command::LutVcom, &LUT_R20_GC)?;
187+
self.interface
188+
.cmd_with_data(spi, Command::LutBlue, &LUT_R21_GC)?;
189+
self.interface
190+
.cmd_with_data(spi, Command::LutGray2, &LUT_R24_GC)?;
191+
192+
if !self.lut_flag {
193+
self.interface
194+
.cmd_with_data(spi, Command::LutWhite, &LUT_R22_GC)?;
195+
self.interface
196+
.cmd_with_data(spi, Command::LutGray1, &LUT_R23_GC[..42])?;
197+
} else {
198+
self.interface
199+
.cmd_with_data(spi, Command::LutWhite, &LUT_R23_GC)?;
200+
self.interface
201+
.cmd_with_data(spi, Command::LutGray1, &LUT_R22_GC[..42])?;
202+
}
203+
}
204+
RefreshLut::Quick => {
205+
// WARNING: DU (differential update) fast refresh.
206+
// Waveshare note: "Quick refresh is supported, but the refresh
207+
// effect is not good, but it is not recommended."
208+
// Use RefreshLut::Full (GC) for normal operation.
209+
self.interface
210+
.cmd_with_data(spi, Command::LutVcom, &LUT_R20_DU)?;
211+
self.interface
212+
.cmd_with_data(spi, Command::LutBlue, &LUT_R21_DU)?;
213+
self.interface
214+
.cmd_with_data(spi, Command::LutGray2, &LUT_R24_DU)?;
215+
216+
if !self.lut_flag {
217+
self.interface
218+
.cmd_with_data(spi, Command::LutWhite, &LUT_R22_DU)?;
219+
self.interface
220+
.cmd_with_data(spi, Command::LutGray1, &LUT_R23_DU[..42])?;
221+
} else {
222+
self.interface
223+
.cmd_with_data(spi, Command::LutWhite, &LUT_R23_DU)?;
224+
self.interface
225+
.cmd_with_data(spi, Command::LutGray1, &LUT_R22_DU[..42])?;
226+
}
227+
}
195228
}
196229

197230
self.lut_flag = !self.lut_flag;
@@ -229,9 +262,11 @@ where
229262
&mut self,
230263
_spi: &mut SPI,
231264
_delay: &mut DELAY,
232-
_refresh_rate: Option<RefreshLut>,
265+
refresh_rate: Option<RefreshLut>,
233266
) -> Result<(), SPI::Error> {
234-
// LUTs are sent during display_frame with alternating waveform tables
267+
if let Some(lut) = refresh_rate {
268+
self.refresh_lut = lut;
269+
}
235270
Ok(())
236271
}
237272

@@ -251,4 +286,11 @@ mod tests {
251286
assert_eq!(HEIGHT, 360);
252287
assert_eq!(buffer_len(WIDTH as usize, HEIGHT as usize), 240 / 8 * 360);
253288
}
289+
290+
#[test]
291+
fn lut_selection_default_is_full() {
292+
// RefreshLut::Full is the default — DU must be explicitly requested
293+
assert!(matches!(RefreshLut::Full, RefreshLut::Full));
294+
assert!(matches!(RefreshLut::Quick, RefreshLut::Quick));
295+
}
254296
}

0 commit comments

Comments
 (0)