rust_hdl_widgets/i2c/
i2c_controller.rs

1use crate::dff::DFF;
2use crate::i2c::i2c_driver::{I2CDriver, I2CDriverCmd};
3use crate::i2c::i2c_test_target::I2CTestTarget;
4use crate::{dff_setup, prelude::*};
5use rust_hdl_core::prelude::*;
6use std::time::Duration;
7
8use super::i2c_test_target::I2CTestBus;
9
10#[derive(Copy, Clone, PartialEq, Debug, LogicState)]
11pub enum I2CControllerCmd {
12    Noop,
13    BeginWrite,
14    Write,
15    BeginRead,
16    Read,
17    EndTransmission,
18    ReadLast,
19}
20
21#[derive(Copy, Clone, PartialEq, Debug, LogicState)]
22enum State {
23    Idle,
24    SendBuffer,
25    GetBuffer,
26    WaitAck,
27    WaitBit,
28    Error,
29    WaitDriverIdle,
30}
31
32#[derive(LogicBlock)]
33pub struct I2CController {
34    pub i2c: I2CBusDriver,
35    pub clock: Signal<In, Clock>,
36    pub cmd: Signal<In, I2CControllerCmd>,
37    pub run: Signal<In, Bit>,
38    pub busy: Signal<Out, Bit>,
39    pub error: Signal<Out, Bit>,
40    pub write_data_in: Signal<In, Bits<8>>,
41    pub read_data_out: Signal<Out, Bits<8>>,
42    pub read_valid: Signal<Out, Bit>,
43    pub ack: Signal<Out, Bit>,
44    pub nack: Signal<Out, Bit>,
45    driver: I2CDriver,
46    counter: DFF<Bits<4>>,
47    read_data: DFF<Bits<8>>,
48    write_data: DFF<Bits<8>>,
49    state: DFF<State>,
50    started: DFF<Bit>,
51    last_read: DFF<Bit>,
52}
53
54impl I2CController {
55    pub fn new(config: I2CConfig) -> Self {
56        Self {
57            i2c: Default::default(),
58            clock: Default::default(),
59            cmd: Default::default(),
60            run: Default::default(),
61            busy: Default::default(),
62            error: Default::default(),
63            write_data_in: Default::default(),
64            read_data_out: Default::default(),
65            read_valid: Default::default(),
66            ack: Default::default(),
67            nack: Default::default(),
68            driver: I2CDriver::new(config),
69            counter: Default::default(),
70            read_data: Default::default(),
71            write_data: Default::default(),
72            state: Default::default(),
73            started: Default::default(),
74            last_read: Default::default(),
75        }
76    }
77}
78
79impl Logic for I2CController {
80    #[hdl_gen]
81    fn update(&mut self) {
82        I2CBusDriver::link(&mut self.i2c, &mut self.driver.i2c);
83        clock!(self, clock, driver);
84        dff_setup!(self, clock, counter, read_data, write_data, state, started, last_read);
85        self.driver.run.next = false;
86        self.driver.cmd.next = I2CDriverCmd::Noop;
87        // Default values
88        self.busy.next = (self.state.q.val() != State::Idle) | self.driver.busy.val();
89        self.error.next = false;
90        self.read_data_out.next = self.read_data.q.val();
91        self.read_valid.next = false;
92        self.ack.next = false;
93        self.nack.next = false;
94        match self.state.q.val() {
95            State::Idle => {
96                if self.run.val() {
97                    match self.cmd.val() {
98                        I2CControllerCmd::BeginWrite => {
99                            // Latch the write data as the address
100                            // Only the lower 7 bits are used.
101                            // The last bit is set to 0 to indicate a write
102                            self.write_data.d.next = self.write_data_in.val() << 1;
103                            if !self.started.q.val() {
104                                self.driver.cmd.next = I2CDriverCmd::SendStart;
105                            } else {
106                                self.driver.cmd.next = I2CDriverCmd::Restart;
107                            }
108                            self.driver.run.next = true;
109                            self.counter.d.next = 8.into();
110                            self.state.d.next = State::SendBuffer;
111                            self.started.d.next = true;
112                        }
113                        I2CControllerCmd::BeginRead => {
114                            // Set the lowest bit to indicate a read
115                            self.write_data.d.next = (self.write_data_in.val() << 1) | 1;
116                            if !self.started.q.val() {
117                                self.driver.cmd.next = I2CDriverCmd::SendStart;
118                            } else {
119                                self.driver.cmd.next = I2CDriverCmd::Restart;
120                            }
121                            self.driver.run.next = true;
122                            self.counter.d.next = 8.into();
123                            self.state.d.next = State::SendBuffer;
124                            self.started.d.next = true;
125                        }
126                        I2CControllerCmd::EndTransmission => {
127                            self.driver.cmd.next = I2CDriverCmd::SendStop;
128                            self.driver.run.next = true;
129                            self.state.d.next = State::WaitDriverIdle;
130                            self.started.d.next = false;
131                        }
132                        I2CControllerCmd::Write => {
133                            self.write_data.d.next = self.write_data_in.val();
134                            self.counter.d.next = 8.into();
135                            self.state.d.next = State::SendBuffer;
136                        }
137                        I2CControllerCmd::Read => {
138                            self.counter.d.next = 8.into();
139                            self.state.d.next = State::GetBuffer;
140                            self.last_read.d.next = false;
141                        }
142                        I2CControllerCmd::ReadLast => {
143                            self.counter.d.next = 8.into();
144                            self.state.d.next = State::GetBuffer;
145                            self.last_read.d.next = true;
146                        }
147                        I2CControllerCmd::Noop => {}
148                        _ => {}
149                    }
150                    if self.driver.busy.val() {
151                        self.state.d.next = State::Error;
152                    }
153                }
154            }
155            State::SendBuffer => {
156                if !self.driver.busy.val() {
157                    if self.counter.q.val() == 0 {
158                        self.driver.cmd.next = I2CDriverCmd::GetBit;
159                        self.driver.run.next = true;
160                        self.state.d.next = State::WaitAck;
161                    } else {
162                        if self.write_data.q.val().get_bit(7) {
163                            self.driver.cmd.next = I2CDriverCmd::SendTrue;
164                        } else {
165                            self.driver.cmd.next = I2CDriverCmd::SendFalse;
166                        }
167                        self.write_data.d.next = self.write_data.q.val() << 1;
168                        self.driver.run.next = true;
169                        self.counter.d.next = self.counter.q.val() - 1;
170                    }
171                }
172            }
173            State::GetBuffer => {
174                if !self.driver.busy.val() {
175                    if self.counter.q.val() == 0 {
176                        if self.last_read.q.val() {
177                            self.driver.cmd.next = I2CDriverCmd::SendTrue;
178                        } else {
179                            self.driver.cmd.next = I2CDriverCmd::SendFalse;
180                        }
181                        self.driver.run.next = true;
182                        self.state.d.next = State::Idle;
183                        self.read_valid.next = true;
184                    } else {
185                        self.driver.cmd.next = I2CDriverCmd::GetBit;
186                        self.driver.run.next = true;
187                        self.state.d.next = State::WaitBit;
188                    }
189                }
190            }
191            State::WaitBit => {
192                if self.driver.read_valid.val() {
193                    self.read_data.d.next = (self.read_data.q.val() << 1)
194                        | bit_cast::<8, 1>(self.driver.read_bit.val().into());
195                    self.counter.d.next = self.counter.q.val() - 1;
196                    self.state.d.next = State::GetBuffer;
197                }
198            }
199            State::WaitAck => {
200                if self.driver.read_valid.val() {
201                    if self.driver.read_bit.val() {
202                        self.nack.next = true;
203                    } else {
204                        self.ack.next = true;
205                    }
206                    self.state.d.next = State::Idle;
207                }
208            }
209            State::WaitDriverIdle => {
210                if !self.driver.busy.val() {
211                    self.state.d.next = State::Idle;
212                }
213            }
214            State::Error => {
215                self.error.next = true;
216            }
217            _ => {
218                self.state.d.next = State::Idle;
219            }
220        }
221        if self.driver.error.val() {
222            self.state.d.next = State::Error;
223        }
224    }
225}
226
227#[test]
228fn test_i2c_controller_synthesizes() {
229    let config = I2CConfig {
230        delay_time: Duration::from_nanos(1500),
231        clock_speed_hz: 48_000_000,
232    };
233    let mut uut = I2CController::new(config);
234    uut.connect_all();
235    let vlog = generate_verilog(&uut);
236    yosys_validate("i2ccontroller", &vlog).unwrap()
237}
238
239// TODO - this probably needs some clean up
240#[derive(LogicBlock)]
241struct I2CControllerTest {
242    clock: Signal<In, Clock>,
243    controller: I2CController,
244    target_1: I2CTestTarget,
245    target_2: I2CTestTarget,
246    test_bus: I2CTestBus<3>,
247}
248
249impl Logic for I2CControllerTest {
250    #[hdl_gen]
251    fn update(&mut self) {
252        clock!(self, clock, controller, target_1, target_2);
253        I2CBusDriver::join(&mut self.controller.i2c, &mut self.test_bus.endpoints[0]);
254        I2CBusDriver::join(&mut self.target_1.i2c, &mut self.test_bus.endpoints[1]);
255        I2CBusDriver::join(&mut self.target_2.i2c, &mut self.test_bus.endpoints[2]);
256    }
257}
258
259impl Default for I2CControllerTest {
260    fn default() -> Self {
261        let config = I2CConfig {
262            delay_time: Duration::from_micros(5),
263            clock_speed_hz: 1_000_000,
264        };
265        Self {
266            clock: Default::default(),
267            controller: I2CController::new(config),
268            target_1: I2CTestTarget::new(0x53),
269            target_2: I2CTestTarget::new(0x57),
270            test_bus: Default::default(),
271        }
272    }
273}
274
275#[test]
276fn test_i2c_controller_operation() {
277    use rand::Rng;
278    struct TestCase {
279        address: u8,
280        reg_index: u8,
281        val_msb: u8,
282        val_lsb: u8,
283    }
284
285    let test_cases = (0..12)
286        .map(|ndx| TestCase {
287            address: if rand::thread_rng().gen::<bool>() {
288                0x53_u8
289            } else {
290                0x57_u8
291            },
292            reg_index: ndx,
293            val_msb: rand::thread_rng().gen::<u8>(),
294            val_lsb: rand::thread_rng().gen::<u8>(),
295        })
296        .collect::<Vec<_>>();
297    let mut uut = I2CControllerTest::default();
298    uut.clock.connect();
299    uut.controller.cmd.connect();
300    uut.controller.run.connect();
301    uut.controller.write_data_in.connect();
302    uut.connect_all();
303    let vlog = generate_verilog(&uut);
304    //println!("{}", vlog);
305    dbg!(I2CBusDriver::join_hdl("me", "foo", "bar"));
306    yosys_validate("i2c_controller", &vlog).unwrap();
307    let mut sim = Simulation::new();
308    sim.add_clock(500_000, |x: &mut Box<I2CControllerTest>| {
309        x.clock.next = !x.clock.val()
310    });
311    sim.add_testbench(move |mut sim: Sim<I2CControllerTest>| {
312        let mut x = sim.init()?;
313        // Check that a write to an invalid address is NACKed.
314        i2c_begin_write!(sim, clock, x, 0x54_u32);
315        sim_assert!(sim, x.controller.nack.val() & !x.controller.ack.val(), x);
316        i2c_end_transmission!(sim, clock, x);
317        wait_clock_cycles!(sim, clock, x, 10);
318        for test in &test_cases {
319            i2c_begin_write!(sim, clock, x, test.address);
320            sim_assert!(sim, x.controller.ack.val() & !x.controller.nack.val(), x);
321            i2c_write!(sim, clock, x, test.reg_index);
322            i2c_write!(sim, clock, x, test.val_msb);
323            i2c_write!(sim, clock, x, test.val_lsb);
324            i2c_end_transmission!(sim, clock, x);
325        }
326        wait_clock_cycles!(sim, clock, x, 10);
327        for test in &test_cases {
328            i2c_begin_write!(sim, clock, x, test.address);
329            sim_assert!(sim, x.controller.ack.val() & !x.controller.nack.val(), x);
330            i2c_write!(sim, clock, x, test.reg_index);
331            sim_assert!(sim, x.controller.ack.val() & !x.controller.nack.val(), x);
332            i2c_end_transmission!(sim, clock, x);
333            i2c_begin_read!(sim, clock, x, test.address);
334            sim_assert!(sim, x.controller.ack.val() & !x.controller.nack.val(), x);
335            let byte = i2c_read!(sim, clock, x);
336            sim_assert_eq!(sim, byte, test.val_msb.to_bits::<8>(), x);
337            let byte = i2c_read_last!(sim, clock, x);
338            sim_assert_eq!(sim, byte, test.val_lsb.to_bits::<8>(), x);
339            i2c_end_transmission!(sim, clock, x);
340        }
341        sim.done(x)
342    });
343    sim.run_to_file(
344        Box::new(uut),
345        160_000_000_000,
346        &vcd_path!("i2c_controller.vcd"),
347    )
348    .unwrap()
349}