Skip to content

Commit 284c5e4

Browse files
feat: add spi slave mode (#164)
* feat: add spi slave mode * add example Signed-off-by: Leah <[email protected]>
1 parent 46bf2a8 commit 284c5e4

File tree

2 files changed

+128
-4
lines changed

2 files changed

+128
-4
lines changed

examples/spi_slave.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
//! Interfacing the on-board L3GD20 (gyroscope)
2+
#![deny(unsafe_code)]
3+
// #![deny(warnings)]
4+
#![no_main]
5+
#![no_std]
6+
7+
#[macro_use(entry, exception)]
8+
extern crate cortex_m_rt as rt;
9+
extern crate cortex_m;
10+
extern crate embedded_hal as ehal;
11+
extern crate panic_semihosting;
12+
extern crate stm32l4xx_hal as hal;
13+
14+
use crate::ehal::spi::{Mode, Phase, Polarity};
15+
use crate::hal::prelude::*;
16+
use crate::hal::spi::Spi;
17+
use crate::rt::ExceptionFrame;
18+
use cortex_m::asm;
19+
20+
/// SPI mode
21+
pub const MODE: Mode = Mode {
22+
phase: Phase::CaptureOnFirstTransition,
23+
polarity: Polarity::IdleLow,
24+
};
25+
26+
#[entry]
27+
fn main() -> ! {
28+
let p = hal::stm32::Peripherals::take().unwrap();
29+
30+
let mut flash = p.FLASH.constrain();
31+
let mut rcc = p.RCC.constrain();
32+
let mut pwr = p.PWR.constrain(&mut rcc.apb1r1);
33+
34+
// TRY the other clock configuration
35+
// let clocks = rcc.cfgr.freeze(&mut flash.acr);
36+
let _clocks = rcc
37+
.cfgr
38+
.sysclk(80.mhz())
39+
.pclk1(80.mhz())
40+
.pclk2(80.mhz())
41+
.freeze(&mut flash.acr, &mut pwr);
42+
43+
let mut gpioa = p.GPIOA.split(&mut rcc.ahb2);
44+
45+
// The `L3gd20` abstraction exposed by the `f3` crate requires a specific pin configuration to
46+
// be used and won't accept any configuration other than the one used here. Trying to use a
47+
// different pin configuration will result in a compiler error.
48+
let sck = gpioa.pa5.into_af5(&mut gpioa.moder, &mut gpioa.afrl);
49+
let miso = gpioa.pa6.into_af5(&mut gpioa.moder, &mut gpioa.afrl);
50+
let mosi = gpioa.pa7.into_af5(&mut gpioa.moder, &mut gpioa.afrl);
51+
52+
// clock speed is determined by the master
53+
let mut spi = Spi::spi1_slave(p.SPI1, (sck, miso, mosi), MODE, &mut rcc.apb2);
54+
55+
let mut data = [0x1];
56+
// this will block until the master starts the clock
57+
spi.transfer(&mut data).unwrap();
58+
59+
// when you reach this breakpoint you'll be able to inspect the variable `data` which contains the
60+
// data sent by the master
61+
asm::bkpt();
62+
63+
loop {
64+
continue;
65+
}
66+
}
67+
68+
#[exception]
69+
fn HardFault(ef: &ExceptionFrame) -> ! {
70+
panic!("{:#?}", ef);
71+
}

src/spi.rs

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ pub struct Spi<SPI, PINS> {
5656
}
5757

5858
macro_rules! hal {
59-
($($SPIX:ident: ($spiX:ident, $APBX:ident, $spiXen:ident, $spiXrst:ident, $pclkX:ident),)+) => {
59+
($($SPIX:ident: ($spiX:ident, $spiX_slave:ident, $APBX:ident, $spiXen:ident, $spiXrst:ident, $pclkX:ident),)+) => {
6060
$(
6161
impl<SCK, MISO, MOSI> Spi<$SPIX, (SCK, MISO, MOSI)> {
6262
/// Configures the SPI peripheral to operate in full duplex master mode
@@ -126,6 +126,59 @@ macro_rules! hal {
126126
Spi { spi, pins }
127127
}
128128

129+
pub fn $spiX_slave(spi: $SPIX, pins: (SCK, MISO, MOSI), mode: Mode, apb2: &mut $APBX,) -> Self
130+
where
131+
SCK: SckPin<$SPIX>,
132+
MISO: MisoPin<$SPIX>,
133+
MOSI: MosiPin<$SPIX>,
134+
{
135+
// enable or reset $SPIX
136+
apb2.enr().modify(|_, w| w.$spiXen().set_bit());
137+
apb2.rstr().modify(|_, w| w.$spiXrst().set_bit());
138+
apb2.rstr().modify(|_, w| w.$spiXrst().clear_bit());
139+
140+
// CPOL: polarity
141+
// CPHA: phase
142+
// BIDIMODE: 2 line unidirectional (full duplex)
143+
// LSBFIRST: MSB first
144+
// CRCEN: hardware CRC calculation disabled
145+
// MSTR: master mode
146+
// SSM: disable software slave management (NSS pin not free for other uses)
147+
// SPE: SPI disabled
148+
spi.cr1.write(|w| {
149+
w.cpol()
150+
.bit(mode.polarity == Polarity::IdleHigh)
151+
.cpha()
152+
.bit(mode.phase == Phase::CaptureOnSecondTransition)
153+
.bidimode()
154+
.clear_bit()
155+
.lsbfirst()
156+
.clear_bit()
157+
.crcen()
158+
.clear_bit()
159+
.ssm()
160+
.clear_bit()
161+
.mstr()
162+
.clear_bit()
163+
});
164+
165+
// DS: 8-bit data size
166+
// FRXTH: RXNE event is generated if the FIFO level is greater than or equal to
167+
// 8-bit
168+
spi.cr2
169+
.write(|w| unsafe { w.ds().bits(0b111).frxth().set_bit() });
170+
171+
// SPE: SPI enabled
172+
spi.cr1.write(|w| w.spe().set_bit());
173+
174+
Spi { spi, pins }
175+
}
176+
177+
pub fn clear_overrun(&mut self) {
178+
self.spi.dr.read().dr();
179+
self.spi.sr.read().ovr();
180+
}
181+
129182
/// Change the baud rate of the SPI
130183
pub fn reclock<F>(&mut self, freq: F, clocks: Clocks)
131184
where F: Into<Hertz>
@@ -226,7 +279,7 @@ use crate::stm32::SPI1;
226279
feature = "stm32l4x6"
227280
))]
228281
hal! {
229-
SPI1: (spi1, APB2, spi1en, spi1rst, pclk2),
282+
SPI1: (spi1, spi1_slave, APB2, spi1en, spi1rst, pclk2),
230283
}
231284

232285
#[cfg(any(
@@ -259,7 +312,7 @@ use crate::{gpio::AF6, stm32::SPI3};
259312
feature = "stm32l4x6",
260313
))]
261314
hal! {
262-
SPI3: (spi3, APB1R1, spi3en, spi3rst, pclk1),
315+
SPI3: (spi3, spi3_slave, APB1R1, spi3en, spi3rst, pclk1),
263316
}
264317

265318
#[cfg(any(
@@ -291,7 +344,7 @@ use crate::stm32::SPI2;
291344
feature = "stm32l4x6",
292345
))]
293346
hal! {
294-
SPI2: (spi2, APB1R1, spi2en, spi2rst, pclk1),
347+
SPI2: (spi2, spi2_slave, APB1R1, spi2en, spi2rst, pclk1),
295348
}
296349

297350
#[cfg(any(

0 commit comments

Comments
 (0)