ssd1315_driver/
command.rs

1use crate::config::PumpLevel;
2use display_interface::{DataFormat::U8, DisplayError, WriteOnlyDataCommand};
3
4#[cfg(feature = "async")]
5use display_interface::AsyncWriteOnlyDataCommand;
6
7/// Commands that are used to initialize OLED screen.
8#[maybe_async_cfg::maybe(
9    sync(keep_self),
10    async(
11        feature = "async",
12        idents(WriteOnlyDataCommand(async = "AsyncWriteOnlyDataCommand"),)
13    )
14)]
15pub enum Command {
16    /* Scrolling Command Table */
17    HScrollSetup(HScrollDir, Page, Page, NFrames), // 0x26: Horizontal Scroll Setup
18    VHScrollSetup(VHScrollDir, Page, Page, NFrames, u8), // 0x29: Vertical and Horizontal Scroll Setup
19    ContentScroll(CScrollDir, Page, Page),               // 0x2C/2D: Content to be scrolled
20    EnableScroll(bool),                                  // 0x2E/2F: Deactivate/Activate Scroll
21    VScrollArea(u8, u8),                                 // 0xA3: Set Vertical Scroll Area
22
23    /* Fundamental Command Table */
24    LowerColStart(u8), // 0x00-0x0F: Set Lower Column Start Address for Page Addressing Mode
25    UpperColStart(u8), // 0x10-0x1F: Set Higher Column Start Address for Page Addressing Mode
26    AddressMode(AddrMode), // 0x20: Set Memory Addressing Mode
27    ColumnAddress(u8, u8), // 0x21: Set Column Address (start, end)
28    PageAddress(Page, Page), // 0x22: Set Page Address (start, end)
29    StartLine(u8),     // 0x40-0x7F: Set Display Start Line
30    Contrast(u8),      // 0x81: Set Contrast Control
31    ChargePump(PumpLevel), // 0x8D: Set Charge Pump
32    AllOn(bool),       // 0xA4/A5: Entire Display ON (A4=resume, A5=all on)
33    Invert(bool),      // 0xA6/A7: Set Normal/Inverse Display (A6=normal, A7=inverse)
34    Multiplex(u8),     // 0xA8: Set Multiplex Ratio
35    InternalIref(bool, bool), // 0xAD: Internal IREF Setting
36    DisplayOn(bool),   // 0xAE/AF: Set Display ON/OFF (AE=off, AF=on)
37    SegmentRemap(bool), // 0xA0/A1: Set Segment Remap (A0=normal, A1=reverse)
38    PageStart(Page),   // 0xB0-0xB7: Set Page Start Address for Page Addressing Mode
39    ReverseComDir(bool), // 0xC0/C8: Set COM Output Scan Direction (C0=normal, C8=remapped)
40    DisplayOffset(u8), // 0xD3: Set Display Offset
41    DisplayClockDiv(u8, u8), // 0xD5: Set Display Clock Divide Ratio/Oscillator Frequency
42    PreChargePeriod(u8, u8), // 0xD9: Set Pre-charge Period
43    ComPinConfig(bool, bool), // 0xDA: Set COM Pins Hardware Configuration (A4, A5)
44    VcomhDeselect(u8), // 0xDB: Set VCOMH Deselect Level
45    Noop,              // 0xE3: No operation
46}
47
48#[maybe_async_cfg::maybe(
49    sync(keep_self),
50    async(
51        feature = "async",
52        idents(WriteOnlyDataCommand(async = "AsyncWriteOnlyDataCommand"),)
53    )
54)]
55impl Command {
56    pub async fn send<DI: WriteOnlyDataCommand>(self, iface: &mut DI) -> Result<(), DisplayError> {
57        let commands: &[u8] = match self {
58            Command::HScrollSetup(dir, start, end, nframes) => &[
59                0x26 | (dir as u8),
60                0,
61                start as u8,
62                nframes as u8,
63                end as u8,
64                0,
65                0x7F,
66            ],
67            Command::VHScrollSetup(dir, start, end, nframes, offset) => &[
68                0x28 | (dir as u8),
69                0,
70                start as u8,
71                nframes as u8,
72                end as u8,
73                offset,
74                0,
75                0x7F,
76            ],
77            Command::ContentScroll(dir, start, end) => {
78                &[0x2C | (dir as u8), 0, start as u8, 1, end as u8, 0, 0x7F]
79            }
80            Command::EnableScroll(en) => &[0x2E | (en as u8)],
81            Command::VScrollArea(above, lines) => &[0xA3, above, lines],
82            Command::LowerColStart(addr) => &[0x0F & addr],
83            Command::UpperColStart(addr) => &[0x10 | (0x07 & addr)],
84            Command::StartLine(line) => &[0x40 | (0x3F & line)],
85            Command::AddressMode(mode) => &[0x20, mode as u8],
86            Command::ColumnAddress(start, end) => &[0x21, start, end],
87            Command::PageAddress(start, end) => &[0x22, start as u8, end as u8],
88            Command::PageStart(page) => &[0xB0 | (page as u8)],
89            Command::Contrast(val) => &[0x81, val],
90            Command::AllOn(on) => &[0xA4 | (on as u8)],
91            Command::Invert(inv) => &[0xA6 | (inv as u8)],
92            Command::DisplayOn(on) => &[0xAE | (on as u8)],
93            Command::SegmentRemap(remap) => &[0xA0 | (remap as u8)],
94            Command::DisplayOffset(offset) => &[0xD3, offset],
95            Command::Multiplex(ratio) => &[0xA8, ratio],
96            Command::ReverseComDir(rev) => &[0xC0 | ((rev as u8) << 3)],
97            Command::ComPinConfig(alt, lr) => &[0xDA, 0x2 | ((alt as u8) << 4) | ((lr as u8) << 5)],
98            Command::DisplayClockDiv(fosc, div) => &[0xD5, ((0xF & fosc) << 4) | (0xF & div)],
99            Command::PreChargePeriod(phase1, phase2) => {
100                &[0xD9, ((0xF & phase2) << 4) | (0xF & phase1)]
101            }
102            Command::VcomhDeselect(level) => &[0xDB, level as u8],
103            Command::ChargePump(level) => &[0x8D, level as u8],
104            Command::InternalIref(en, current) => {
105                &[0xAD, ((current as u8) << 5) | ((en as u8) << 4)]
106            }
107            Command::Noop => &[0xE3],
108        };
109
110        iface.send_commands(U8(commands)).await
111    }
112}
113
114/// Horizontal Scroll Direction
115pub enum HScrollDir {
116    /// Left to right
117    LeftToRight = 0,
118    /// Right to left
119    RightToLeft = 1,
120}
121
122/// Content Scroll Direction
123pub enum CScrollDir {
124    /// Left to right
125    LeftToRight = 0,
126    /// Right to left
127    RightToLeft = 1,
128}
129
130/// Vertical and horizontal scroll dir
131pub enum VHScrollDir {
132    /// Vertical and right horizontal
133    VerticalRight = 0b01,
134    /// Vertical and left horizontal
135    VerticalLeft = 0b10,
136}
137
138/// Display page
139#[derive(Debug, Clone, Copy)]
140pub enum Page {
141    Page0 = 0b000,
142    Page1 = 0b001,
143    Page2 = 0b010,
144    Page3 = 0b011,
145    Page4 = 0b100,
146    Page5 = 0b101,
147    Page6 = 0b110,
148    Page7 = 0b111,
149}
150
151/// Frow the row to Page
152/// 0..7  => Page0
153/// 8..15 => Page1
154/// ...
155impl From<u8> for Page {
156    fn from(val: u8) -> Page {
157        match val / 8 {
158            0 => Page::Page0,
159            1 => Page::Page1,
160            2 => Page::Page2,
161            3 => Page::Page3,
162            4 => Page::Page4,
163            5 => Page::Page5,
164            6 => Page::Page6,
165            7 => Page::Page7,
166            _ => panic!("Page too high"),
167        }
168    }
169}
170
171/// Frame interval
172pub enum NFrames {
173    /// 2 Frames
174    F2 = 0b111,
175    /// 3 Frames
176    F3 = 0b100,
177    /// 4 Frames
178    F4 = 0b101,
179    /// 5 Frames
180    F5 = 0b110,
181    /// 6 Frames
182    F6 = 0b000,
183    /// 32 Frames
184    F32 = 0b001,
185    /// 64 Frames
186    F64 = 0b010,
187    /// 128 Frames
188    F128 = 0b011,
189}
190
191/// Addressing modes
192pub enum AddrMode {
193    Horizontal = 0b00, // Horizontal mode
194    Vertical = 0b01,   // Vertical mode
195    Page = 0b10,       // Page mode (default)
196}