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
use crate::traits::Command;
use core::marker::PhantomData;
use embedded_hal::{delay::DelayNs, digital::*, spi::SpiDevice};
/// The Connection Interface of all (?) EEI VFD
///
pub(crate) struct DisplayInterface<SPI, CS, RST, DELAY> {
/// SPI
_spi: PhantomData<SPI>,
/// DELAY
_delay: PhantomData<DELAY>,
/// CS for SPI
cs: CS,
/// Pin for Resetting
rst: RST,
}
impl<SPI, CS, RST, DELAY> DisplayInterface<SPI, CS, RST, DELAY>
where
SPI: SpiDevice,
CS: OutputPin,
RST: OutputPin,
DELAY: DelayNs,
{
pub fn new(cs: CS, rst: RST) -> Self {
DisplayInterface {
_spi: PhantomData,
_delay: PhantomData,
cs,
rst,
}
}
/// Basic function for sending [Commands](Command).
///
fn cmd<T: Command>(&mut self, spi: &mut SPI, command: T) -> Result<(), SPI::Error> {
// Transfer the command over spi
let addr = command.address();
self.write(spi, &[addr.reverse_bits()])
}
/// Basic function for sending an array of u8-values of data over spi
///
pub(crate) fn args(
&mut self,
spi: &mut SPI,
args: impl IntoIterator<Item = u8>,
) -> Result<(), SPI::Error> {
args.into_iter()
.try_for_each(|val| self.write(spi, &[val.reverse_bits()]))
}
pub(crate) fn data(
&mut self,
spi: &mut SPI,
data: impl IntoIterator<Item = u8>,
) -> Result<(), SPI::Error> {
data.into_iter().try_for_each(|val| self.write(spi, &[val]))
}
/// Basic function for sending [Commands](Command) and the data belonging to it.
///
/// TODO: directly use ::write? cs wouldn't needed to be changed twice than
pub(crate) fn cmd_with_data<T: Command>(
&mut self,
spi: &mut SPI,
command: T,
args: impl IntoIterator<Item = u8>,
data: impl IntoIterator<Item = u8>,
) -> Result<(), SPI::Error> {
// this is nessessary for shifting out the previous frame when communicating
// with high frequency
let _ = self.cs.set_high();
// activate spi with cs low
let _ = self.cs.set_low();
self.cmd(spi, command)?;
self.args(spi, args)?;
self.data(spi, data)?;
let _ = self.cs.set_high();
Ok(())
}
/// Basic function for sending [Commands](Command) and the data belonging to it.
///
/// TODO: directly use ::write? cs wouldn't needed to be changed twice than
pub(crate) fn cmd_with_arg<T: Command>(
&mut self,
spi: &mut SPI,
command: T,
args: impl IntoIterator<Item = u8>,
) -> Result<(), SPI::Error> {
// this is nessessary for shifting out the previous frame when communicating
// with high frequency
let _ = self.cs.set_high();
// activate spi with cs low
let _ = self.cs.set_low();
self.cmd(spi, command)?;
self.args(spi, args)?;
let _ = self.cs.set_high();
Ok(())
}
/// Basic function for sending the same byte of data (one u8) multiple times over spi
///
/// Enables direct interaction with the device with the help of [command()](ConnectionInterface::command())
#[allow(unused)]
pub(crate) fn data_x_times(
&mut self,
spi: &mut SPI,
val: u8,
repetitions: u32,
) -> Result<(), SPI::Error> {
// Transfer data (u8) over spi
for _ in 0..repetitions {
self.write(spi, &[val])?;
}
Ok(())
}
// spi write helper/abstraction function
fn write(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> {
// transfer spi data
// Be careful!! Linux has a default limit of 4096 bytes per spi transfer
// see https://raspberrypi.stackexchange.com/questions/65595/spi-transfer-fails-with-buffer-size-greater-than-4096
if cfg!(target_os = "linux") {
for data_chunk in data.chunks(4096) {
spi.write(data_chunk)?;
}
} else {
spi.write(data)?;
}
Ok(())
}
/// Resets the device.
///
/// Often used to awake the module from deep sleep. See [VFD256x50::sleep()](Epd4in2::sleep())
///
/// The timing of keeping the reset pin low seems to be important and different per device.
/// Most displays seem to require keeping it low for 10ms, but the 7in5_v2 only seems to reset
/// properly with 2ms
pub(crate) fn reset(&mut self, delay: &mut DELAY, duration: u32) {
let _ = self.rst.set_low();
delay.delay_ms(duration);
let _ = self.rst.set_high();
delay.delay_ms(1)
}
}