Skip to main content

pic32_hal/
spi.rs

1//! SPI driver (SPI master)
2
3use crate::pac::{SPI1, SPI2};
4use core::{cmp::max, slice};
5use embedded_hal::spi::{ErrorKind, ErrorType, SpiBus};
6pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
7
8/// SPI error
9pub type Error = ErrorKind;
10
11pub enum Proto {
12    Spi(Mode),
13    AudioI2s(AudioFrameFormat),
14}
15
16/// Length of audio frame and length of sample/subframe
17#[derive(Copy, Clone, Debug, PartialEq)]
18pub enum AudioFrameFormat {
19    /// 32 bit frame, 16 bit samples
20    F32S16,
21    /// 64 bit frame, 16 bit samples
22    F64S16,
23    /// 64 bit frame, 24 bit samples
24    F64S24,
25    /// 64 bit frame, 32 bit samples
26    F64S32,
27}
28
29impl AudioFrameFormat {
30    fn mode16(self) -> bool {
31        match self {
32            AudioFrameFormat::F32S16 => false,
33            AudioFrameFormat::F64S16 => true,
34            AudioFrameFormat::F64S24 => true,
35            AudioFrameFormat::F64S32 => false,
36        }
37    }
38
39    fn mode32(self) -> bool {
40        match self {
41            AudioFrameFormat::F32S16 => false,
42            AudioFrameFormat::F64S16 => false,
43            AudioFrameFormat::F64S24 => true,
44            AudioFrameFormat::F64S32 => true,
45        }
46    }
47}
48
49pub struct Spi<SPI> {
50    spi: SPI,
51}
52
53macro_rules! spi {
54    ($Id:ident, $Spi:ident) => {
55        impl Spi<$Spi> {
56            /// create an SPI instance
57            ///
58            /// clock_div: clock divisor to initialize the BRG with. Only even
59            /// values can be configured, i.e. the LSB will be ignored. When a
60            /// value < 2 is given it will be replaced with 2.
61            /// `BRG = MAX(clock_div / 2 - 1, 0)`
62            pub fn $Id(spi: $Spi, proto: Proto, clock_div: u32) -> Self {
63                spi.con1.write(|w| unsafe { w.bits(0) }); // first turn SPI off
64                let brg1 = clock_div / 2;
65                let brg = if brg1 > 0 { brg1 - 1 } else { brg1 };
66                spi.brg.write(|w| unsafe { w.bits(brg) });
67                match proto {
68                    Proto::Spi(mode) => {
69                        let ckp = match mode.polarity {
70                            Polarity::IdleLow => false,
71                            Polarity::IdleHigh => true,
72                        };
73                        let cke = match mode.phase {
74                            Phase::CaptureOnFirstTransition => true,
75                            Phase::CaptureOnSecondTransition => false,
76                        };
77                        spi.con2.write(|w| unsafe { w.bits(0) });
78                        spi.con1.write(|w| {
79                            w.enhbuf()
80                                .bit(true)
81                                .cke()
82                                .bit(cke)
83                                .ckp()
84                                .bit(ckp)
85                                .msten()
86                                .bit(true)
87                        });
88                        spi.con1set.write(|w| w.on().bit(true));
89                    }
90                    Proto::AudioI2s(frame_format) => {
91                        spi.con2.write(|w| unsafe {
92                            w.ignrov()
93                                .bit(true)
94                                .igntur()
95                                .bit(true)
96                                .auden()
97                                .bit(true)
98                                .audmod()
99                                .bits(0b00) // I2S mode
100                        });
101                        spi.con1.write(|w| unsafe {
102                            w.mclksel()
103                                .bit(true) // use reference clock
104                                .enhbuf()
105                                .bit(true)
106                                .mode32()
107                                .bit(frame_format.mode32())
108                                .mode16()
109                                .bit(frame_format.mode16())
110                                .ckp()
111                                .bit(true)
112                                .stxisel()
113                                .bits(0b11) // IRQ when buffer not full
114                                .srxisel()
115                                .bits(0b01) // IRQ when buffer is not empty
116                                .msten()
117                                .bit(true)
118                                .on()
119                                .bit(true)
120                        });
121                    }
122                }
123                Spi { spi }
124            }
125
126            pub fn free(self) -> $Spi {
127                self.spi.con1.write(|w| w.on().bit(false)); // turn SPI off
128                self.spi
129            }
130        }
131
132        impl embedded_hal_0_2::spi::FullDuplex<u8> for Spi<$Spi> {
133            type Error = Error;
134
135            fn read(&mut self) -> nb::Result<u8, Error> {
136                if self.spi.stat.read().spirbe().bit() {
137                    Err(nb::Error::WouldBlock)
138                } else if self.spi.stat.read().spirov().bit() {
139                    self.spi.statclr.write(|w| w.spirov().bit(true));
140                    Err(nb::Error::Other(Error::Overrun))
141                } else {
142                    let byte = self.spi.buf.read().bits() as u8;
143                    Ok(byte)
144                }
145            }
146
147            fn send(&mut self, byte: u8) -> nb::Result<(), Error> {
148                if self.spi.stat.read().spitbf().bit() {
149                    Err(nb::Error::WouldBlock)
150                } else {
151                    self.spi.buf.write(|w| unsafe { w.bits(byte as u32) });
152                    Ok(())
153                }
154            }
155        }
156
157        impl embedded_hal_0_2::blocking::spi::transfer::Default<u8> for Spi<$Spi> {}
158        impl embedded_hal_0_2::blocking::spi::write::Default<u8> for Spi<$Spi> {}
159
160        impl ErrorType for Spi<$Spi> {
161            type Error = Error;
162        }
163
164        impl SpiBus<u8> for Spi<$Spi> {
165            fn read(&mut self, bytes: &mut [u8]) -> Result<(), Self::Error> {
166                self.transfer(bytes, &[])
167            }
168
169            fn write(&mut self, bytes: &[u8]) -> Result<(), Self::Error> {
170                self.transfer(&mut [], bytes)
171            }
172
173            fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
174                let xfer_len = max(read.len(), write.len());
175                let mut rd_ndx = 0;
176                let mut wr_ndx = 0;
177                // not using iterators for performance reasons
178                while rd_ndx < xfer_len || wr_ndx < xfer_len {
179                    // write to FIFO
180                    if wr_ndx < xfer_len && !self.spi.stat.read().spitbf().bit() {
181                        let byte = if wr_ndx < write.len() {
182                            write[wr_ndx]
183                        } else {
184                            0x00
185                        };
186                        self.spi.buf.write(|w| unsafe { w.bits(byte as u32) });
187                        wr_ndx += 1;
188                    }
189                    // read from FIFO
190                    if rd_ndx < xfer_len && !self.spi.stat.read().spirbe().bit() {
191                        let byte = self.spi.buf.read().bits() as u8;
192                        if rd_ndx < read.len() {
193                            read[rd_ndx] = byte;
194                        }
195                        rd_ndx += 1;
196                    }
197                }
198                Ok(())
199            }
200
201            fn transfer_in_place(&mut self, bytes: &mut [u8]) -> Result<(), Self::Error> {
202                let ptr = bytes.as_mut_ptr();
203                let len = bytes.len();
204                // This unsafe code works because transfer() always reads from a
205                // given byte position before writing back to it.
206                let read = unsafe { slice::from_raw_parts_mut(ptr, len) };
207                let write = unsafe { slice::from_raw_parts(ptr, len) };
208                self.transfer(read, write)
209            }
210
211            fn flush(&mut self) -> Result<(), Self::Error> {
212                Ok(())
213            }
214        }
215    };
216}
217
218spi!(spi1, SPI1);
219spi!(spi2, SPI2);