opentitanlib/test_utils/bitbanging/
i2c.rs

1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5use super::Bit;
6use anyhow::{Context, Result, bail};
7use arrayvec::ArrayVec;
8
9#[derive(Debug, PartialEq)]
10enum Symbol {
11    Start,
12    Stop,
13    Byte { data: u8, nack: bool },
14    Broken(ArrayVec<Bit, 8>),
15}
16
17impl Symbol {
18    pub fn broken(data: u8, bits: usize) -> Result<Self> {
19        if !(1..8).contains(&bits) {
20            bail!("Samples must be between 1 and 7");
21        }
22        let buffer: ArrayVec<Bit, 8> = (0..bits).map(|bit| Bit::from(data << bit)).collect();
23
24        Ok(Self::Broken(buffer))
25    }
26
27    // We must extend the transaction: in a given sample, if data is written to SDA at the same time as SCL
28    // being driven high, then physical factors e.g. capacitance can cause the SDA write to appear before
29    // the SCL, even though the order of bitbanging is reversed. This can then cause a mistaken "STOP" signal
30    // to be received. We instead run at half frequency: on one cycle write SDA, and on the next write SCL.
31    // This makes GPIO bitbanging of I2C signals reliable.
32    // Assumes that SCL is low (0) when called.
33    pub fn bitbanging<const SDA: u8, const SCL: u8>(&self, samples: &mut Vec<u8>) {
34        match self {
35            // Each sample is translated into 2 samples: the first changes the SDA, and
36            // the second changes the SCL, to ensure correct ordering.
37            Symbol::Start => samples.extend([
38                // SDA high, SCL high
39                0x01 << SDA | 0x00 << SCL,
40                0x01 << SDA | 0x01 << SCL,
41                // SDA low, SCL high
42                0x00 << SDA | 0x01 << SCL,
43                0x00 << SDA | 0x01 << SCL,
44                // SDA low, SCL low
45                0x00 << SDA | 0x01 << SCL,
46                0x00 << SDA | 0x00 << SCL,
47            ]),
48            Symbol::Stop => samples.extend([
49                // SDA low, SCL low
50                0x00 << SDA | 0x00 << SCL,
51                0x00 << SDA | 0x00 << SCL,
52                // SDA low, SCL high
53                0x00 << SDA | 0x00 << SCL,
54                0x00 << SDA | 0x01 << SCL,
55                // SDA high, SCL high
56                0x01 << SDA | 0x01 << SCL,
57                0x01 << SDA | 0x01 << SCL,
58            ]),
59            Symbol::Byte { data, nack } => Self::bitbanging_byte::<SDA, SCL>(*data, *nack, samples),
60            Symbol::Broken(bits) => Self::bitbanging_bits::<SDA, SCL>(bits, samples),
61        }
62    }
63
64    fn bitbanging_byte<const SDA: u8, const SCL: u8>(byte: u8, nack: bool, samples: &mut Vec<u8>) {
65        let data: u16 = (byte as u16) << 1u16 | nack as u16;
66        samples.extend((0..9u8).rev().flat_map(|bit| {
67            [
68                // Change SDA (to data), SCL high
69                ((((data >> bit) & 0x01) << SDA) | 0x00 << SCL) as u8,
70                ((((data >> bit) & 0x01) << SDA) | 0x01 << SCL) as u8,
71                // Maintain SDA, SCL low
72                ((((data >> bit) & 0x01) << SDA) | 0x01 << SCL) as u8,
73                ((((data >> bit) & 0x01) << SDA) | 0x00 << SCL) as u8,
74            ]
75        }));
76    }
77
78    fn bitbanging_bits<const SDA: u8, const SCL: u8>(bits: &[Bit], samples: &mut Vec<u8>) {
79        samples.extend(bits.iter().rev().flat_map(|bit| {
80            [
81                // Change SDA (to data), SCL high
82                ((*bit as u8) << SDA) | 0x00 << SCL,
83                ((*bit as u8) << SDA) | 0x01 << SCL,
84                // Maintain SDA, SCL low
85                ((*bit as u8) << SDA) | 0x01 << SCL,
86                ((*bit as u8) << SDA) | 0x00 << SCL,
87            ]
88        }));
89    }
90}
91
92pub mod encoder {
93    use super::*;
94
95    #[derive(Debug, PartialEq)]
96    pub enum Transfer<'w> {
97        Start,
98        Stop,
99        Addr { addr: u8, read: bool, nack: bool },
100        Write(&'w [u8]),
101        Read(usize),
102        Broken(ArrayVec<Bit, 8>),
103    }
104
105    impl Transfer<'_> {
106        fn bitbanging<const SDA: u8, const SCL: u8>(
107            &self,
108            is_next_stop: bool,
109            samples: &mut Vec<u8>,
110        ) {
111            match self {
112                Transfer::Start => Symbol::Start.bitbanging::<SDA, SCL>(samples),
113                Transfer::Stop => Symbol::Stop.bitbanging::<SDA, SCL>(samples),
114                Transfer::Addr { addr, read, nack } => Symbol::Byte {
115                    data: (addr << 1) | *read as u8,
116                    nack: *nack,
117                }
118                .bitbanging::<SDA, SCL>(samples),
119                Transfer::Write(bytes) => {
120                    for byte in bytes.iter() {
121                        Symbol::Byte {
122                            data: *byte,
123                            nack: true,
124                        }
125                        .bitbanging::<SDA, SCL>(samples)
126                    }
127                }
128                Transfer::Broken(bits) => {
129                    Symbol::Broken(bits.clone()).bitbanging::<SDA, SCL>(samples)
130                }
131                Transfer::Read(len) => {
132                    for index in 0..*len {
133                        Symbol::Byte {
134                            data: 0xff,
135                            nack: index >= (len - 1) && is_next_stop,
136                        }
137                        .bitbanging::<SDA, SCL>(samples)
138                    }
139                }
140            }
141        }
142    }
143
144    pub struct Encoder<const SDA: u8, const SCL: u8> {}
145    impl<const SDA: u8, const SCL: u8> Encoder<SDA, SCL> {
146        // Note that this function will run I2C at half of the specified bitbanging sample frequency, because
147        // two cycles must be used per sample to ensure that changes to SDA appear before the rise of SCL,
148        // as otherwise I2C via GPIO bitbanging can be flaky.
149        pub fn run(&self, transfer: &[Transfer]) -> Vec<u8> {
150            let mut samples: Vec<u8> = Vec::new();
151            for window in transfer.windows(2) {
152                window[0]
153                    .bitbanging::<SDA, SCL>(window.get(1) == Some(&Transfer::Stop), &mut samples)
154            }
155
156            // We missed the last element for using the windows function to peek, so we parse the last element here.
157            transfer
158                .iter()
159                .last()
160                .unwrap()
161                .bitbanging::<SDA, SCL>(false, &mut samples);
162            samples
163        }
164    }
165}
166
167pub mod decoder {
168    use super::*;
169    use std::iter::Peekable;
170
171    #[derive(Debug, PartialEq)]
172    pub enum Transfer<'b> {
173        Start,
174        Stop,
175        Addr { addr: u8, read: bool, nack: bool },
176        Bytes { data: &'b [u8], nack: bool },
177        Broken(ArrayVec<Bit, 8>),
178    }
179
180    impl<'a> std::convert::From<Symbol> for Transfer<'a> {
181        fn from(symbol: Symbol) -> Self {
182            match symbol {
183                Symbol::Start => Self::Start,
184                Symbol::Stop => Self::Stop,
185                Symbol::Broken(bits) => Self::Broken(bits),
186                _ => panic!("Can't convert {:?} into Transfer", symbol),
187            }
188        }
189    }
190
191    enum DecodingState {
192        Start,
193        Bytes,
194    }
195
196    #[derive(Clone, Debug)]
197    struct Sample<const SDA: u8, const SCL: u8> {
198        raw: u8,
199    }
200
201    impl<const SDA: u8, const SCL: u8> Sample<SDA, SCL> {
202        fn sda(&self) -> Bit {
203            ((self.raw >> SDA) & 0x01).into()
204        }
205
206        fn scl(&self) -> Bit {
207            ((self.raw >> SCL) & 0x01).into()
208        }
209    }
210    pub struct Decoder<const SDA: u8, const SCL: u8> {
211        pub buffer: [u8; 256],
212    }
213
214    impl<const SDA: u8, const SCL: u8> Decoder<SDA, SCL> {
215        /// Loops until the clk transitions to low.
216        /// Returns a symbol (Start|Stop) in case the sda transitions while the clk is high.
217        /// The caller must make sure that the clock was high in the previous sample.
218        fn sample_on_fall_edge<I>(samples: &mut I) -> Result<Option<Symbol>>
219        where
220            I: Iterator<Item = Sample<SDA, SCL>>,
221        {
222            let mut previous: Option<Sample<SDA, SCL>> = None;
223            for sample in samples.by_ref() {
224                if sample.scl() == Bit::Low {
225                    return Ok(None); // No symbol found.
226                }
227                // If sda transitioned with the scl high it either means a stop or start symbol.
228                if let Some(previous) = previous
229                    && previous.sda() != sample.sda()
230                {
231                    return Ok(Some(match sample.sda() {
232                        Bit::High => Symbol::Stop,
233                        Bit::Low => Symbol::Start,
234                    }));
235                }
236                previous = Some(sample);
237            }
238            bail!("Ran out of samples and did not find fall edge")
239        }
240
241        /// Returns a sample when a raise clock edge is detected.
242        /// This function will not consume the sample where the raise clock is detected.
243        /// The caller must make sure that the clock was low in the previous sample.
244        fn sample_on_raise_edge<I>(samples: &mut Peekable<I>) -> Option<Sample<SDA, SCL>>
245        where
246            I: Iterator<Item = Sample<SDA, SCL>>,
247        {
248            while samples.next_if(|sample| sample.scl() == Bit::Low).is_some() {}
249            samples.peek().cloned()
250        }
251
252        fn loop_until<I>(samples: &mut I, sda: Bit, scl: Bit) -> Option<Sample<SDA, SCL>>
253        where
254            I: Iterator<Item = Sample<SDA, SCL>>,
255        {
256            samples
257                .by_ref()
258                .find(|sample| sample.sda() == sda && sample.scl() == scl)
259        }
260
261        fn find_start<I>(samples: &mut I) -> Result<Sample<SDA, SCL>>
262        where
263            I: Iterator<Item = Sample<SDA, SCL>>,
264        {
265            'outer: loop {
266                // While clock and sda is not high.
267                Self::loop_until(samples, Bit::High, Bit::High)
268                    .context("Beginning of start bit not found")?;
269
270                // SDA should transition to low while scl is high, marking the beginning of start condition.
271                for sample in samples.by_ref() {
272                    if sample.scl() == Bit::Low {
273                        continue 'outer;
274                    }
275
276                    if sample.sda() == Bit::Low {
277                        return Ok(sample);
278                    }
279                }
280                bail!("Start bit condition not found")
281            }
282        }
283
284        fn decode_symbol<I>(samples: &mut Peekable<I>) -> Result<Symbol>
285        where
286            I: Iterator<Item = Sample<SDA, SCL>>,
287        {
288            let mut byte = 0u16;
289            // 8 bits data + 1 bit ack/nack
290            for index in 0..9 {
291                let Ok(fall_sample) = Self::sample_on_fall_edge(samples) else {
292                    return Symbol::broken(byte as u8, index);
293                };
294
295                // Return in case a symbol was detected during fall sampling.
296                if let Some(symbol) = fall_sample {
297                    return Ok(symbol);
298                }
299
300                let Some(sample) = Self::sample_on_raise_edge(samples) else {
301                    return Symbol::broken(byte as u8, index);
302                };
303                byte <<= 1;
304                byte |= sample.sda() as u16;
305            }
306
307            Ok(Symbol::Byte {
308                data: (byte >> 1) as u8,
309                nack: byte & 0x01 == 1,
310            })
311        }
312
313        pub fn run(&mut self, samples: Vec<u8>) -> Result<Vec<Transfer<'_>>> {
314            let mut samples = samples
315                .into_iter()
316                .map(|raw| Sample::<SDA, SCL> { raw })
317                .peekable();
318            Self::find_start(&mut samples)?;
319            let mut trans = vec![Transfer::Start];
320            let mut state = DecodingState::Start;
321            let mut head_offset = 0usize;
322            let mut buffer = &mut self.buffer[..];
323
324            while let Ok(symbol) = Self::decode_symbol(&mut samples) {
325                state = match state {
326                    DecodingState::Start => match symbol {
327                        Symbol::Byte { data, nack } => {
328                            let read = (data & 1) == 1;
329                            trans.push(Transfer::Addr {
330                                addr: data >> 1,
331                                read,
332                                nack,
333                            });
334                            DecodingState::Bytes
335                        }
336                        _ => {
337                            trans.push(symbol.into());
338                            DecodingState::Start
339                        }
340                    },
341                    DecodingState::Bytes => match symbol {
342                        Symbol::Byte { data, nack } => {
343                            buffer[head_offset] = data;
344                            head_offset += 1;
345                            assert!(head_offset < buffer.len());
346                            if nack {
347                                let (filled, empty) = buffer.split_at_mut(head_offset);
348                                buffer = empty;
349                                head_offset = 0;
350                                trans.push(Transfer::Bytes { data: filled, nack });
351                                DecodingState::Start
352                            } else {
353                                DecodingState::Bytes
354                            }
355                        }
356                        Symbol::Start | Symbol::Stop => {
357                            if head_offset > 0 {
358                                let (filled, empty) = buffer.split_at_mut(head_offset);
359                                buffer = empty;
360                                head_offset = 0;
361                                trans.push(Transfer::Bytes {
362                                    data: filled,
363                                    nack: false,
364                                });
365                            }
366                            trans.push(symbol.into());
367                            DecodingState::Start
368                        }
369                        Symbol::Broken(_) => {
370                            trans.push(symbol.into());
371                            DecodingState::Start
372                        }
373                    },
374                }
375            }
376            Ok(trans)
377        }
378    }
379}