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 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 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 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#[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 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 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}