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}