Skip to content

Commit 9de51c0

Browse files
authored
Add support for SPI. (#28)
1 parent 6beea3b commit 9de51c0

File tree

4 files changed

+337
-2
lines changed

4 files changed

+337
-2
lines changed

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ pub mod rcc;
7979
// pub mod rng;
8080
pub mod serial;
8181
pub mod signature;
82-
// pub mod spi;
82+
pub mod spi;
8383
// pub mod stopwatch;
8484
pub mod syscfg;
8585
pub mod time;

src/prelude.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ pub use crate::rcc::RccExt as _;
3232
// pub use crate::rng::RngCore as _;
3333
// pub use crate::rng::RngExt as _;
3434
pub use crate::serial::SerialExt as _;
35-
// pub use crate::spi::SpiExt as _;
35+
pub use crate::spi::SpiExt as _;
3636
pub use crate::time::U32Ext as _;
3737
// pub use crate::timer::opm::OpmExt as _;
3838
// pub use crate::timer::pwm::PwmExt as _;

src/rcc/.mod.rs.swp

16 KB
Binary file not shown.

src/spi.rs

Lines changed: 335 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,335 @@
1+
use crate::gpio::{gpioa::*, gpiob::*, gpioc::*, gpiof::*, Alternate, AF5, AF6};
2+
#[cfg(any(
3+
feature = "stm32g471",
4+
feature = "stm32g473",
5+
feature = "stm32g474",
6+
feature = "stm32g483",
7+
feature = "stm32g484"
8+
))]
9+
use crate::gpio::{gpioe::*, gpiog::*};
10+
use crate::rcc::{Enable, GetBusFreq, Rcc, RccBus, Reset};
11+
#[cfg(any(
12+
feature = "stm32g471",
13+
feature = "stm32g473",
14+
feature = "stm32g474",
15+
feature = "stm32g483",
16+
feature = "stm32g484"
17+
))]
18+
use crate::stm32::SPI4;
19+
use crate::stm32::{RCC, SPI1, SPI2, SPI3};
20+
use crate::time::Hertz;
21+
use core::ptr;
22+
pub use hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
23+
24+
/// SPI error
25+
#[derive(Debug)]
26+
pub enum Error {
27+
/// Overrun occurred
28+
Overrun,
29+
/// Mode fault occurred
30+
ModeFault,
31+
/// CRC error
32+
Crc,
33+
}
34+
35+
/// A filler type for when the SCK pin is unnecessary
36+
pub struct NoSck;
37+
/// A filler type for when the Miso pin is unnecessary
38+
pub struct NoMiso;
39+
/// A filler type for when the Mosi pin is unnecessary
40+
pub struct NoMosi;
41+
42+
pub trait Pins<SPI> {}
43+
44+
pub trait PinSck<SPI> {}
45+
46+
pub trait PinMiso<SPI> {}
47+
48+
pub trait PinMosi<SPI> {}
49+
50+
impl<SPI, SCK, MISO, MOSI> Pins<SPI> for (SCK, MISO, MOSI)
51+
where
52+
SCK: PinSck<SPI>,
53+
MISO: PinMiso<SPI>,
54+
MOSI: PinMosi<SPI>,
55+
{
56+
}
57+
58+
#[derive(Debug)]
59+
pub struct Spi<SPI, PINS> {
60+
spi: SPI,
61+
pins: PINS,
62+
}
63+
64+
pub trait SpiExt<SPI>: Sized {
65+
fn spi<PINS, T>(self, pins: PINS, mode: Mode, freq: T, rcc: &mut Rcc) -> Spi<SPI, PINS>
66+
where
67+
PINS: Pins<SPI>,
68+
T: Into<Hertz>;
69+
}
70+
71+
macro_rules! spi {
72+
($SPIX:ident, $spiX:ident,
73+
sck: [ $($( #[ $pmetasck:meta ] )* $SCK:ty,)+ ],
74+
miso: [ $($( #[ $pmetamiso:meta ] )* $MISO:ty,)+ ],
75+
mosi: [ $($( #[ $pmetamosi:meta ] )* $MOSI:ty,)+ ],
76+
) => {
77+
impl PinSck<$SPIX> for NoSck {}
78+
79+
impl PinMiso<$SPIX> for NoMiso {}
80+
81+
impl PinMosi<$SPIX> for NoMosi {}
82+
83+
$(
84+
$( #[ $pmetasck ] )*
85+
impl PinSck<$SPIX> for $SCK {}
86+
)*
87+
$(
88+
$( #[ $pmetamiso ] )*
89+
impl PinMiso<$SPIX> for $MISO {}
90+
)*
91+
$(
92+
$( #[ $pmetamosi ] )*
93+
impl PinMosi<$SPIX> for $MOSI {}
94+
)*
95+
96+
impl<PINS: Pins<$SPIX>> Spi<$SPIX, PINS> {
97+
pub fn $spiX<T>(
98+
spi: $SPIX,
99+
pins: PINS,
100+
mode: Mode,
101+
speed: T,
102+
rcc: &mut Rcc
103+
) -> Self
104+
where
105+
T: Into<Hertz>
106+
{
107+
// Enable and reset SPI
108+
unsafe {
109+
let rcc_ptr = &(*RCC::ptr());
110+
$SPIX::enable(rcc_ptr);
111+
$SPIX::reset(rcc_ptr);
112+
}
113+
114+
// disable SS output
115+
spi.cr2.write(|w| w.ssoe().clear_bit());
116+
117+
let spi_freq = speed.into().0;
118+
let bus_freq = <$SPIX as RccBus>::Bus::get_frequency(&rcc.clocks).0;
119+
let br = match bus_freq / spi_freq {
120+
0 => unreachable!(),
121+
1..=2 => 0b000,
122+
3..=5 => 0b001,
123+
6..=11 => 0b010,
124+
12..=23 => 0b011,
125+
24..=47 => 0b100,
126+
48..=95 => 0b101,
127+
96..=191 => 0b110,
128+
_ => 0b111,
129+
};
130+
131+
spi.cr2.write(|w| unsafe {
132+
w.frxth().set_bit().ds().bits(0b111).ssoe().clear_bit()
133+
});
134+
135+
spi.cr1.write(|w| unsafe {
136+
w.cpha()
137+
.bit(mode.phase == Phase::CaptureOnSecondTransition)
138+
.cpol()
139+
.bit(mode.polarity == Polarity::IdleHigh)
140+
.mstr()
141+
.set_bit()
142+
.br()
143+
.bits(br)
144+
.lsbfirst()
145+
.clear_bit()
146+
.ssm()
147+
.set_bit()
148+
.ssi()
149+
.set_bit()
150+
.rxonly()
151+
.clear_bit()
152+
.dff()
153+
.clear_bit()
154+
.bidimode()
155+
.clear_bit()
156+
.ssi()
157+
.set_bit()
158+
.spe()
159+
.set_bit()
160+
});
161+
162+
Spi { spi, pins }
163+
}
164+
165+
pub fn release(self) -> ($SPIX, PINS) {
166+
(self.spi, self.pins)
167+
}
168+
}
169+
170+
impl SpiExt<$SPIX> for $SPIX {
171+
fn spi<PINS, T>(self, pins: PINS, mode: Mode, freq: T, rcc: &mut Rcc) -> Spi<$SPIX, PINS>
172+
where
173+
PINS: Pins<$SPIX>,
174+
T: Into<Hertz>
175+
{
176+
Spi::$spiX(self, pins, mode, freq, rcc)
177+
}
178+
}
179+
180+
impl<PINS> hal::spi::FullDuplex<u8> for Spi<$SPIX, PINS> {
181+
type Error = Error;
182+
183+
fn read(&mut self) -> nb::Result<u8, Error> {
184+
let sr = self.spi.sr.read();
185+
186+
Err(if sr.ovr().bit_is_set() {
187+
nb::Error::Other(Error::Overrun)
188+
} else if sr.modf().bit_is_set() {
189+
nb::Error::Other(Error::ModeFault)
190+
} else if sr.crcerr().bit_is_set() {
191+
nb::Error::Other(Error::Crc)
192+
} else if sr.rxne().bit_is_set() {
193+
// NOTE(read_volatile) read only 1 byte (the svd2rust API only allows
194+
// reading a half-word)
195+
return Ok(unsafe {
196+
ptr::read_volatile(&self.spi.dr as *const _ as *const u8)
197+
});
198+
} else {
199+
nb::Error::WouldBlock
200+
})
201+
}
202+
203+
fn send(&mut self, byte: u8) -> nb::Result<(), Error> {
204+
let sr = self.spi.sr.read();
205+
206+
Err(if sr.ovr().bit_is_set() {
207+
nb::Error::Other(Error::Overrun)
208+
} else if sr.modf().bit_is_set() {
209+
nb::Error::Other(Error::ModeFault)
210+
} else if sr.crcerr().bit_is_set() {
211+
nb::Error::Other(Error::Crc)
212+
} else if sr.txe().bit_is_set() {
213+
// NOTE(write_volatile) see note above
214+
unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, byte) }
215+
return Ok(());
216+
} else {
217+
nb::Error::WouldBlock
218+
})
219+
}
220+
}
221+
222+
impl<PINS> ::hal::blocking::spi::transfer::Default<u8> for Spi<$SPIX, PINS> {}
223+
224+
impl<PINS> ::hal::blocking::spi::write::Default<u8> for Spi<$SPIX, PINS> {}
225+
}
226+
}
227+
228+
spi!(
229+
SPI1,
230+
spi1,
231+
sck: [
232+
PA5<Alternate<AF5>>,
233+
PB3<Alternate<AF5>>,
234+
#[cfg(any(
235+
feature = "stm32g471",
236+
feature = "stm32g473",
237+
feature = "stm32g474",
238+
feature = "stm32g483",
239+
feature = "stm32g484"
240+
))]
241+
PG2<Alternate<AF5>>,
242+
],
243+
miso: [
244+
PA6<Alternate<AF5>>,
245+
PB4<Alternate<AF5>>,
246+
#[cfg(any(
247+
feature = "stm32g471",
248+
feature = "stm32g473",
249+
feature = "stm32g474",
250+
feature = "stm32g483",
251+
feature = "stm32g484"
252+
))]
253+
PG3<Alternate<AF5>>,
254+
],
255+
mosi: [
256+
PA7<Alternate<AF5>>,
257+
PB5<Alternate<AF5>>,
258+
#[cfg(any(
259+
feature = "stm32g471",
260+
feature = "stm32g473",
261+
feature = "stm32g474",
262+
feature = "stm32g483",
263+
feature = "stm32g484"
264+
))]
265+
PG4<Alternate<AF5>>,
266+
],
267+
);
268+
269+
spi!(
270+
SPI2,
271+
spi2,
272+
sck: [
273+
PF1<Alternate<AF5>>,
274+
PF9<Alternate<AF5>>,
275+
PF10<Alternate<AF5>>,
276+
PB13<Alternate<AF5>>,
277+
],
278+
miso: [
279+
PA10<Alternate<AF5>>,
280+
PB14<Alternate<AF5>>,
281+
],
282+
mosi: [
283+
PA11<Alternate<AF5>>,
284+
PB15<Alternate<AF5>>,
285+
],
286+
);
287+
288+
spi!(
289+
SPI3,
290+
spi3,
291+
sck: [
292+
PB3<Alternate<AF6>>,
293+
PC10<Alternate<AF6>>,
294+
#[cfg(any(
295+
feature = "stm32g471",
296+
feature = "stm32g473",
297+
feature = "stm32g474",
298+
feature = "stm32g483",
299+
feature = "stm32g484"
300+
))]
301+
PG9<Alternate<AF6>>,
302+
],
303+
miso: [
304+
PB4<Alternate<AF6>>,
305+
PC11<Alternate<AF6>>,
306+
],
307+
mosi: [
308+
PB5<Alternate<AF6>>,
309+
PC12<Alternate<AF6>>,
310+
],
311+
);
312+
313+
#[cfg(any(
314+
feature = "stm32g471",
315+
feature = "stm32g473",
316+
feature = "stm32g474",
317+
feature = "stm32g483",
318+
feature = "stm32g484"
319+
))]
320+
spi!(
321+
SPI4,
322+
spi4,
323+
sck: [
324+
PE2<Alternate<AF5>>,
325+
PE12<Alternate<AF5>>,
326+
],
327+
miso: [
328+
PE5<Alternate<AF5>>,
329+
PE13<Alternate<AF5>>,
330+
],
331+
mosi: [
332+
PE6<Alternate<AF5>>,
333+
PE14<Alternate<AF5>>,
334+
],
335+
);

0 commit comments

Comments
 (0)