Skip to content

Commit 6aea05b

Browse files
burrbullTheZoq2
authored andcommitted
alternative implementation for SPI pins (#145)
Allows usage of the SPI peripheral without using all the pins.
1 parent d006750 commit 6aea05b

File tree

3 files changed

+155
-50
lines changed

3 files changed

+155
-50
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
3838

3939
### Changed
4040

41+
- Pins can be passed in any order to SPI constructor,
42+
`NoSck`, `NoMiso` and `NoMosi` can be also passed instead of real pin
4143
- DMA traits now require AsSlice instead of AsRef
4244
- GPIO `downgrade` function now returns a `Pxx` instead of a type specific to a
4345
GPIO port

src/rcc.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,11 @@ bus! {
557557
WWDG => (APB1, wwdgen, wwdgrst),
558558
}
559559

560+
#[cfg(feature = "high")]
561+
bus! {
562+
SPI3 => (APB1, spi3en, spi3rst),
563+
}
564+
560565
ahb_bus! {
561566
CRC => (crcen),
562567
DMA1 => (dma1en),

src/spi.rs

Lines changed: 148 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,43 @@
1-
//! # Serial Peripheral Interface
1+
/*!
2+
# Serial Peripheral Interface
3+
4+
## Alternate function remapping
5+
6+
### SPI1
7+
8+
| Function | Spi1NoRemap | Spi1Remap |
9+
|:----:|:-----------:|:---------:|
10+
| SCK | PA5 | PB3 |
11+
| MISO | PA6 | PB4 |
12+
| MOSI | PA7 | PB5 |
13+
14+
### SPI2
15+
16+
| Function | Spi2NoRemap |
17+
|:----:|:-----------:|
18+
| SCK | PB13 |
19+
| MISO | PB14 |
20+
| MOSI | PB15 |
21+
22+
### SPI3
23+
24+
Available only on high density devices.
25+
26+
| Function | Spi3NoRemap | Spi3Remap |
27+
|:----:|:-----------:|:---------:|
28+
| SCK | PB3 | PC10 |
29+
| MISO | PB4 | PC11 |
30+
| MOSI | PB5 | PC12 |
31+
*/
232

333
use core::ptr;
434

535
use nb;
636

737
pub use crate::hal::spi::{Mode, Phase, Polarity};
838
use crate::pac::{SPI1, SPI2};
39+
#[cfg(feature="high")]
40+
use crate::pac::SPI3;
941

1042
use crate::afio::MAPR;
1143
use crate::gpio::gpioa::{PA5, PA6, PA7};
@@ -33,47 +65,88 @@ pub enum Error {
3365
_Extensible,
3466
}
3567

36-
pub trait Pins<SPI> {
37-
const REMAP: bool;
38-
}
68+
use core::marker::PhantomData;
3969

40-
impl Pins<SPI1>
41-
for (
42-
PA5<Alternate<PushPull>>,
43-
PA6<Input<Floating>>,
44-
PA7<Alternate<PushPull>>,
45-
)
46-
{
47-
const REMAP: bool = false;
70+
mod sealed {
71+
pub trait Remap {
72+
type Periph;
73+
const REMAP: bool;
74+
}
75+
pub trait Sck<REMAP> {}
76+
pub trait Miso<REMAP> {}
77+
pub trait Mosi<REMAP> {}
78+
pub struct _Sck;
79+
pub struct _Miso;
80+
pub struct _Mosi;
4881
}
82+
use sealed::{Remap, Sck, Miso, Mosi};
4983

50-
impl Pins<SPI1>
51-
for (
52-
PB3<Alternate<PushPull>>,
53-
PB4<Input<Floating>>,
54-
PB5<Alternate<PushPull>>,
55-
)
56-
{
57-
const REMAP: bool = true;
84+
pub trait Pins<SPI, P> {
85+
type _Pos;
5886
}
59-
60-
impl Pins<SPI2>
61-
for (
62-
PB13<Alternate<PushPull>>,
63-
PB14<Input<Floating>>,
64-
PB15<Alternate<PushPull>>,
65-
)
66-
{
67-
const REMAP: bool = false;
87+
macro_rules! pins_impl {
88+
( $( ( $($PINX:ident),+ ), ( $($TRAIT:ident),+ ), ( $($POS:ident),* ); )+ ) => {
89+
$(
90+
#[allow(unused_parens)]
91+
impl<REMAP, $($PINX,)+> Pins<REMAP, ($(sealed::$POS),+)> for ($($PINX),+)
92+
where
93+
$($PINX: $TRAIT<REMAP>,)+
94+
{
95+
type _Pos = ($(sealed::$POS),+);
96+
}
97+
)+
98+
};
6899
}
69100

70-
pub struct Spi<SPI, PINS> {
101+
pins_impl!(
102+
(SCK, MISO, MOSI), (Sck, Miso, Mosi), (_Sck, _Miso, _Mosi);
103+
(SCK, MOSI, MISO), (Sck, Mosi, Miso), (_Sck, _Mosi, _Miso);
104+
(MOSI, SCK, MISO), (Mosi, Sck, Miso), (_Mosi, _Sck, _Miso);
105+
(MOSI, MISO, SCK), (Mosi, Miso, Sck), (_Mosi, _Miso, _Sck);
106+
(MISO, MOSI, SCK), (Miso, Mosi, Sck), (_Miso, _Mosi, _Sck);
107+
(MISO, SCK, MOSI), (Miso, Sck, Mosi), (_Miso, _Sck, _Mosi);
108+
);
109+
110+
pub struct Spi<SPI, REMAP, PINS> {
71111
spi: SPI,
72112
pins: PINS,
113+
_remap: PhantomData<REMAP>,
73114
}
74115

75-
impl<PINS> Spi<SPI1, PINS> {
76-
pub fn spi1<F>(
116+
/// A filler type for when the SCK pin is unnecessary
117+
pub struct NoSck;
118+
/// A filler type for when the Miso pin is unnecessary
119+
pub struct NoMiso;
120+
/// A filler type for when the Mosi pin is unnecessary
121+
pub struct NoMosi;
122+
123+
impl<REMAP> Sck<REMAP> for NoSck {}
124+
impl<REMAP> Miso<REMAP> for NoMiso {}
125+
impl<REMAP> Mosi<REMAP> for NoMosi {}
126+
127+
macro_rules! remap {
128+
($name:ident, $SPIX:ident, $state:literal, $SCK:ident, $MISO:ident, $MOSI:ident) => {
129+
pub struct $name;
130+
impl Remap for $name {
131+
type Periph = $SPIX;
132+
const REMAP: bool = $state;
133+
}
134+
impl Sck<$name> for $SCK<Alternate<PushPull>> {}
135+
impl Miso<$name> for $MISO<Input<Floating>> {}
136+
impl Mosi<$name> for $MOSI<Alternate<PushPull>> {}
137+
}
138+
}
139+
140+
remap!(Spi1NoRemap, SPI1, false, PA5, PA6, PA7);
141+
remap!(Spi1Remap, SPI1, true, PB3, PB4, PB5);
142+
remap!(Spi2NoRemap, SPI2, false, PB13, PB14, PB15);
143+
#[cfg(feature="high")]
144+
remap!(Spi3NoRemap, SPI3, false, PB3, PB4, PB5);
145+
#[cfg(feature = "stm32f105")]
146+
remap!(Spi3Remap, SPI3, true, PC10, PC11, PC12);
147+
148+
impl<REMAP, PINS> Spi<SPI1, REMAP, PINS> {
149+
pub fn spi1<F, POS>(
77150
spi: SPI1,
78151
pins: PINS,
79152
mapr: &mut MAPR,
@@ -84,15 +157,16 @@ impl<PINS> Spi<SPI1, PINS> {
84157
) -> Self
85158
where
86159
F: Into<Hertz>,
87-
PINS: Pins<SPI1>,
160+
REMAP: Remap<Periph = SPI1>,
161+
PINS: Pins<REMAP, POS>,
88162
{
89-
mapr.modify_mapr(|_, w| w.spi1_remap().bit(PINS::REMAP));
163+
mapr.modify_mapr(|_, w| w.spi1_remap().bit(REMAP::REMAP));
90164
Spi::_spi1(spi, pins, mode, freq.into(), clocks, apb)
91165
}
92166
}
93167

94-
impl<PINS> Spi<SPI2, PINS> {
95-
pub fn spi2<F>(
168+
impl<REMAP, PINS> Spi<SPI2, REMAP, PINS> {
169+
pub fn spi2<F, POS>(
96170
spi: SPI2,
97171
pins: PINS,
98172
mode: Mode,
@@ -102,16 +176,36 @@ impl<PINS> Spi<SPI2, PINS> {
102176
) -> Self
103177
where
104178
F: Into<Hertz>,
105-
PINS: Pins<SPI2>,
179+
REMAP: Remap<Periph = SPI2>,
180+
PINS: Pins<REMAP, POS>,
106181
{
107182
Spi::_spi2(spi, pins, mode, freq.into(), clocks, apb)
108183
}
109184
}
110185

186+
#[cfg(feature="high")]
187+
impl<REMAP, PINS> Spi<SPI3, REMAP, PINS> {
188+
pub fn spi3<F, POS>(
189+
spi: SPI3,
190+
pins: PINS,
191+
mode: Mode,
192+
freq: F,
193+
clocks: Clocks,
194+
apb: &mut <SPI3 as RccBus>::Bus,
195+
) -> Self
196+
where
197+
F: Into<Hertz>,
198+
REMAP: Remap<Periph = SPI3>,
199+
PINS: Pins<REMAP, POS>,
200+
{
201+
Spi::_spi3(spi, pins, mode, freq.into(), clocks, apb)
202+
}
203+
}
204+
111205
macro_rules! hal {
112206
($($SPIX:ident: ($spiX:ident),)+) => {
113207
$(
114-
impl<PINS> Spi<$SPIX, PINS> {
208+
impl<REMAP, PINS> Spi<$SPIX, REMAP, PINS> {
115209
fn $spiX(
116210
spi: $SPIX,
117211
pins: PINS,
@@ -171,15 +265,15 @@ macro_rules! hal {
171265
.set_bit()
172266
);
173267

174-
Spi { spi, pins }
268+
Spi { spi, pins, _remap: PhantomData }
175269
}
176270

177271
pub fn free(self) -> ($SPIX, PINS) {
178272
(self.spi, self.pins)
179273
}
180274
}
181275

182-
impl<PINS> crate::hal::spi::FullDuplex<u8> for Spi<$SPIX, PINS> {
276+
impl<REMAP, PINS> crate::hal::spi::FullDuplex<u8> for Spi<$SPIX, REMAP, PINS> {
183277
type Error = Error;
184278

185279
fn read(&mut self) -> nb::Result<u8, Error> {
@@ -222,9 +316,9 @@ macro_rules! hal {
222316

223317
}
224318

225-
impl<PINS> crate::hal::blocking::spi::transfer::Default<u8> for Spi<$SPIX, PINS> {}
319+
impl<REMAP, PINS> crate::hal::blocking::spi::transfer::Default<u8> for Spi<$SPIX, REMAP, PINS> {}
226320

227-
impl<PINS> crate::hal::blocking::spi::write::Default<u8> for Spi<$SPIX, PINS> {}
321+
impl<REMAP, PINS> crate::hal::blocking::spi::write::Default<u8> for Spi<$SPIX, REMAP, PINS> {}
228322
)+
229323
}
230324
}
@@ -233,32 +327,36 @@ hal! {
233327
SPI1: (_spi1),
234328
SPI2: (_spi2),
235329
}
330+
#[cfg(feature="high")]
331+
hal! {
332+
SPI3: (_spi3),
333+
}
236334

237335
// DMA
238336

239-
pub struct SpiPayload<SPI, PINS> {
240-
spi: Spi<SPI, PINS>
337+
pub struct SpiPayload<SPI, REMAP, PINS> {
338+
spi: Spi<SPI, REMAP, PINS>
241339
}
242340

243-
pub type SpiTxDma<SPI, PINS, CHANNEL> = TxDma<SpiPayload<SPI, PINS>, CHANNEL>;
341+
pub type SpiTxDma<SPI, REMAP, PINS, CHANNEL> = TxDma<SpiPayload<SPI, REMAP, PINS>, CHANNEL>;
244342

245343
macro_rules! spi_dma {
246344
($SPIi:ident, $TCi:ident) => {
247-
impl<PINS> Transmit for SpiTxDma<$SPIi, PINS, $TCi> {
345+
impl<REMAP, PINS> Transmit for SpiTxDma<$SPIi, REMAP, PINS, $TCi> {
248346
type TxChannel = $TCi;
249347
type ReceivedWord = u8;
250348
}
251349

252-
impl<PINS> Spi<$SPIi, PINS> {
253-
pub fn with_tx_dma(self, channel: $TCi) -> SpiTxDma<$SPIi, PINS, $TCi> {
350+
impl<REMAP, PINS> Spi<$SPIi, REMAP, PINS> {
351+
pub fn with_tx_dma(self, channel: $TCi) -> SpiTxDma<$SPIi, REMAP, PINS, $TCi> {
254352
let payload = SpiPayload{
255353
spi: self
256354
};
257355
SpiTxDma {payload, channel}
258356
}
259357
}
260358

261-
impl<PINS> TransferPayload for SpiTxDma<$SPIi, PINS, $TCi> {
359+
impl<REMAP, PINS> TransferPayload for SpiTxDma<$SPIi, REMAP, PINS, $TCi> {
262360
fn start(&mut self) {
263361
self.payload.spi.spi.cr2.modify(|_, w| w.txdmaen().set_bit());
264362
self.channel.start();
@@ -269,7 +367,7 @@ macro_rules! spi_dma {
269367
}
270368
}
271369

272-
impl<A, B, PIN> crate::dma::WriteDma<A, B, u8> for SpiTxDma<$SPIi, PIN, $TCi>
370+
impl<A, B, REMAP, PIN> crate::dma::WriteDma<A, B, u8> for SpiTxDma<$SPIi, REMAP, PIN, $TCi>
273371
where
274372
A: AsSlice<Element=u8>,
275373
B: Static<A>

0 commit comments

Comments
 (0)