edrv_st7735/
lib.rs

1//! Driver for ST7735.
2
3#![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
61/// Common 0.96" 160x80 display
62pub 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
70/// Common 0.96" 160x80 display, type 2
71pub 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        // BITS:
131        // MY, MX, MV, ML, RGB, MH, D1, D0
132        self.send_command_data(cmds::MADCTL, &[0b0110_10_00]).await?;
133
134        self.send_command_data(cmds::COLMOD, &[0x05]).await?; // 16-bit/pixel
135        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(); // ignore any io errors
199        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(); // ignore any io errors
205        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}