embedded_c_sdk_bind_hal/
spi.rs

1pub use crate::ll_api::{SpiBusBitOrder, SpiBusDataSize, SpiBusId, SpiBusMode};
2use crate::{ll_api::ll_cmd::*, tick::Delay};
3use core::{cmp::min, ptr};
4use embedded_hal::{delay::DelayNs, digital::OutputPin, spi::Operation};
5
6#[derive(Debug, PartialEq, Eq, Clone, Copy)]
7pub enum Error {
8    Code(i32),
9}
10
11/// Configuration structure for initializing a SPI (Serial Peripheral Interface) bus.
12///
13/// This struct holds the necessary parameters to configure a SPI bus before it can be used for communication.
14///
15/// # Fields
16/// * `baudrate` - The baud rate at which the SPI bus operates, specifying the speed of the serial communication.
17/// * `mode` - The SPI bus mode, determining the clock polarity and phase for data transmission and reception.
18/// * `size` - The data size per word transferred over the SPI bus, typically 8 or 16 bits.
19/// * `order` - The bit order for data transmission, either most significant bit first (MSB) or least significant bit first (LSB).
20pub struct Config {
21    pub baudrate: u32,
22    pub mode: SpiBusMode,
23    pub size: SpiBusDataSize,
24    pub order: SpiBusBitOrder,
25}
26
27impl Default for Config {
28    fn default() -> Self {
29        Self {
30            baudrate: 8_000_000,
31            mode: SpiBusMode::Mode0,
32            size: SpiBusDataSize::DataSize8,
33            order: SpiBusBitOrder::MsbFirst,
34        }
35    }
36}
37
38#[derive(Clone, Debug)]
39pub struct SpiBus {
40    bus: SpiBusId,
41}
42
43impl SpiBus {
44    /// Initializes a new SPI bus with the given configuration.
45    ///
46    /// # Arguments
47    /// * `bus` - The identifier for the SPI bus.
48    /// * `config` - A reference to the configuration parameters for the SPI bus.
49    ///
50    /// # Returns
51    /// A new `SpiBus` instance configured according to the provided parameters.
52    pub fn new(bus: SpiBusId, config: &Config) -> Self {
53        let flags = config.size as u32 | config.order as u32;
54        ll_invoke_inner!(INVOKE_ID_SPI_INIT, bus, config.mode, flags, config.baudrate);
55        SpiBus { bus }
56    }
57
58    /// Converts the SPI bus into a SPI device by associating it with a chip select pin.
59    ///
60    /// # Arguments
61    /// * `nss` - The chip select pin configured as an output.
62    ///
63    /// # Returns
64    /// A `SpiDevice` instance ready to communicate with a specific device.
65    pub fn to_device<NSS: OutputPin>(self, nss: NSS) -> SpiDevice<NSS> {
66        SpiDevice { bus: self, nss }
67    }
68
69    /// Performs a blocking read operation on the SPI bus.
70    ///
71    /// # Arguments
72    /// * `words` - A mutable slice where the read data will be stored.
73    ///
74    /// # Returns
75    /// The number of bytes read or an error code.
76    fn blocking_read(&mut self, words: &mut [u8]) -> i32 {
77        ll_invoke_inner!(
78            INVOKE_ID_SPI_BLOCKING_RW,
79            self.bus,
80            ptr::null::<u8>(),
81            words.as_mut_ptr(),
82            words.len()
83        )
84    }
85
86    /// Performs a blocking write operation on the SPI bus.
87    ///
88    /// # Arguments
89    /// * `words` - A slice containing the data to be written.
90    ///
91    /// # Returns
92    /// The number of bytes written or an error code.
93    fn blocking_write(&mut self, words: &[u8]) -> i32 {
94        ll_invoke_inner!(
95            INVOKE_ID_SPI_BLOCKING_RW,
96            self.bus,
97            words.as_ptr(),
98            ptr::null::<u8>(),
99            words.len()
100        )
101    }
102
103    /// Performs a blocking transfer operation on the SPI bus.
104    ///
105    /// # Arguments
106    /// * `read` - A mutable slice where the received data will be stored.
107    /// * `write` - A slice containing the data to be sent.
108    ///
109    /// # Returns
110    /// The number of bytes transferred or an error code.
111    fn blocking_transfer(&mut self, read: &mut [u8], write: &[u8]) -> i32 {
112        let size = min(read.len(), write.len());
113        ll_invoke_inner!(
114            INVOKE_ID_SPI_BLOCKING_RW,
115            self.bus,
116            write.as_ptr(),
117            read.as_ptr(),
118            size
119        )
120    }
121
122    /// Performs a blocking transfer operation in place on the SPI bus.
123    ///
124    /// # Arguments
125    /// * `words` - A mutable slice for both sending and receiving data.
126    ///
127    /// # Returns
128    /// The number of bytes transferred or an error code.
129    fn blocking_transfer_in_place(&mut self, words: &mut [u8]) -> i32 {
130        let rw_ptr = words.as_ptr();
131        ll_invoke_inner!(
132            INVOKE_ID_SPI_BLOCKING_RW,
133            self.bus,
134            rw_ptr,
135            rw_ptr,
136            words.len()
137        )
138    }
139}
140
141impl Drop for SpiBus {
142    fn drop(&mut self) {
143        ll_invoke_inner!(INVOKE_ID_SPI_DEINIT, self.bus);
144    }
145}
146
147impl embedded_hal::spi::ErrorType for SpiBus {
148    type Error = Error;
149}
150
151impl embedded_hal::spi::SpiBus for SpiBus {
152    fn flush(&mut self) -> Result<(), Self::Error> {
153        Ok(())
154    }
155
156    fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
157        let result = self.blocking_read(words);
158        if result == 0 {
159            return Ok(());
160        }
161        return Err(Error::Code(result));
162    }
163
164    fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
165        let result = self.blocking_write(words);
166        if result == 0 {
167            return Ok(());
168        }
169        return Err(Error::Code(result));
170    }
171
172    fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
173        let result = self.blocking_transfer(read, write);
174        if result == 0 {
175            return Ok(());
176        }
177        return Err(Error::Code(result));
178    }
179
180    fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
181        let result = self.blocking_transfer_in_place(words);
182        if result == 0 {
183            return Ok(());
184        }
185        return Err(Error::Code(result));
186    }
187}
188
189impl embedded_hal::spi::Error for Error {
190    fn kind(&self) -> embedded_hal::spi::ErrorKind {
191        match *self {
192            Self::Code(_) => embedded_hal::spi::ErrorKind::Other,
193        }
194    }
195}
196
197pub struct SpiDevice<NSS> {
198    bus: SpiBus,
199    nss: NSS,
200}
201
202impl<NSS: OutputPin> SpiDevice<NSS> {
203    /// Creates a new `SpiDevice` instance.
204    ///
205    /// # Arguments
206    /// * `bus` - A reference to the SPI bus this device will communicate over.
207    /// * `nss` - A pin configured as an output, used as the chip select line for the device.
208    ///
209    /// # Returns
210    /// A new `SpiDevice` instance ready to communicate with the device over the provided SPI bus.
211    pub fn new(bus: SpiBus, nss: NSS) -> Self {
212        SpiDevice { bus, nss }
213    }
214}
215
216impl<NSS: OutputPin> embedded_hal::spi::ErrorType for SpiDevice<NSS> {
217    type Error = Error;
218}
219
220impl<NSS: OutputPin> embedded_hal::spi::SpiDevice for SpiDevice<NSS> {
221    fn transaction(&mut self, operations: &mut [Operation<'_, u8>]) -> Result<(), Self::Error> {
222        let mut result = Ok(());
223
224        self.nss.set_low().ok();
225        for op in operations {
226            match op {
227                Operation::Read(words) => {
228                    let ret = self.bus.blocking_read(words);
229                    if ret != 0 {
230                        result = Err(Error::Code(ret));
231                    }
232                }
233                Operation::Write(words) => {
234                    let ret = self.bus.blocking_write(words);
235                    if ret != 0 {
236                        result = Err(Error::Code(ret));
237                    }
238                }
239                Operation::Transfer(rd_words, wr_words) => {
240                    let ret = self.bus.blocking_transfer(rd_words, wr_words);
241                    if ret != 0 {
242                        result = Err(Error::Code(ret));
243                    }
244                }
245                Operation::TransferInPlace(words) => {
246                    let ret = self.bus.blocking_transfer_in_place(words);
247                    if ret != 0 {
248                        result = Err(Error::Code(ret));
249                    }
250                }
251                Operation::DelayNs(ns) => {
252                    let mut delay = Delay::new();
253                    delay.delay_ns(*ns);
254                }
255            }
256        }
257        self.nss.set_high().ok();
258
259        result
260    }
261}