1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
use display_interface::{DataFormat, DisplayError, WriteOnlyDataCommand};
/// ssd1309 Commands
/// Commands
#[derive(Debug)]
#[allow(dead_code)]
pub enum Command {
/// Set contrast. Higher number is higher contrast. Default = 0x7F
Contrast(u8),
/// Turn entire display on. If set, all pixels will
/// be set to on, if not, the value in memory will be used.
AllOn(bool),
/// Invert display.
Invert(bool),
/// Turn display on or off.
DisplayOn(bool),
/// Set column address lower 4 bits
ColumnAddressLow(u8),
/// Set column address higher 4 bits
ColumnAddressHigh(u8),
/// Set page address
PageAddress(Page),
/// Set display start line from 0-63
StartLine(u8),
/// Reverse columns from 127-0
SegmentRemap(bool),
/// Set multipex ratio from 15-63 (MUX-1)
Multiplex(u8),
/// Scan from COM[n-1] to COM0 (where N is mux ratio)
ReverseComDir(bool),
/// Set vertical shift
DisplayOffset(u8),
/// Setup com hardware configuration
/// First value indicates sequential (false) or alternative (true)
/// pin configuration.
ComPinConfig(bool),
/// Set up display clock.
/// First value is oscillator frequency, increasing with higher value
/// Second value is divide ratio - 1
DisplayClockDiv(u8, u8),
/// Set up phase 1 and 2 of precharge period. each value is from 0-63
PreChargePeriod(u8, u8),
/// Set Vcomh Deselect level
VcomhDeselect(VcomhLevel),
/// Enable or disable scrolling
ScrollActive(bool),
/// NOOP
Noop,
}
impl Command {
/// Send command to ssd1309
pub fn send<DI>(self, iface: &mut DI) -> Result<(), DisplayError>
where
DI: WriteOnlyDataCommand,
{
// Transform command into a fixed size array of 7 u8 and the real length for sending
let (data, len) = match self {
Command::Contrast(val) => ([0x81, val, 0, 0, 0, 0, 0], 2),
Command::AllOn(on) => ([0xA4 | (on as u8), 0, 0, 0, 0, 0, 0], 1),
Command::Invert(inv) => ([0xA6 | (inv as u8), 0, 0, 0, 0, 0, 0], 1),
Command::DisplayOn(on) => ([0xAE | (on as u8), 0, 0, 0, 0, 0, 0], 1),
Command::ColumnAddressLow(addr) => ([0xF & addr, 0, 0, 0, 0, 0, 0], 1),
Command::ColumnAddressHigh(addr) => ([0x10 | (0xF & addr), 0, 0, 0, 0, 0, 0], 1),
Command::PageAddress(page) => ([0xB0 | (page as u8), 0, 0, 0, 0, 0, 0], 1),
Command::StartLine(line) => ([0x40 | (0x3F & line), 0, 0, 0, 0, 0, 0], 1),
Command::SegmentRemap(remap) => ([0xA0 | (remap as u8), 0, 0, 0, 0, 0, 0], 1),
Command::Multiplex(ratio) => ([0xA8, ratio, 0, 0, 0, 0, 0], 2),
Command::ReverseComDir(rev) => ([0xC0 | ((rev as u8) << 3), 0, 0, 0, 0, 0, 0], 1),
Command::DisplayOffset(offset) => ([0xD3, offset, 0, 0, 0, 0, 0], 2),
Command::ComPinConfig(alt) => ([0xDA, 0x02 | ((alt as u8) << 4), 0, 0, 0, 0, 0], 2),
Command::DisplayClockDiv(fosc, div) => {
([0xD5, ((0xF & fosc) << 4) | (0xF & div), 0, 0, 0, 0, 0], 2)
}
Command::PreChargePeriod(phase1, phase2) => (
[0xD9, ((0xF & phase2) << 4) | (0xF & phase1), 0, 0, 0, 0, 0],
2,
),
Command::VcomhDeselect(level) => ([0xDB, (level as u8) << 2, 0, 0, 0, 0, 0], 2),
Command::ScrollActive(active) => ([0x2E | (active as u8), 0, 0, 0, 0, 0, 0], 1),
Command::Noop => ([0xE3, 0, 0, 0, 0, 0, 0], 1),
};
// Send command over the interface
iface.send_commands(DataFormat::U8(&data[0..len]))
}
}
/// Display page
#[derive(Debug, Clone, Copy)]
pub enum Page {
/// Page 0
Page0 = 0,
/// Page 1
Page1 = 1,
/// Page 2
Page2 = 2,
/// Page 3
Page3 = 3,
/// Page 4
Page4 = 4,
/// Page 5
Page5 = 5,
/// Page 6
Page6 = 6,
/// Page 7
Page7 = 7,
}
impl From<u8> for Page {
fn from(val: u8) -> Page {
match val / 8 {
0 => Page::Page0,
1 => Page::Page1,
2 => Page::Page2,
3 => Page::Page3,
4 => Page::Page4,
5 => Page::Page5,
6 => Page::Page6,
7 => Page::Page7,
_ => panic!("Page too high"),
}
}
}
/// Frame interval
#[derive(Debug, Clone, Copy)]
#[allow(dead_code)]
pub enum NFrames {
/// 2 Frames
F2 = 0b111,
/// 3 Frames
F3 = 0b100,
/// 4 Frames
F4 = 0b101,
/// 5 Frames
F5 = 0b000,
/// 25 Frames
F25 = 0b110,
/// 64 Frames
F64 = 0b001,
/// 128 Frames
F128 = 0b010,
/// 256 Frames
F256 = 0b011,
}
/// Vcomh Deselect level
#[derive(Debug, Clone, Copy)]
#[allow(dead_code)]
pub enum VcomhLevel {
/// 0.65 * Vcc
V064 = 0b0000,
/// 0.77 * Vcc
V078 = 0b1101,
/// 0.83 * Vcc
V084 = 0b1111,
}