1use crate::prelude::*;
2use rust_hdl_core::prelude::*;
3use std::time::Duration;
4
5#[derive(Copy, Clone)]
6pub struct I2CConfig {
7 pub delay_time: Duration,
8 pub clock_speed_hz: u64,
9}
10
11#[derive(Copy, Clone, PartialEq, Debug, LogicState)]
12pub enum I2CDriverCmd {
13 Noop,
14 SendStart,
15 SendTrue,
16 SendFalse,
17 SendStop,
18 GetBit,
19 Restart,
20}
21
22#[derive(Copy, Clone, PartialEq, Debug, LogicState)]
23enum State {
24 Idle,
25 Start,
26 Send,
27 Error,
28 Clock,
29 Stop,
30 StopSetup,
31 CheckArbitration,
32 Restart,
33 RestartDelay,
34 Receive,
35 ReceiveClock,
36}
37
38#[derive(LogicBlock)]
40pub struct I2CDriver {
41 pub i2c: I2CBusDriver,
42 pub clock: Signal<In, Clock>,
43 pub cmd: Signal<In, I2CDriverCmd>,
44 pub run: Signal<In, Bit>,
45 pub busy: Signal<Out, Bit>,
46 pub error: Signal<Out, Bit>,
47 pub read_bit: Signal<Out, Bit>,
48 pub read_valid: Signal<Out, Bit>,
49 state: DFF<State>,
50 delay: Shot<32>,
51 sda_is_high: Signal<Local, Bit>,
52 scl_is_high: Signal<Local, Bit>,
53 sda_flop: DFF<Bit>,
54 scl_flop: DFF<Bit>,
55 clear_sda: Signal<Local, Bit>,
56 clear_scl: Signal<Local, Bit>,
57 set_sda: Signal<Local, Bit>,
58 set_scl: Signal<Local, Bit>,
59}
60
61impl Logic for I2CDriver {
62 #[hdl_gen]
63 fn update(&mut self) {
64 dff_setup!(self, clock, state, sda_flop, scl_flop);
65 clock!(self, clock, delay);
66 self.delay.trigger.next = false;
68 self.i2c.sda.drive_low.next = self.sda_flop.q.val();
69 self.i2c.scl.drive_low.next = self.scl_flop.q.val();
70 self.error.next = false;
71 self.sda_is_high.next = self.i2c.sda.line_state.val();
73 self.scl_is_high.next = self.i2c.scl.line_state.val();
74 self.set_scl.next = false;
75 self.clear_scl.next = false;
76 self.set_sda.next = false;
77 self.clear_sda.next = false;
78 self.read_bit.next = self.sda_is_high.val();
79 self.read_valid.next = false;
80 self.busy.next = (self.state.q.val() != State::Idle) & (self.state.q.val() != State::Error);
81 match self.state.q.val() {
82 State::Idle => {
83 if self.run.val() {
84 match self.cmd.val() {
85 I2CDriverCmd::SendStart => {
86 if !self.sda_is_high.val() {
90 self.state.d.next = State::Error
91 } else {
92 self.clear_sda.next = true;
95 self.delay.trigger.next = true;
96 self.state.d.next = State::Start
97 }
98 }
99 I2CDriverCmd::SendTrue => {
100 self.set_sda.next = true;
102 self.delay.trigger.next = true;
104 self.state.d.next = State::Send
105 }
106 I2CDriverCmd::GetBit => {
107 self.set_sda.next = true;
109 self.delay.trigger.next = true;
111 self.state.d.next = State::Receive;
112 }
113 I2CDriverCmd::SendFalse => {
114 self.clear_sda.next = true;
116 self.delay.trigger.next = true;
118 self.state.d.next = State::Send
119 }
120 I2CDriverCmd::SendStop => {
121 self.clear_sda.next = true;
124 self.delay.trigger.next = true;
125 self.state.d.next = State::Stop
126 }
127 I2CDriverCmd::Restart => {
128 self.set_sda.next = true;
131 self.delay.trigger.next = true;
132 self.state.d.next = State::Restart
133 }
134 I2CDriverCmd::Noop => {}
135 _ => {}
136 }
137 }
138 }
139 State::Start => {
140 if self.delay.fired.val() {
141 self.clear_scl.next = true;
143 self.state.d.next = State::Idle;
144 }
145 }
146 State::Stop => {
147 if self.delay.fired.val() {
148 self.set_scl.next = true;
150 self.delay.trigger.next = true;
151 self.state.d.next = State::StopSetup;
152 }
153 }
154 State::Error => {
155 self.error.next = true;
156 }
157 State::Send => {
158 if self.delay.fired.val() {
159 self.set_scl.next = true;
161 self.state.d.next = State::Clock;
162 self.delay.trigger.next = true;
164 }
165 }
166 State::Receive => {
167 if self.delay.fired.val() {
168 self.set_scl.next = true;
170 self.state.d.next = State::ReceiveClock;
171 self.delay.trigger.next = true;
173 }
174 }
175 State::Clock => {
176 if self.delay.fired.val() {
177 self.clear_scl.next = true;
178 self.state.d.next = State::Idle;
179 }
180 }
181 State::ReceiveClock => {
182 if self.delay.fired.val() {
183 self.read_valid.next = true;
184 self.clear_scl.next = true;
185 self.state.d.next = State::Idle;
186 }
187 }
188 State::StopSetup => {
189 if self.delay.fired.val() {
190 self.set_sda.next = true;
192 self.delay.trigger.next = true;
194 self.state.d.next = State::CheckArbitration;
195 }
196 }
197 State::Restart => {
198 if self.delay.fired.val() {
200 self.set_scl.next = true;
201 self.state.d.next = State::RestartDelay;
202 self.delay.trigger.next = true;
203 }
204 }
205 State::RestartDelay => {
206 if self.delay.fired.val() {
207 self.clear_sda.next = true;
208 self.delay.trigger.next = true;
209 self.state.d.next = State::Start
210 }
211 }
212 State::CheckArbitration => {
213 if self.delay.fired.val() {
214 if !self.i2c.sda.line_state.val() {
218 self.state.d.next = State::Error;
219 } else {
220 self.state.d.next = State::Idle;
221 }
222 }
223 }
224 _ => {
225 self.state.d.next = State::Idle;
226 }
227 }
228 if self.set_scl.val() {
229 self.scl_flop.d.next = false;
230 }
231 if self.clear_scl.val() {
232 self.scl_flop.d.next = true;
233 }
234 if self.set_sda.val() {
235 self.sda_flop.d.next = false;
236 }
237 if self.clear_sda.val() {
238 self.sda_flop.d.next = true;
239 }
240 if self.run.val() & self.busy.val() {
241 self.state.d.next = State::Error;
242 }
243 }
244}
245
246impl I2CDriver {
247 pub fn new(config: I2CConfig) -> I2CDriver {
248 I2CDriver {
249 i2c: Default::default(),
250 clock: Default::default(),
251 cmd: Default::default(),
252 run: Default::default(),
253 busy: Default::default(),
254 delay: Shot::new(config.clock_speed_hz, config.delay_time),
255 sda_is_high: Default::default(),
256 state: Default::default(),
257 error: Default::default(),
258 scl_is_high: Default::default(),
259 sda_flop: Default::default(),
260 scl_flop: Default::default(),
261 clear_sda: Default::default(),
262 clear_scl: Default::default(),
263 set_sda: Default::default(),
264 set_scl: Default::default(),
265 read_bit: Default::default(),
266 read_valid: Default::default(),
267 }
268 }
269}
270
271#[test]
272fn test_i2c_driver_synthesizes() {
273 let config = I2CConfig {
274 delay_time: Duration::from_nanos(1500),
275 clock_speed_hz: 48_000_000,
276 };
277 let mut uut = I2CDriver::new(config);
278 uut.connect_all();
279 let vlog = generate_verilog(&uut);
280 yosys_validate("i2cdriver", &vlog).unwrap()
281}