Skip to main content

ph_qmi8658/interface/
spi.rs

1//! SPI interface adapter for the QMI8658.
2//!
3//! Experimental: the SPI transport has not been validated on hardware yet.
4
5use embedded_hal_async::spi::{Operation, SpiDevice};
6
7use super::{Interface, InterfaceSettings, sealed};
8use crate::error::Error;
9
10/// SPI interface configuration (experimental).
11#[derive(Clone, Copy, Debug, PartialEq, Eq)]
12#[cfg_attr(feature = "defmt", derive(defmt::Format))]
13pub struct SpiConfig {
14    pub(crate) auto_increment: bool,
15    pub(crate) big_endian: bool,
16    pub(crate) three_wire: bool,
17}
18
19impl SpiConfig {
20    /// Creates a new SPI configuration (4-wire, auto-increment, big-endian).
21    pub const fn new() -> Self {
22        Self {
23            auto_increment: true,
24            big_endian: true,
25            three_wire: false,
26        }
27    }
28
29    /// Enables or disables address auto-increment.
30    #[must_use]
31    pub const fn with_auto_increment(mut self, enable: bool) -> Self {
32        self.auto_increment = enable;
33        self
34    }
35
36    /// Sets the serial read endianness (CTRL1.BE).
37    #[must_use]
38    pub const fn with_big_endian(mut self, enable: bool) -> Self {
39        self.big_endian = enable;
40        self
41    }
42
43    /// Enables 3-wire SPI mode (CTRL1.SIM).
44    #[must_use]
45    pub const fn with_three_wire(mut self, enable: bool) -> Self {
46        self.three_wire = enable;
47        self
48    }
49
50    pub(crate) const fn interface_settings(self) -> InterfaceSettings {
51        InterfaceSettings::new(self.auto_increment, self.big_endian, self.three_wire)
52    }
53}
54
55impl Default for SpiConfig {
56    fn default() -> Self {
57        Self::new()
58    }
59}
60
61/// SPI register interface (experimental).
62pub struct SpiInterface<SPI> {
63    spi: SPI,
64}
65
66impl<SPI> SpiInterface<SPI> {
67    /// Creates a new SPI interface with the given bus.
68    pub const fn new(spi: SPI) -> Self {
69        Self { spi }
70    }
71
72    /// Releases the underlying SPI bus.
73    pub fn release(self) -> SPI {
74        self.spi
75    }
76}
77
78const SPI_READ_MASK: u8 = 0x80;
79
80const fn spi_addr_read(reg: u8) -> u8 {
81    (reg & 0x7F) | SPI_READ_MASK
82}
83
84const fn spi_addr_write(reg: u8) -> u8 {
85    reg & 0x7F
86}
87
88impl<SPI> Interface for SpiInterface<SPI>
89where
90    SPI: SpiDevice,
91{
92    async fn read_reg(&mut self, reg: u8) -> Result<u8, Error> {
93        let mut buffer = [0u8];
94        self.read_regs(reg, &mut buffer).await?;
95        Ok(buffer[0])
96    }
97
98    async fn read_regs(&mut self, reg: u8, buffer: &mut [u8]) -> Result<(), Error> {
99        if buffer.is_empty() {
100            return Ok(());
101        }
102        let addr = spi_addr_read(reg);
103        let addr_buf = [addr];
104        let mut ops = [Operation::Write(&addr_buf), Operation::Read(buffer)];
105        self.spi.transaction(&mut ops).await.map_err(|_| Error::Bus)
106    }
107
108    async fn write_reg(&mut self, reg: u8, value: u8) -> Result<(), Error> {
109        let addr = spi_addr_write(reg);
110        let buffer = [addr, value];
111        self.spi.write(&buffer).await.map_err(|_| Error::Bus)
112    }
113
114    async fn write_regs(&mut self, reg: u8, data: &[u8]) -> Result<(), Error> {
115        if data.is_empty() {
116            return Ok(());
117        }
118        let addr = spi_addr_write(reg);
119        let addr_buf = [addr];
120        let mut ops = [Operation::Write(&addr_buf), Operation::Write(data)];
121        self.spi.transaction(&mut ops).await.map_err(|_| Error::Bus)
122    }
123}
124
125impl<SPI> sealed::Sealed for SpiInterface<SPI> {}