rust_hdl_widgets/i2c/
i2c_driver.rs

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// Implement the bit-bang I2C interface as reported on Wikipedia
39#[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        // Latch avoidance and default conditions
67        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        // Helpers to make the code more readable
72        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 (read_SDA() == 0) {
87                            //     arbitration_lost();
88                            // }
89                            if !self.sda_is_high.val() {
90                                self.state.d.next = State::Error
91                            } else {
92                                //  clear_SDA();
93                                //  I2C_delay();
94                                self.clear_sda.next = true;
95                                self.delay.trigger.next = true;
96                                self.state.d.next = State::Start
97                            }
98                        }
99                        I2CDriverCmd::SendTrue => {
100                            // set_SDA()
101                            self.set_sda.next = true;
102                            // I2C_delay()
103                            self.delay.trigger.next = true;
104                            self.state.d.next = State::Send
105                        }
106                        I2CDriverCmd::GetBit => {
107                            // set_SDA() - let target drive the SDA line
108                            self.set_sda.next = true;
109                            // I2C_delay()
110                            self.delay.trigger.next = true;
111                            self.state.d.next = State::Receive;
112                        }
113                        I2CDriverCmd::SendFalse => {
114                            // clear_SDA()
115                            self.clear_sda.next = true;
116                            // I2C_delay()
117                            self.delay.trigger.next = true;
118                            self.state.d.next = State::Send
119                        }
120                        I2CDriverCmd::SendStop => {
121                            // clear_SDA();
122                            // I2C_delay();
123                            self.clear_sda.next = true;
124                            self.delay.trigger.next = true;
125                            self.state.d.next = State::Stop
126                        }
127                        I2CDriverCmd::Restart => {
128                            //   set_SDA();
129                            //   I2C_delay();
130                            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                    //  clear_SCL();
142                    self.clear_scl.next = true;
143                    self.state.d.next = State::Idle;
144                }
145            }
146            State::Stop => {
147                if self.delay.fired.val() {
148                    // set_SCL()
149                    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                    // set_SCL()
160                    self.set_scl.next = true;
161                    self.state.d.next = State::Clock;
162                    // I2C_delay()
163                    self.delay.trigger.next = true;
164                }
165            }
166            State::Receive => {
167                if self.delay.fired.val() {
168                    // set SCL()
169                    self.set_scl.next = true;
170                    self.state.d.next = State::ReceiveClock;
171                    // I2C_delay()
172                    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                    // set_SDA()
191                    self.set_sda.next = true;
192                    // I2C_delay()
193                    self.delay.trigger.next = true;
194                    self.state.d.next = State::CheckArbitration;
195                }
196            }
197            State::Restart => {
198                //   set_SCL();
199                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 (read_SDA() == 0) {
215                    //    arbitration_lost();
216                    // }
217                    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}