stm32_hal2/spi/
h.rs

1// Note: This module contains lots of C+P from stm32h7xx-hal.
2
3use core::{cell::UnsafeCell, ops::Deref, ptr};
4
5use super::*;
6use crate::{
7    MAX_ITERS, check_errors,
8    pac::{self, RCC},
9    util::RccPeriph,
10};
11
12// Depth of FIFO to use. See RM0433 Rev 7, Table 409. Note that 16 is acceptable on this MCU,
13// for SPI 1-3
14const FIFO_LEN: usize = 8;
15
16/// Possible interrupt types. Enable these in SPIx_IER. Check with SR. Clear with IFCR
17#[derive(Copy, Clone)]
18pub enum SpiInterrupt {
19    /// Additional number of transactions reload interrupt enable (TSERFIE)
20    NumberOfTransactionsReload,
21    /// Mode fault (MODFIE)
22    ModeFault,
23    /// TIFRE (TIFREIE)
24    Tifre,
25    /// CRC error (CRCEIE)
26    CrcError,
27    /// Overrun (OVRIE)
28    Overrun,
29    /// Underrun (UNDRIE)
30    Underrun,
31    /// TXTFIE
32    Txtfie,
33    /// EOT, SUSP, and TXC (EOTIE)
34    EotSuspTxc,
35    /// DXP (TXPIE)
36    Dxp,
37    /// TXP (TXPIE)
38    Txp,
39    /// RXP (RXPIE)
40    Rxp,
41}
42
43/// Number of bits in at single SPI data frame. Sets `CFGR1` register, `DSIZE` field.
44#[derive(Copy, Clone)]
45#[repr(u8)]
46pub enum DataSize {
47    D4 = 3,
48    D5 = 4,
49    D6 = 5,
50    D7 = 6,
51    D8 = 7,
52    D9 = 8,
53    D10 = 9,
54    D11 = 10,
55    D12 = 11,
56    D13 = 12,
57    D14 = 13,
58    D15 = 14,
59    D16 = 15,
60    D17 = 16,
61    D18 = 17,
62    D19 = 18,
63    D20 = 19,
64    D21 = 20,
65    D22 = 21,
66    D23 = 22,
67    D24 = 23,
68    D25 = 24,
69    D26 = 25,
70    D27 = 26,
71    D28 = 27,
72    D29 = 28,
73    D30 = 29,
74    D31 = 30,
75    D32 = 31,
76}
77
78impl<R> Spi<R>
79where
80    R: Deref<Target = pac::spi1::RegisterBlock> + RccPeriph,
81{
82    /// Initialize an SPI peripheral, including configuration register writes, and enabling and resetting
83    /// its RCC peripheral clock.
84    pub fn new(regs: R, cfg: SpiConfig, baud_rate: BaudRate) -> Self {
85        let rcc = unsafe { &(*RCC::ptr()) };
86        R::en_reset(rcc);
87
88        // H743 RM, section 50.4.8: Configuration of SPI.
89        // 1. Write the proper GPIO registers: Configure GPIO for MOSI, MISO and SCK pins.
90        // (Handled in application code)
91
92        // 2. Write to the SPI_CFG1 and SPI_CFG2 registers to set up proper values of all not
93        // reserved bits and bit fields included there with next exceptions:
94        // a) SSOM, SSOE, MBR[2:0], MIDI[3:0] and MSSI[3:0] are required at master mode
95        // only, the MSSI bits take effect when SSOE is set, MBR setting is required for slave
96        // at TI mode, too
97        // b) UDRDET[1:0] and UDRCFG[1:0] are required at slave mode only,
98        // c) CRCSIZE[4:0] is required if CRCEN is set,
99        // d) CPOL, CPHA, LSBFRST, SSOM, SSOE, SSIOP and SSM are not required at TI
100        // mode.
101        // e) Once the AFCNTR bit is set at SPI_CFG2 register, all the SPI outputs start to be
102        // propagated onto the associated GPIO pins regardless the peripheral enable so
103        // any later configurations changes of the SPI_CFG1 and SPI_CFG2 registers can
104        // affect level of signals at these pins.
105        // f) The I2SMOD bit at SPI_I2SCFGR register has to be kept cleared to prevent any
106        // unexpected influence of occasional I2S configuration.
107
108        // [St forum thread on how to set up SPI in master mode avoiding mode faults:
109        // https://community.st.com/s/question/0D50X0000AFrHS6SQN/stm32h7-what-is-the-proper-
110        // way-to-make-spi-work-in-master-mode
111        regs.cr1
112            .modify(|_, w| w.ssi().bit(cfg.slave_select == SlaveSelect::Software));
113
114        regs.cfg1.modify(|_, w| {
115            w.mbr().bits(baud_rate as u8);
116            w.dsize().bits(cfg.data_size as u8);
117            w.crcen().clear_bit()
118        });
119
120        // Specifies minimum time delay (expressed in SPI clock cycles periods) inserted between two
121        // consecutive data frames in master mode. In clock cycles; 0 - 15. (hardware CS)
122        let inter_word_delay = 0;
123
124        regs.cfg2.modify(|_, w| {
125            w.cpol().bit(cfg.mode.polarity as u8 != 0);
126            w.cpha().bit(cfg.mode.phase as u8 != 0);
127            w.master().set_bit();
128            w.ssm().bit(cfg.slave_select == SlaveSelect::Software);
129            w.ssoe().bit(cfg.slave_select != SlaveSelect::Software);
130            w.midi().bits(inter_word_delay);
131            w.master().set_bit();
132            w.comm().bits(0b00) // Full-duplex mode
133        });
134
135        // 3. Write to the SPI_CR2 register to select length of the transfer, if it is not known TSIZE
136        // has to be programmed to zero.
137        // Resetting this here; will be set to the appropriate value at each transaction.
138        regs.cr2.modify(|_, w| w.tsize().bits(0));
139
140        // 4. Write to SPI_CRCPOLY and into TCRCINI, RCRCINI and CRC33_17 bits at
141        // SPI2S_CR1 register to configure the CRC polynomial and CRC calculation if needed.
142
143        // 5. Configure DMA streams dedicated for the SPI Tx and Rx in DMA registers if the DMA
144        // streams are used (see chapter Communication using DMA).
145
146        // 6. Program the IOLOCK bit in the SPI_CFG1 register if the configuration protection is
147        // required (for safety).
148
149        regs.cr1.modify(|_, w| w.spe().set_bit());
150
151        Self { regs, cfg }
152    }
153
154    /// Change the SPI baud rate.
155    pub fn reclock(&mut self, baud_rate: BaudRate) {
156        self.regs.cr1.modify(|_, w| w.spe().clear_bit());
157
158        self.regs
159            .cfg1
160            .modify(|_, w| unsafe { w.mbr().bits(baud_rate as u8) });
161
162        self.regs.cr1.modify(|_, w| w.spe().set_bit());
163    }
164
165    /// L44 RM, section 40.4.9: "Procedure for disabling the SPI"
166    /// When SPI is disabled, it is mandatory to follow the disable procedures described in this
167    /// paragraph. It is important to do this before the system enters a low-power mode when the
168    /// peripheral clock is stopped. Ongoing transactions can be corrupted in this case. In some
169    /// modes the disable procedure is the only way to stop continuous communication running.
170    pub fn disable(&mut self) {
171        // The correct disable procedure is (except when receive only mode is used):
172        // 1. Wait until TXC=1 and/or EOT=1 (no more data to transmit and last data frame sent).
173        // When CRC is used, it is sent automatically after the last data in the block is processed.
174        // TXC/EOT is set when CRC frame is completed in this case. When a transmission is
175        // suspended the software has to wait till CSTART bit is cleared.
176        while self.regs.sr.read().txc().bit_is_clear() {}
177        while self.regs.sr.read().eot().bit_is_clear() {}
178        // 2. Read all RxFIFO data (until RXWNE=0 and RXPLVL=00)
179        while self.regs.sr.read().rxwne().bit_is_set() || self.regs.sr.read().rxplvl().bits() != 0 {
180            unsafe { ptr::read_volatile(&self.regs.rxdr as *const _ as *const u8) };
181        }
182        // 3. Disable the SPI (SPE=0).
183        self.regs.cr1.modify(|_, w| w.spe().clear_bit());
184    }
185
186    // todo: Temp C+P from h7xx hal while troubleshooting.
187    /// Internal implementation for exchanging a word
188    ///
189    /// * Assumes the transaction has started (CSTART handled externally)
190    /// * Assumes at least one word has already been written to the Tx FIFO
191    fn exchange(&mut self, word: u8) -> Result<u8, SpiError> {
192        let status = self.regs.sr.read();
193        check_errors!(status);
194
195        let mut i = 0;
196        while !self.regs.sr.read().dxp().is_available() {
197            i += 1;
198            if i >= MAX_ITERS {
199                return Err(SpiError::Hardware);
200            }
201        }
202
203        // NOTE(write_volatile/read_volatile) write/read only 1 word
204        unsafe {
205            let txdr = &self.regs.txdr as *const _ as *const UnsafeCell<u8>;
206            ptr::write_volatile(UnsafeCell::raw_get(txdr), word);
207            return Ok(ptr::read_volatile(&self.regs.rxdr as *const _ as *const u8));
208        }
209    }
210    /// Read a single byte if available, or block until it's available.
211    ///
212    /// Assumes the transaction has started (CSTART handled externally)
213    /// Assumes at least one word has already been written to the Tx FIFO
214    pub fn read(&mut self) -> Result<u8, SpiError> {
215        check_errors!(self.regs.sr.read());
216
217        let mut i = 0;
218        while !self.regs.sr.read().rxp().is_not_empty() {
219            i += 1;
220            if i >= MAX_ITERS {
221                return Err(SpiError::Hardware);
222            }
223        }
224
225        // NOTE(read_volatile) read only 1 word
226        return Ok(unsafe { ptr::read_volatile(&self.regs.rxdr as *const _ as *const u8) });
227    }
228
229    /// Write multiple bytes on the SPI line, blocking until complete.
230    pub fn write(&mut self, write_words: &[u8]) -> Result<(), SpiError> {
231        // both buffers are the same length
232        if write_words.is_empty() {
233            return Ok(());
234        }
235
236        // Fill the first half of the write FIFO
237        let len = write_words.len();
238        let mut write = write_words.iter();
239        for _ in 0..core::cmp::min(FIFO_LEN, len) {
240            self.send(*write.next().unwrap());
241        }
242
243        // Continue filling write FIFO and emptying read FIFO
244        for word in write {
245            let _ = self.exchange(*word);
246        }
247
248        // Dummy read from the read FIFO
249        for _ in 0..core::cmp::min(FIFO_LEN, len) {
250            let _ = self.read();
251        }
252
253        Ok(())
254    }
255
256    /// Read multiple bytes to a buffer, blocking until complete.
257    pub fn transfer(&mut self, words: &mut [u8]) -> Result<(), SpiError> {
258        if words.is_empty() {
259            return Ok(());
260        }
261
262        // Fill the first half of the write FIFO
263        let len = words.len();
264        for i in 0..core::cmp::min(FIFO_LEN, len) {
265            self.send(words[i]);
266        }
267
268        for i in FIFO_LEN..len + FIFO_LEN {
269            if i < len {
270                // Continue filling write FIFO and emptying read FIFO
271                let read_value = self.exchange(words[i])?;
272
273                words[i - FIFO_LEN] = read_value;
274            } else {
275                // Finish emptying the read FIFO
276                words[i - FIFO_LEN] = self.read()?;
277            }
278        }
279
280        Ok(())
281    }
282
283    fn send(&mut self, word: u8) -> Result<(), SpiError> {
284        check_errors!(self.regs.sr.read());
285
286        // NOTE(write_volatile) see note above
287        unsafe {
288            let txdr = &self.regs.txdr as *const _ as *const UnsafeCell<u8>;
289            ptr::write_volatile(UnsafeCell::raw_get(txdr), word)
290        }
291        // write CSTART to start a transaction in
292        // master mode
293        self.regs.cr1.modify(|_, w| w.cstart().started());
294
295        return Ok(());
296    }
297
298    /// Receive data using DMA. See H743 RM, section 50.4.14: Communication using DMA
299    pub unsafe fn read_dma(
300        &mut self,
301        buf: &mut [u8],
302        channel: DmaChannel,
303        channel_cfg: ChannelCfg,
304        dma_periph: dma::DmaPeriph,
305    ) {
306        // todo: Accept u16 and u32 words too.
307        let (ptr, len) = (buf.as_mut_ptr(), buf.len());
308
309        self.regs.cr1.modify(|_, w| w.spe().clear_bit());
310        self.regs.cfg1.modify(|_, w| w.rxdmaen().set_bit());
311
312        let periph_addr = &self.regs.rxdr as *const _ as u32;
313        let num_data = len as u32;
314
315        match dma_periph {
316            dma::DmaPeriph::Dma1 => {
317                let mut regs = unsafe { &(*DMA1::ptr()) };
318                dma::cfg_channel(
319                    &mut regs,
320                    channel,
321                    periph_addr,
322                    ptr as u32,
323                    num_data,
324                    dma::Direction::ReadFromPeriph,
325                    dma::DataSize::S8,
326                    dma::DataSize::S8,
327                    channel_cfg,
328                );
329            }
330
331            dma::DmaPeriph::Dma2 => {
332                let mut regs = unsafe { &(*pac::DMA2::ptr()) };
333                dma::cfg_channel(
334                    &mut regs,
335                    channel,
336                    periph_addr,
337                    ptr as u32,
338                    num_data,
339                    dma::Direction::ReadFromPeriph,
340                    dma::DataSize::S8,
341                    dma::DataSize::S8,
342                    channel_cfg,
343                );
344            }
345        }
346
347        self.regs.cr1.modify(|_, w| w.spe().set_bit());
348        self.regs.cr1.modify(|_, w| w.cstart().set_bit()); // Must be separate from SPE enable.
349    }
350
351    pub unsafe fn write_dma(
352        &mut self,
353        buf: &[u8],
354        channel: DmaChannel,
355        channel_cfg: ChannelCfg,
356        dma_periph: dma::DmaPeriph,
357    ) {
358        // Static write and read buffers?
359        let (ptr, len) = (buf.as_ptr(), buf.len());
360
361        self.regs.cr1.modify(|_, w| w.spe().clear_bit());
362
363        // todo: Accept u16 words too.
364
365        // A DMA access is requested when the TXE or RXNE enable bit in the SPIx_CR2 register is
366        // set. Separate requests must be issued to the Tx and Rx buffers.
367        // In transmission, a DMA request is issued each time TXE is set to 1. The DMA then
368        // writes to the SPIx_DR register.
369
370        // When starting communication using DMA, to prevent DMA channel management raising
371        // error events, these steps must be followed in order:
372        //
373        // 1. Enable DMA Rx buffer in the RXDMAEN bit in the SPI_CR2 register, if DMA Rx is
374        // used.
375        // (N/A)
376
377        // 2. Enable DMA streams for Tx and Rx in DMA registers, if the streams are used.
378        let periph_addr = &self.regs.txdr as *const _ as u32;
379        let num_data = len as u32;
380
381        match dma_periph {
382            dma::DmaPeriph::Dma1 => {
383                let mut regs = unsafe { &(*DMA1::ptr()) };
384                dma::cfg_channel(
385                    &mut regs,
386                    channel,
387                    periph_addr,
388                    ptr as u32,
389                    num_data,
390                    dma::Direction::ReadFromMem,
391                    dma::DataSize::S8,
392                    dma::DataSize::S8,
393                    channel_cfg,
394                );
395            }
396            dma::DmaPeriph::Dma2 => {
397                let mut regs = unsafe { &(*pac::DMA2::ptr()) };
398                dma::cfg_channel(
399                    &mut regs,
400                    channel,
401                    periph_addr,
402                    ptr as u32,
403                    num_data,
404                    dma::Direction::ReadFromMem,
405                    dma::DataSize::S8,
406                    dma::DataSize::S8,
407                    channel_cfg,
408                );
409            }
410        }
411
412        // 3. Enable DMA Tx buffer in the TXDMAEN bit in the SPI_CR2 register, if DMA Tx is used.
413        self.regs.cfg1.modify(|_, w| w.txdmaen().set_bit());
414
415        // 4. Enable the SPI by setting the SPE bit.
416        self.regs.cr1.modify(|_, w| w.spe().set_bit());
417        self.regs.cr1.modify(|_, w| w.cstart().set_bit()); // Must be separate from SPE enable.
418    }
419
420    /// Transfer data from DMA; this is the basic reading API, using both write and read transfers:
421    /// It performs a write with register data, and reads to a buffer.
422    pub unsafe fn transfer_dma(
423        &mut self,
424        buf_write: &[u8],
425        buf_read: &mut [u8],
426        channel_write: DmaChannel,
427        channel_read: DmaChannel,
428        channel_cfg_write: ChannelCfg,
429        channel_cfg_read: ChannelCfg,
430        dma_periph: dma::DmaPeriph,
431    ) {
432        // todo: Accept u16 and u32 words too.
433        let (ptr_write, len_write) = (buf_write.as_ptr(), buf_write.len());
434        let (ptr_read, len_read) = (buf_read.as_mut_ptr(), buf_read.len());
435
436        self.regs.cr1.modify(|_, w| w.spe().clear_bit());
437
438        // todo: DRY here, with `write_dma`, and `read_dma`.
439
440        let periph_addr_write = &self.regs.txdr as *const _ as u32;
441        let periph_addr_read = &self.regs.rxdr as *const _ as u32;
442
443        let num_data_write = len_write as u32;
444        let num_data_read = len_read as u32;
445
446        // Be careful - order of enabling Rx and Tx may matter, along with other things like when we
447        // enable the channels, and the SPI periph.
448        self.regs.cfg1.modify(|_, w| w.rxdmaen().set_bit());
449
450        match dma_periph {
451            dma::DmaPeriph::Dma1 => {
452                let mut regs = unsafe { &(*DMA1::ptr()) };
453                dma::cfg_channel(
454                    &mut regs,
455                    channel_write,
456                    periph_addr_write,
457                    ptr_write as u32,
458                    num_data_write,
459                    dma::Direction::ReadFromMem,
460                    dma::DataSize::S8,
461                    dma::DataSize::S8,
462                    channel_cfg_write,
463                );
464
465                dma::cfg_channel(
466                    &mut regs,
467                    channel_read,
468                    periph_addr_read,
469                    ptr_read as u32,
470                    num_data_read,
471                    dma::Direction::ReadFromPeriph,
472                    dma::DataSize::S8,
473                    dma::DataSize::S8,
474                    channel_cfg_read,
475                );
476            }
477
478            dma::DmaPeriph::Dma2 => {
479                let mut regs = unsafe { &(*pac::DMA2::ptr()) };
480                dma::cfg_channel(
481                    &mut regs,
482                    channel_write,
483                    periph_addr_write,
484                    ptr_write as u32,
485                    num_data_write,
486                    dma::Direction::ReadFromMem,
487                    dma::DataSize::S8,
488                    dma::DataSize::S8,
489                    channel_cfg_write,
490                );
491
492                dma::cfg_channel(
493                    &mut regs,
494                    channel_read,
495                    periph_addr_read,
496                    ptr_read as u32,
497                    num_data_read,
498                    dma::Direction::ReadFromPeriph,
499                    dma::DataSize::S8,
500                    dma::DataSize::S8,
501                    channel_cfg_read,
502                );
503            }
504        }
505
506        self.regs.cfg1.modify(|_, w| w.txdmaen().set_bit());
507
508        self.regs.cr1.modify(|_, w| w.spe().set_bit());
509        self.regs.cr1.modify(|_, w| w.cstart().set_bit()); // Must be separate from SPE enable.
510    }
511
512    /// Enable an interrupt.
513    pub fn enable_interrupt(&mut self, interrupt_type: SpiInterrupt) {
514        self.regs.ier.modify(|_, w| match interrupt_type {
515            SpiInterrupt::NumberOfTransactionsReload => w.tserfie().set_bit(),
516            SpiInterrupt::ModeFault => w.modfie().set_bit(),
517            SpiInterrupt::Tifre => w.tifreie().set_bit(),
518            SpiInterrupt::CrcError => w.crceie().set_bit(),
519            SpiInterrupt::Overrun => w.ovrie().set_bit(),
520            SpiInterrupt::Underrun => w.udrie().set_bit(),
521            SpiInterrupt::Txtfie => w.txtfie().set_bit(),
522            SpiInterrupt::EotSuspTxc => w.eotie().set_bit(),
523            // SpiInterrupt::Dxp => w.dxpie().set_bit(),
524            // SpiInterrupt::Txp => w.txpie().set_bit(),
525            // SpiInterrupt::Rxp => w.rxpie().set_bit(),
526            _ => w.eotie().set_bit(), // todo: PAC ommission?
527        });
528    }
529
530    /// Clear an interrupt.
531    pub fn clear_interrupt(&mut self, interrupt_type: SpiInterrupt) {
532        self.regs.ifcr.write(|w| match interrupt_type {
533            SpiInterrupt::NumberOfTransactionsReload => w.tserfc().set_bit(),
534            SpiInterrupt::ModeFault => w.modfc().set_bit(),
535            SpiInterrupt::Tifre => w.tifrec().set_bit(),
536            SpiInterrupt::CrcError => w.crcec().set_bit(),
537            SpiInterrupt::Overrun => w.ovrc().set_bit(),
538            SpiInterrupt::Underrun => w.udrc().set_bit(),
539            SpiInterrupt::Txtfie => w.txtfc().set_bit(),
540            SpiInterrupt::EotSuspTxc => w.eotc().set_bit(),
541            // SpiInterrupt::Dxp => w.dxpc().set_bit(),
542            // SpiInterrupt::Txp => w.txpc().set_bit(),
543            // SpiInterrupt::Rxp => w.rxpc().set_bit(),
544            _ => w.eotc().set_bit(), // todo: PAC ommission?
545        });
546    }
547}