rust_hdl_widgets/i2c/
i2c_target.rs

1use crate::prelude::*;
2use rust_hdl_core::prelude::*;
3
4#[derive(Copy, Clone, PartialEq, Debug, LogicState)]
5enum State {
6    Idle,
7    Start,
8    Reading,
9    Waiting,
10    Flag,
11    Ack,
12    AckHold,
13    WaitEndTransaction,
14    CheckStop,
15    Writing,
16    WaitSCLHigh,
17    WaitSCLLow,
18    WaitSCLHighAck,
19    CollectAck,
20}
21
22#[derive(LogicBlock, Default)]
23pub struct I2CTarget {
24    pub i2c: I2CBusDriver,
25    pub clock: Signal<In, Clock>,
26    pub from_bus: Signal<Out, Bits<8>>,
27    pub bus_write: Signal<Out, Bit>,
28    pub active: Signal<In, Bit>,
29    pub stop: Signal<Out, Bit>,
30    pub to_bus: Signal<In, Bits<8>>,
31    pub write_enable: Signal<In, Bit>,
32    pub ack: Signal<Out, Bit>,
33    pub nack: Signal<Out, Bit>,
34    pub write_ok: Signal<Out, Bit>,
35    state: DFF<State>,
36    scl_is_high: Signal<Local, Bit>,
37    sda_is_high: Signal<Local, Bit>,
38    sda_flop: DFF<Bit>,
39    clear_sda: Signal<Local, Bit>,
40    set_sda: Signal<Local, Bit>,
41    read_bit: DFF<Bit>,
42    count: DFF<Bits<4>>,
43    accum: DFF<Bits<8>>,
44}
45
46impl Logic for I2CTarget {
47    #[hdl_gen]
48    fn update(&mut self) {
49        // Clock the internal structures
50        dff_setup!(self, clock, state, sda_flop, read_bit, count, accum);
51        // Latch prevention
52        self.i2c.scl.drive_low.next = false;
53        self.i2c.sda.drive_low.next = self.sda_flop.q.val();
54        self.sda_is_high.next = self.i2c.sda.line_state.val();
55        self.scl_is_high.next = self.i2c.scl.line_state.val();
56        self.set_sda.next = false;
57        self.clear_sda.next = false;
58        self.from_bus.next = self.accum.q.val();
59        self.bus_write.next = false;
60        self.stop.next = false;
61        self.ack.next = false;
62        self.nack.next = false;
63        self.write_ok.next = false;
64        // For now, can only read bits
65        match self.state.q.val() {
66            State::Idle => {
67                self.set_sda.next = true;
68                self.count.d.next = 0.into();
69                if !self.sda_is_high.val() & self.scl_is_high.val() {
70                    self.state.d.next = State::Start;
71                }
72            }
73            State::Start => {
74                if self.sda_is_high.val() {
75                    self.state.d.next = State::Idle;
76                } else if !self.sda_is_high.val() & !self.scl_is_high.val() {
77                    self.state.d.next = State::Reading;
78                }
79            }
80            State::Writing => {
81                if self.accum.q.val().get_bit(7) {
82                    self.set_sda.next = true;
83                } else {
84                    self.clear_sda.next = true;
85                }
86                self.count.d.next = self.count.q.val() + 1;
87                self.accum.d.next = self.accum.q.val() << 1;
88                self.state.d.next = State::WaitSCLHigh;
89                if self.count.q.val() == 8 {
90                    self.state.d.next = State::WaitSCLHighAck;
91                }
92            }
93            State::WaitSCLHighAck => {
94                if self.scl_is_high.val() {
95                    self.set_sda.next = true;
96                    self.state.d.next = State::CollectAck;
97                }
98            }
99            State::CollectAck => {
100                if !self.scl_is_high.val() {
101                    if self.sda_is_high.val() {
102                        self.nack.next = true;
103                    } else {
104                        self.ack.next = true;
105                    }
106                    self.state.d.next = State::Reading;
107                }
108            }
109            State::WaitSCLHigh => {
110                if self.scl_is_high.val() {
111                    self.state.d.next = State::WaitSCLLow;
112                }
113            }
114            State::WaitSCLLow => {
115                if !self.scl_is_high.val() {
116                    self.state.d.next = State::Writing;
117                }
118            }
119            State::Reading => {
120                self.write_ok.next = true;
121                if self.write_enable.val() {
122                    self.accum.d.next = self.to_bus.val();
123                    self.count.d.next = 0.into();
124                    self.state.d.next = State::Writing;
125                }
126                if self.scl_is_high.val() {
127                    self.read_bit.d.next = self.sda_is_high.val();
128                    self.state.d.next = State::Waiting;
129                }
130            }
131            State::Waiting => {
132                if !self.scl_is_high.val() {
133                    self.accum.d.next =
134                        (self.accum.q.val() << 1) | bit_cast::<8, 1>(self.read_bit.q.val().into());
135                    self.count.d.next = self.count.q.val() + 1;
136                    if self.count.q.val() == 7 {
137                        self.state.d.next = State::Flag;
138                    } else {
139                        self.state.d.next = State::Reading;
140                    }
141                }
142                if !self.read_bit.q.val() & self.sda_is_high.val() & self.scl_is_high.val() {
143                    self.stop.next = true;
144                    self.state.d.next = State::Idle;
145                }
146                if self.read_bit.q.val() & !self.sda_is_high.val() & self.scl_is_high.val() {
147                    self.stop.next = true;
148                    self.state.d.next = State::Idle;
149                }
150            }
151            State::Flag => {
152                self.bus_write.next = true;
153                self.accum.d.next = 0.into();
154                self.count.d.next = 0.into();
155                self.state.d.next = State::Ack;
156            }
157            State::Ack => {
158                self.clear_sda.next = self.active.val();
159                if !self.active.val() {
160                    self.state.d.next = State::WaitEndTransaction;
161                }
162                if self.scl_is_high.val() {
163                    self.state.d.next = State::AckHold;
164                }
165            }
166            State::AckHold => {
167                if !self.scl_is_high.val() {
168                    self.set_sda.next = true;
169                    self.state.d.next = State::Reading;
170                }
171            }
172            State::WaitEndTransaction => {
173                // A STOP condition is signalled by
174                // CLK -> H, SDA -> L
175                // CLK -> H, SDA -> H
176                if self.scl_is_high.val() & !self.sda_is_high.val() {
177                    self.state.d.next = State::CheckStop;
178                }
179            }
180            State::CheckStop => {
181                if self.scl_is_high.val() & self.sda_is_high.val() {
182                    self.state.d.next = State::Idle;
183                    self.stop.next = true;
184                }
185            }
186            _ => {
187                self.state.d.next = State::Idle;
188            }
189        }
190        if self.set_sda.val() {
191            self.sda_flop.d.next = false;
192        }
193        if self.clear_sda.val() {
194            self.sda_flop.d.next = true;
195        }
196    }
197}