inky_frame/frame/
display.rs

1// Permission is hereby granted, free of charge, to any person obtaining a copy
2// of this software and associated documentation files (the "Software"), to deal
3// in the Software without restriction, including without limitation the rights
4// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
5// copies of the Software, and to permit persons to whom the Software is
6// furnished to do so, subject to the following conditions:
7//
8// The above copyright notice and this permission notice shall be included in
9// all copies or substantial portions of the Software.
10//
11// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17// SOFTWARE.
18//
19
20#![no_implicit_prelude]
21
22extern crate core;
23extern crate rpsp;
24
25use core::clone::Clone;
26use core::convert::{Into, TryInto};
27use core::option::Option::{self, None, Some};
28use core::result::Result::{self, Ok};
29
30use rpsp::Board;
31use rpsp::clock::Timer;
32use rpsp::pin::gpio::{Input, Output};
33use rpsp::pin::{Pin, PinID};
34use rpsp::spi::{Spi, SpiBus, SpiConfig, SpiError, SpiFormat, SpiIO, SpiPhase, SpiPolarity};
35
36use crate::frame::ShiftRegister;
37
38const SR_BUSY: u8 = 7u8;
39const BAUDRATE: u32 = 3_000_000u32;
40
41pub enum BusySignal {
42    Pin(Pin<Input>),
43    SR(ShiftRegister),
44}
45
46pub struct Display<'a, const W: u16, const H: u16> {
47    bs:    BusySignal,
48    cs:    Pin<Output>,
49    rst:   Pin<Output>,
50    spi:   SpiBus<'a>,
51    data:  Pin<Output>,
52    timer: Timer,
53}
54
55impl BusySignal {
56    #[inline]
57    fn is_ready(&self) -> bool {
58        match self {
59            BusySignal::Pin(v) => v.is_high(),
60            BusySignal::SR(v) => v.is_set(SR_BUSY),
61        }
62    }
63}
64impl<const W: u16, const H: u16> Display<'_, W, H> {
65    #[inline]
66    pub fn new<'a>(p: &Board, spi: SpiBus<'a>, cs: PinID, rst: PinID, data: PinID, bs: BusySignal) -> Display<'a, W, H> {
67        Display {
68            bs,
69            spi,
70            cs: p.pin(cs).output_high(),
71            rst: p.pin(rst).output_high(),
72            data: p.pin(data),
73            timer: p.timer().clone(),
74        }
75    }
76    pub fn create(p: &Board, tx: PinID, sck: PinID, cs: PinID, rst: PinID, data: PinID, bs: BusySignal) -> Result<Display<W, H>, SpiError> {
77        Ok(Display {
78            bs,
79            cs: p.pin(cs).output_high(),
80            rst: p.pin(rst).output_high(),
81            spi: Spi::new(
82                p,
83                BAUDRATE,
84                SpiConfig::new()
85                    .bits(8)
86                    .format(SpiFormat::Motorola)
87                    .phase(SpiPhase::First)
88                    .polarity(SpiPolarity::Low)
89                    .primary(true),
90                (tx, sck).try_into()?,
91            )?
92            .into(),
93            data: p.pin(data),
94            timer: p.timer().clone(),
95        })
96    }
97
98    #[inline]
99    pub fn off(&mut self) {
100        self.wait();
101        self.cmd(0x2) // POF
102    }
103    #[inline]
104    pub fn sleep(&mut self) {
105        self.wait();
106        self.cmd(0xA5) // ???
107    }
108    #[inline]
109    pub fn refresh(&mut self) {
110        self.setup();
111        self.cmd(0x4);
112        self.wait();
113        self.cmd(0x12);
114        self.wait();
115    }
116    #[inline(always)]
117    pub fn width(&self) -> u16 {
118        W
119    }
120    #[inline(always)]
121    pub fn height(&self) -> u16 {
122        H
123    }
124    #[inline(always)]
125    pub fn is_busy(&self) -> bool {
126        !self.bs.is_ready()
127    }
128    #[inline(always)]
129    pub fn is_ready(&self) -> bool {
130        self.bs.is_ready()
131    }
132    pub fn update(&mut self, b: &[u8]) {
133        self.setup();
134        self.cmd_data(0x10, b); // DTM1
135        self.wait();
136        self.cmd(0x4); // PON
137        self.wait();
138        self.cmd(0x12); // DRF
139        self.wait();
140        self.cmd(0x2); // POF
141    }
142    #[inline(always)]
143    pub fn spi_bus(&mut self) -> &mut Spi {
144        &mut self.spi
145    }
146    #[inline(always)]
147    pub fn shift_register(&self) -> Option<&ShiftRegister> {
148        match &self.bs {
149            BusySignal::Pin(_) => None,
150            BusySignal::SR(v) => Some(v),
151        }
152    }
153
154    /// Returns immediately, the user must issue a
155    /// POF command using the 'off' function once
156    /// the display refresh is complete.
157    pub unsafe fn update_async(&mut self, b: &[u8]) {
158        self.setup();
159        self.cmd_data(0x10, b); // DTM1
160        self.wait();
161        self.cmd(0x4); // PON
162        self.wait();
163        self.cmd(0x12); // DRF
164    }
165
166    #[inline]
167    fn wait(&self) {
168        while !self.bs.is_ready() {
169            self.timer.sleep_ms(10);
170        }
171    }
172    fn setup(&mut self) {
173        self.reset();
174        self.cmd_data(0x0, &[0xAF | if W == 600 { 0x40 } else { 0 }, 0x8]); // PSR
175        self.cmd_data(0x1, &[0x37, 0, 0x23, 0x23]); // PWR
176        self.cmd_data(0x3, &[0]); // PFS
177        self.cmd_data(0x6, &[0xC7, 0xC7, 0x1D]); // BTST
178        self.cmd_data(0x30, &[0x3C]); // PLL
179        self.cmd_data(0x40, &[0]); // TSC
180        self.cmd_data(0x50, &[0x37]); // CDI
181        self.cmd_data(0x60, &[0x22]); // TCON
182        self.cmd_data(0x61, &[(W >> 8) as u8, W as u8, (H >> 8) as u8, H as u8]); // TRES
183        self.cmd_data(0xE3, &[0xAA]); // PWS
184        self.timer.sleep_ms(100);
185        self.cmd_data(0x50, &[0x37]) // CDI
186    }
187    fn reset(&self) {
188        self.rst.low();
189        self.timer.sleep_ms(10);
190        self.rst.high();
191        self.timer.sleep_ms(10);
192        self.wait();
193    }
194    fn cmd(&mut self, v: u8) {
195        self.cs.low();
196        self.data.low();
197        self.spi.write_single(v);
198        self.cs.high();
199    }
200    fn cmd_data(&mut self, v: u8, b: &[u8]) {
201        self.cs.low();
202        self.data.low();
203        self.spi.write_single(v);
204        self.data.high();
205        self.spi.write(b);
206        self.cs.high();
207    }
208}