1use embedded_hal as hal;
2
3use hal::delay::DelayNs;
4use hal::digital::OutputPin;
5use hal::pwm::SetDutyCycle;
6use hal::spi::SpiBus;
7
8use crate::commands::*;
9use crate::utils::{color_buffer, u16_to_bytes};
10
11const COLUMNS: u16 = 240;
12const PAGES: u16 = 320;
13
14#[derive(Debug)]
15pub enum LcdError {
16 PinError,
17 SpiError,
18}
19
20#[derive(Debug)]
23pub enum LcdOrientation {
24 Rotate0,
25 Rotate90,
26 Rotate180,
27 Rotate270,
28}
29
30pub struct Lcd<T, U, V, W> {
38 spi: T,
39 dc_pin: U, rst_pin: V, bl_pin: W, orientation: LcdOrientation,
43 max_buffer_size: usize,
44}
45
46impl<T, U, V, W> Lcd<T, U, V, W>
47where
48 T: SpiBus,
49 U: OutputPin,
50 V: OutputPin,
51 W: SetDutyCycle,
52{
53 pub fn new(spi: T, dc_pin: U, rst_pin: V, bl_pin: W) -> Self {
54 Self {
55 spi,
56 dc_pin,
57 rst_pin,
58 bl_pin,
59 orientation: LcdOrientation::Rotate0,
60 max_buffer_size: 32,
61 }
62 }
63 pub fn with_orientation(mut self, orientation: LcdOrientation) -> Self {
78 self.orientation = orientation;
79 self
80 }
81
82 pub fn with_max_buffer_size(mut self, size: usize) -> Self {
84 self.max_buffer_size = size;
85 self
86 }
87
88 fn size(&self) -> (u16, u16) {
89 match self.orientation {
90 LcdOrientation::Rotate0 | LcdOrientation::Rotate180 => (COLUMNS, PAGES),
91 LcdOrientation::Rotate90 | LcdOrientation::Rotate270 => (PAGES, COLUMNS),
92 }
93 }
94
95 fn memory_access_control_value(&self) -> u8 {
96 let orientation = match self.orientation {
97 LcdOrientation::Rotate0 => 0b00000000,
98 LcdOrientation::Rotate90 => 0b01100000,
99 LcdOrientation::Rotate180 => 0b11000000,
100 LcdOrientation::Rotate270 => 0b10100000,
101 };
102 orientation | 0b00001000
103 }
104
105 pub fn reset<D>(&mut self, delay: &mut D) -> Result<(), LcdError>
106 where
107 D: DelayNs,
108 {
109 delay.delay_ms(200);
111 self.rst_pin.set_low().map_err(|_| LcdError::PinError)?;
112 delay.delay_ms(200);
113 self.rst_pin.set_high().map_err(|_| LcdError::PinError)?;
114 delay.delay_ms(200);
115 Ok(())
116 }
117
118 pub fn set_backlight(&mut self, value: u16) -> Result<(), LcdError> {
119 self.bl_pin
120 .set_duty_cycle(value)
121 .map_err(|_| LcdError::PinError)?;
122 Ok(())
123 }
124
125 fn write_command(&mut self, cmd: u8) -> Result<(), LcdError> {
126 self.dc_pin.set_low().map_err(|_| LcdError::PinError)?;
127 self.spi.write(&[cmd]).map_err(|_| LcdError::SpiError)?;
128 Ok(())
129 }
130
131 #[inline(always)]
133 pub(crate) fn enable_write_data(&mut self) -> Result<(), LcdError> {
134 self.dc_pin.set_high().map_err(|_| LcdError::PinError)?;
135 Ok(())
136 }
137
138 #[inline(always)]
140 pub(crate) fn write_data(&mut self, data: &[u8]) -> Result<(), LcdError> {
141 let mut offset = 0;
142 self.enable_write_data()?;
143 while offset < data.len() {
144 let end = data.len().min(offset + self.max_buffer_size);
145 self.write_data_continue(&data[offset..end])?;
146 offset += self.max_buffer_size;
147 }
148 Ok(())
149 }
150
151 #[inline(always)]
154 pub(crate) fn write_data_continue(&mut self, data: &[u8]) -> Result<(), LcdError> {
155 self.spi.write(data).map_err(|_| LcdError::SpiError)?;
156 Ok(())
157 }
158
159 pub fn init<D>(&mut self, delay: &mut D) -> Result<(), LcdError>
160 where
161 D: DelayNs,
162 {
163 self.reset(delay)?;
165
166 self.write_command(SLEEP_OUT)?;
167
168 self.write_command(POWER_CONTROL_B)?;
169 self.write_data(&[0x00])?;
170 self.write_data(&[0xC1])?;
171 self.write_data(&[0x30])?;
172 self.write_command(POWER_ON_SEQ_CONTROL)?;
173 self.write_data(&[0x64])?;
174 self.write_data(&[0x03])?;
175 self.write_data(&[0x12])?;
176 self.write_data(&[0x81])?;
177 self.write_command(DRIVER_TIMING_CONTROL_A)?;
178 self.write_data(&[0x85])?;
179 self.write_data(&[0x00])?;
180 self.write_data(&[0x79])?;
181 self.write_command(POWER_CONTROL_A)?;
182 self.write_data(&[0x39])?;
183 self.write_data(&[0x2C])?;
184 self.write_data(&[0x00])?;
185 self.write_data(&[0x34])?;
186 self.write_data(&[0x02])?;
187 self.write_command(PUMP_RATIO_CONTROL)?;
188 self.write_data(&[0x20])?;
189 self.write_command(DRIVER_TIMING_CONTROL_B)?;
190 self.write_data(&[0x00])?;
191 self.write_data(&[0x00])?;
192 self.write_command(POWER_CONTROL_1)?;
193 self.write_data(&[0x1D])?;
194 self.write_command(POWER_CONTROL_2)?;
195 self.write_data(&[0x12])?;
196 self.write_command(VCOM_CONTROL_1)?;
197 self.write_data(&[0x33])?;
198 self.write_data(&[0x3F])?;
199 self.write_command(VCOM_CONTROL_2)?;
200 self.write_data(&[0x92])?;
201 self.write_command(PIXEL_FORMAT_SET)?;
202 self.write_data(&[0x55])?;
203 self.write_command(MEMORY_ACCESS_CONTROL)?;
204 self.write_data(&[self.memory_access_control_value()])?;
205 self.write_command(FRAME_CONTROL_NORMAL_MODE)?;
206 self.write_data(&[0x00])?;
207 self.write_data(&[0x12])?;
208 self.write_command(DISPLAY_FUNCTION_CONTROL)?;
209 self.write_data(&[0x0A])?;
210 self.write_data(&[0xA2])?;
211
212 self.write_command(SET_TEAR_SCANLINE)?;
213 self.write_data(&[0x02])?;
214
215 self.write_command(DISPLAY_ON)?;
216 self.set_gamma()?;
217
218 self.set_backlight(255)?;
219
220 Ok(())
221 }
222
223 fn set_gamma(&mut self) -> Result<(), LcdError> {
224 self.write_command(ENABLE_3G)?;
225 self.write_data(&[0x00])?;
226 self.write_command(GAMMA_SET)?;
227 self.write_data(&[0x01])?;
228 self.write_command(POSITIVE_GAMMA_CORRECTION)?;
229 self.write_data(&[0x0F])?;
230 self.write_data(&[0x22])?;
231 self.write_data(&[0x1C])?;
232 self.write_data(&[0x1B])?;
233 self.write_data(&[0x08])?;
234 self.write_data(&[0x0F])?;
235 self.write_data(&[0x48])?;
236 self.write_data(&[0xB8])?;
237 self.write_data(&[0x34])?;
238 self.write_data(&[0x05])?;
239 self.write_data(&[0x0C])?;
240 self.write_data(&[0x09])?;
241 self.write_data(&[0x0F])?;
242 self.write_data(&[0x07])?;
243 self.write_data(&[0x00])?;
244 self.write_command(NEGATIVE_GAMMA_CORRECTION)?;
245 self.write_data(&[0x00])?;
246 self.write_data(&[0x23])?;
247 self.write_data(&[0x24])?;
248 self.write_data(&[0x07])?;
249 self.write_data(&[0x10])?;
250 self.write_data(&[0x07])?;
251 self.write_data(&[0x38])?;
252 self.write_data(&[0x47])?;
253 self.write_data(&[0x4B])?;
254 self.write_data(&[0x0A])?;
255 self.write_data(&[0x13])?;
256 self.write_data(&[0x06])?;
257 self.write_data(&[0x30])?;
258 self.write_data(&[0x38])?;
259 self.write_data(&[0x0F])?;
260 Ok(())
261 }
262
263 pub fn display_on(&mut self) -> Result<(), LcdError> {
265 self.write_command(DISPLAY_ON)
266 }
267
268 pub fn display_off(&mut self) -> Result<(), LcdError> {
270 self.write_command(DISPLAY_OFF)
271 }
272
273 pub fn enter_sleep_mode(&mut self) -> Result<(), LcdError> {
275 self.write_command(ENTER_SLEEP_MODE)
276 }
277
278 pub fn leave_sleep_mode(&mut self) -> Result<(), LcdError> {
280 self.write_command(SLEEP_OUT)
281 }
282
283 pub(crate) fn set_window(
284 &mut self,
285 x0: u16,
286 y0: u16,
287 x1: u16,
288 y1: u16,
289 ) -> Result<(), LcdError> {
290 let c1 = x1.saturating_sub(1).max(x0);
291 let p1 = y1.saturating_sub(1).max(y0);
292 let (c0h, c0l) = u16_to_bytes(x0);
293 let (c1h, c1l) = u16_to_bytes(c1);
294 let (p0h, p0l) = u16_to_bytes(y0);
295 let (p1h, p1l) = u16_to_bytes(p1);
296
297 self.write_command(COLUMN_ADDRESS_SET)?;
298 self.write_data(&[c0h, c0l, c1h, c1l])?;
299
300 self.write_command(PAGE_ADDRESS_SET)?;
301 self.write_data(&[p0h, p0l, p1h, p1l])?;
302
303 self.write_command(MEMORY_WRITE)?;
304 Ok(())
305 }
306
307 pub fn clear(&mut self, color: u16) -> Result<(), LcdError> {
309 let (w, h) = self.size();
310 self.fill_rect(0, 0, w, h, color)?;
311
312 Ok(())
313 }
314
315 pub fn fill_rect(
317 &mut self,
318 x: u16,
319 y: u16,
320 w: u16,
321 h: u16,
322 color: u16,
323 ) -> Result<(), LcdError> {
324 self.set_window(x, y, x + w, y + h)?;
325 self.enable_write_data()?;
326
327 let chunk = color_buffer::<32>(color);
330 for _ in 0..(w as u32 * h as u32).div_ceil(16) {
331 self.write_data_continue(&chunk)?;
332 }
333 Ok(())
334 }
335
336 pub fn draw_sprite(
342 &mut self,
343 x: u16,
344 y: u16,
345 w: u16,
346 h: u16,
347 data: &[u8],
348 ) -> Result<(), LcdError> {
349 self.set_window(x, y, x + w, y + h)?;
350 self.write_data(&data)?;
351 Ok(())
352 }
353}