1#![no_std]
4
5use embedded_graphics_core::pixelcolor::Rgb565;
6use embedded_graphics_core::prelude::*;
7use embedded_hal::delay::DelayNs;
8use embedded_hal::digital::OutputPin;
9
10pub mod blocking;
11
12pub mod cmds {
13 pub const NOP: u8 = 0x00;
14 pub const SWRESET: u8 = 0x01;
15 pub const RDDID: u8 = 0x04;
16 pub const RDDST: u8 = 0x09;
17 pub const SLPIN: u8 = 0x10;
18 pub const SLPOUT: u8 = 0x11;
19 pub const PTLON: u8 = 0x12;
20 pub const NORON: u8 = 0x13;
21 pub const INVOFF: u8 = 0x20;
22 pub const INVON: u8 = 0x21;
23 pub const DISPOFF: u8 = 0x28;
24 pub const DISPON: u8 = 0x29;
25 pub const CASET: u8 = 0x2A;
26 pub const RASET: u8 = 0x2B;
27 pub const RAMWR: u8 = 0x2C;
28 pub const RAMRD: u8 = 0x2E;
29 pub const PTLAR: u8 = 0x30;
30 pub const COLMOD: u8 = 0x3A;
31 pub const MADCTL: u8 = 0x36;
32 pub const FRMCTR1: u8 = 0xB1;
33 pub const FRMCTR2: u8 = 0xB2;
34 pub const FRMCTR3: u8 = 0xB3;
35 pub const INVCTR: u8 = 0xB4;
36 pub const DISSET5: u8 = 0xB6;
37 pub const PWCTR1: u8 = 0xC0;
38 pub const PWCTR2: u8 = 0xC1;
39 pub const PWCTR3: u8 = 0xC2;
40 pub const PWCTR4: u8 = 0xC3;
41 pub const PWCTR5: u8 = 0xC4;
42 pub const VMCTR1: u8 = 0xC5;
43 pub const RDID1: u8 = 0xDA;
44 pub const RDID2: u8 = 0xDB;
45 pub const RDID3: u8 = 0xDC;
46 pub const RDID4: u8 = 0xDD;
47 pub const PWCTR6: u8 = 0xFC;
48 pub const GMCTRP1: u8 = 0xE0;
49 pub const GMCTRN1: u8 = 0xE1;
50}
51
52pub trait DisplaySpec {
53 const WIDTH: u16;
54 const HEIGHT: u16;
55 const OFFSETX: u16 = 0;
56 const OFFSETY: u16 = 0;
57
58 const INVERTED: bool = false;
59}
60
61pub struct Display160x80Type1;
63impl DisplaySpec for Display160x80Type1 {
64 const WIDTH: u16 = 160;
65 const HEIGHT: u16 = 80;
66 const OFFSETX: u16 = 0;
67 const OFFSETY: u16 = 24;
68}
69
70pub struct Display160x80Type2;
72impl DisplaySpec for Display160x80Type2 {
73 const WIDTH: u16 = 160;
74 const HEIGHT: u16 = 80;
75 const OFFSETX: u16 = 1;
76 const OFFSETY: u16 = 26;
77 const INVERTED: bool = true;
78}
79
80#[derive(Debug)]
81pub enum Error<BusError> {
82 Bus(BusError),
83}
84
85impl<E> From<E> for Error<E> {
86 fn from(e: E) -> Self {
87 Error::Bus(e)
88 }
89}
90
91pub struct ST7735<SPEC, SPI, DC> {
92 spi: SPI,
93 dc: DC,
94 _marker: core::marker::PhantomData<SPEC>,
95}
96
97impl<SPEC: DisplaySpec, SPI: embedded_hal_async::spi::SpiDevice, DC: OutputPin> ST7735<SPEC, SPI, DC> {
98 pub fn new(spi: SPI, dc: DC) -> Self {
99 Self {
100 spi,
101 dc,
102 _marker: core::marker::PhantomData,
103 }
104 }
105
106 pub async fn init<D: DelayNs>(&mut self, delay: &mut D) -> Result<(), Error<SPI::Error>> {
107 self.send_command(cmds::SWRESET).await?;
108 delay.delay_ms(20);
109 self.send_command(cmds::SLPOUT).await?;
110 delay.delay_ms(200);
111
112 self.send_command_data(cmds::FRMCTR1, &[0x01, 0x2C, 0x2D]).await?;
113 self.send_command_data(cmds::FRMCTR2, &[0x01, 0x2C, 0x2D]).await?;
114 self.send_command_data(cmds::FRMCTR3, &[0x01, 0x2C, 0x2D, 0x01, 0x2C, 0x2D])
115 .await?;
116 self.send_command_data(cmds::INVCTR, &[0x07]).await?;
117 self.send_command_data(cmds::PWCTR1, &[0xA2, 0x02, 0x84]).await?;
118 self.send_command_data(cmds::PWCTR2, &[0xC5]).await?;
119 self.send_command_data(cmds::PWCTR3, &[0x0A, 0x00]).await?;
120 self.send_command_data(cmds::PWCTR4, &[0x8A, 0x2A]).await?;
121 self.send_command_data(cmds::PWCTR5, &[0x8A, 0xEE]).await?;
122 self.send_command_data(cmds::VMCTR1, &[0x0E]).await?;
123
124 if SPEC::INVERTED {
125 self.send_command(cmds::INVON).await?;
126 } else {
127 self.send_command(cmds::INVOFF).await?;
128 }
129
130 self.send_command_data(cmds::MADCTL, &[0b0110_10_00]).await?;
133
134 self.send_command_data(cmds::COLMOD, &[0x05]).await?; self.send_command(cmds::DISPON).await?;
136
137 delay.delay_ms(100);
138
139 Ok(())
140 }
141
142 #[inline]
143 async fn set_update_window(&mut self, x: u16, y: u16, w: u16, h: u16) -> Result<(), Error<SPI::Error>> {
144 let ox = SPEC::OFFSETX + x;
145 let oy = SPEC::OFFSETY + y;
146
147 self.send_command_data(
148 cmds::CASET,
149 &[
150 (ox >> 8) as u8,
151 (ox & 0xFF) as u8,
152 ((ox + w - 1) >> 8) as u8,
153 ((ox + w - 1) & 0xFF) as u8,
154 ],
155 )
156 .await?;
157
158 self.send_command_data(
159 cmds::RASET,
160 &[
161 (oy >> 8) as u8,
162 (oy & 0xFF) as u8,
163 ((oy + h - 1) >> 8) as u8,
164 ((oy + h - 1) & 0xFF) as u8,
165 ],
166 )
167 .await?;
168 Ok(())
169 }
170
171 pub async fn write_framebuffer(&mut self, data: &[u8]) -> Result<(), Error<SPI::Error>> {
172 self.set_update_window(0, 0, SPEC::WIDTH, SPEC::HEIGHT).await?;
173 self.send_command_data(cmds::RAMWR, data).await?;
174 Ok(())
175 }
176
177 pub async fn write_window_framebuffer(
178 &mut self,
179 x: u16,
180 y: u16,
181 w: u16,
182 h: u16,
183 data: &[u8],
184 ) -> Result<(), Error<SPI::Error>> {
185 self.set_update_window(x, y, w, h).await?;
186 self.send_command_data(cmds::RAMWR, data).await?;
187 Ok(())
188 }
189
190 pub async fn write_pixel(&mut self, x: u16, y: u16, data: &[u8]) -> Result<(), Error<SPI::Error>> {
191 self.set_update_window(x, y, 1, 1).await?;
192
193 self.send_command_data(cmds::RAMWR, data).await?;
194 Ok(())
195 }
196
197 async fn send_command(&mut self, cmd: u8) -> Result<(), Error<SPI::Error>> {
198 let _ = self.dc.set_low(); self.spi.write(&[cmd]).await?;
200 Ok(())
201 }
202
203 async fn send_data(&mut self, data: &[u8]) -> Result<(), Error<SPI::Error>> {
204 let _ = self.dc.set_high(); self.spi.write(data).await?;
206 Ok(())
207 }
208
209 async fn send_command_data(&mut self, cmd: u8, data: &[u8]) -> Result<(), Error<SPI::Error>> {
210 self.send_command(cmd).await?;
211 self.send_data(data).await?;
212 Ok(())
213 }
214
215 pub async fn clear(&mut self, color: Rgb565) -> Result<(), Error<SPI::Error>> {
216 self.set_update_window(0, 0, SPEC::WIDTH, SPEC::HEIGHT).await?;
217
218 self.send_command(cmds::RAMWR).await?;
219 for _ in 0..((SPEC::WIDTH as u16) * (SPEC::HEIGHT as u16)) {
220 self.send_data(color.to_be_bytes().as_ref()).await?;
221 }
222 Ok(())
223 }
224}