Skip to main content

jtag_scanner/protocols/
spi.rs

1use embedded_hal::spi::{Mode, Phase, Polarity, SpiBus};
2
3use crate::{Error, PinGroup, PinId};
4
5pub struct Spi {
6    pin_group: PinGroup,
7    sck: PinId,
8    mosi: PinId,
9    miso: PinId,
10    mode: Mode,
11    lsb_first: bool,
12}
13
14impl Spi {
15    /// Creates the adapter for `SpiBus`. Check `embedded-hal-bus` for
16    /// how to turn it into an `SpiDevice`.
17    ///
18    /// Expects **exclusive** access to `SCK`, `MOSI`, `MISO` in the `pin_group`.
19    pub fn new(mut pin_group: PinGroup, mode: Mode) -> Result<Self, Error> {
20        let sck = pin_group.get_pin_id("SCK")?;
21        let mosi = pin_group.get_pin_id("MOSI")?;
22        let miso = pin_group.get_pin_id("MISO")?;
23        if !sck.is_output()
24            || !pin_group.pin_writable(&sck)?
25            || !mosi.is_output()
26            || !pin_group.pin_writable(&mosi)?
27            || !miso.is_input()
28        {
29            return Error::result(crate::ErrorKind::WrongPinType, "bad SPI pin config");
30        }
31        pin_group.set_pin_state(&sck, Some(mode.polarity == Polarity::IdleHigh))?;
32        if miso.is_output() && pin_group.pin_writable(&miso)? {
33            pin_group.set_pin_state(&miso, None)?;
34        }
35        pin_group.write_update()?;
36        Ok(Self {
37            pin_group,
38            sck,
39            miso,
40            mosi,
41            mode,
42            lsb_first: false,
43        })
44    }
45
46    /// Set it to true if bits in a byte should be clocked out from LSB to MSB.
47    /// False by default.
48    pub fn set_lsb_first(&mut self, val: bool) {
49        self.lsb_first = val;
50    }
51}
52
53impl embedded_hal::spi::Error for Error {
54    fn kind(&self) -> embedded_hal::spi::ErrorKind {
55        embedded_hal::spi::ErrorKind::Other
56    }
57}
58
59impl embedded_hal::spi::ErrorType for Spi {
60    type Error = Error;
61}
62
63impl SpiBus for Spi {
64    fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
65        let len = read.len().max(write.len());
66        if len == 0 {
67            return Ok(());
68        }
69        let cpha = self.mode.phase == Phase::CaptureOnSecondTransition;
70        let cpol = self.mode.polarity == Polarity::IdleHigh;
71
72        let mut set_bit = |bit_index: usize, val: bool| {
73            let i_byte = bit_index / 8;
74            if i_byte >= read.len() {
75                return; // no-op
76            }
77            let i_bit = if self.lsb_first {
78                bit_index % 8
79            } else {
80                7 - bit_index % 8
81            };
82            if val {
83                read[i_byte] |= 1 << i_bit;
84            } else {
85                read[i_byte] &= 0xFF ^ (1 << i_bit);
86            }
87        };
88
89        let get_bit = |bit_index: usize| -> bool {
90            let i_byte = bit_index / 8;
91            if i_byte >= write.len() {
92                return false; // for padding 0s
93            }
94            let i_bit = if self.lsb_first {
95                bit_index % 8
96            } else {
97                7 - bit_index % 8
98            };
99            ((write[i_byte] >> i_bit) & 1) == 1
100        };
101
102        // i: 0, 2..: writes CLK to idle(CPHA=0) or non-idle(CPHA=1), writes `i / 2`th bit to MOSI.
103        // i: 1, 3..: writes CLK to non-idle(CPHA=0) or idle(CPHA=1), reads `i / 2`th bit from MISO.
104        self.pin_group.batch(
105            len * 8 * 2,
106            |i, edit| {
107                if i % 2 == 0 {
108                    let bit_index = i / 2;
109                    edit.set(&self.mosi, Some(get_bit(bit_index)))?;
110                    let sck_val = if cpha { !cpol } else { cpol };
111                    edit.set(&self.sck, Some(sck_val))?;
112                } else {
113                    let sck_val = if cpha { cpol } else { !cpol };
114                    edit.set(&self.sck, Some(sck_val))?;
115                }
116                Ok(())
117            },
118            |i, view| {
119                if i % 2 != 0 {
120                    let bit_index = i / 2;
121                    let bit_read = view.get(&self.miso)?.input().unwrap();
122                    set_bit(bit_index, bit_read);
123                }
124                Ok(())
125            },
126        )?;
127        if !cpha {
128            self.pin_group.set_pin_state(&self.sck, Some(cpol))?;
129            self.pin_group.write_update()?;
130        }
131        Ok(())
132    }
133
134    fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
135        for w in words.iter_mut() {
136            *w = 0x00;
137        }
138        self.transfer_in_place(words)
139    }
140    fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
141        let mut buf_read = vec![0x00; words.len()];
142        self.transfer(&mut buf_read, words)
143    }
144    fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
145        let buf_write = Vec::from(&mut *words);
146        self.transfer(words, &buf_write)
147    }
148    fn flush(&mut self) -> Result<(), Self::Error> {
149        Ok(())
150    }
151}