Skip to content

Commit fead2eb

Browse files
authored
Support 16 bit SPI (#107)
Add support for 16-bit SPI words
1 parent 4259e42 commit fead2eb

File tree

2 files changed

+47
-22
lines changed

2 files changed

+47
-22
lines changed

CHANGELOG.md

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

1010
### Added
11+
12+
- Support for 16-bit words with SPI ([#107](https://github.com/stm32-rs/stm32f3xx-hal/pull/107))
1113
- SPI support for reclock after initialization ([#98](https://github.com/stm32-rs/stm32f3xx-hal/pull/98))
1214

1315
## [v0.5.0] - 2020-07-21

src/spi.rs

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ use core::ptr;
44

55
use crate::hal::spi::FullDuplex;
66
pub use crate::hal::spi::{Mode, Phase, Polarity};
7-
use crate::pac::{SPI1, SPI2, SPI3};
7+
use crate::pac::{
8+
spi1::cr2::{DS_A, FRXTH_A},
9+
SPI1, SPI2, SPI3,
10+
};
811
use crate::stm32::spi1;
912

1013
use crate::gpio::gpioa::{PA5, PA6, PA7};
@@ -47,6 +50,7 @@ use crate::rcc::APB1;
4750
))]
4851
use crate::rcc::APB2;
4952
use crate::time::Hertz;
53+
use core::marker::PhantomData;
5054

5155
/// SPI error
5256
#[derive(Debug)]
@@ -104,16 +108,33 @@ unsafe impl MosiPin<SPI2> for PB15<AF5> {}
104108
unsafe impl MosiPin<SPI3> for PB5<AF6> {}
105109
unsafe impl MosiPin<SPI3> for PC12<AF6> {}
106110

111+
pub trait Word {
112+
fn register_config() -> (FRXTH_A, DS_A);
113+
}
114+
115+
impl Word for u8 {
116+
fn register_config() -> (FRXTH_A, DS_A) {
117+
(FRXTH_A::QUARTER, DS_A::EIGHTBIT)
118+
}
119+
}
120+
121+
impl Word for u16 {
122+
fn register_config() -> (FRXTH_A, DS_A) {
123+
(FRXTH_A::HALF, DS_A::SIXTEENBIT)
124+
}
125+
}
126+
107127
/// SPI peripheral operating in full duplex master mode
108-
pub struct Spi<SPI, PINS> {
128+
pub struct Spi<SPI, PINS, WORD = u8> {
109129
spi: SPI,
110130
pins: PINS,
131+
_word: PhantomData<WORD>,
111132
}
112133

113134
macro_rules! hal {
114135
($($SPIX:ident: ($spiX:ident, $APBX:ident, $spiXen:ident, $spiXrst:ident, $pclkX:ident),)+) => {
115136
$(
116-
impl<SCK, MISO, MOSI> Spi<$SPIX, (SCK, MISO, MOSI)> {
137+
impl<SCK, MISO, MOSI, WORD> Spi<$SPIX, (SCK, MISO, MOSI), WORD> {
117138
/// Configures the SPI peripheral to operate in full duplex master mode
118139
pub fn $spiX<F>(
119140
spi: $SPIX,
@@ -128,17 +149,20 @@ macro_rules! hal {
128149
SCK: SckPin<$SPIX>,
129150
MISO: MisoPin<$SPIX>,
130151
MOSI: MosiPin<$SPIX>,
152+
WORD: Word,
131153
{
132154
// enable or reset $SPIX
133155
apb2.enr().modify(|_, w| w.$spiXen().enabled());
134156
apb2.rstr().modify(|_, w| w.$spiXrst().reset());
135157
apb2.rstr().modify(|_, w| w.$spiXrst().clear_bit());
136158

137-
// FRXTH: RXNE event is generated if the FIFO level is greater than or equal to
138-
// 8-bit
139-
// DS: 8-bit data size
140-
// SSOE: Slave Select output disabled
141-
spi.cr2.write(|w| w.frxth().quarter().ds().eight_bit().ssoe().disabled());
159+
let (frxth, ds) = WORD::register_config();
160+
spi.cr2.write(|w| {
161+
w.frxth().variant(frxth);
162+
w.ds().variant(ds);
163+
// Slave Select output disabled
164+
w.ssoe().disabled()
165+
});
142166

143167
// CPHA: phase
144168
// CPOL: polarity
@@ -179,7 +203,7 @@ macro_rules! hal {
179203
.unidirectional()
180204
});
181205

182-
Spi { spi, pins }
206+
Spi { spi, pins, _word: PhantomData }
183207
}
184208

185209
/// Releases the SPI peripheral and associated pins
@@ -216,10 +240,10 @@ macro_rules! hal {
216240

217241
}
218242

219-
impl<PINS> FullDuplex<u8> for Spi<$SPIX, PINS> {
243+
impl<PINS, WORD> FullDuplex<WORD> for Spi<$SPIX, PINS, WORD> {
220244
type Error = Error;
221245

222-
fn read(&mut self) -> nb::Result<u8, Error> {
246+
fn read(&mut self) -> nb::Result<WORD, Error> {
223247
let sr = self.spi.sr.read();
224248

225249
Err(if sr.ovr().is_overrun() {
@@ -229,17 +253,16 @@ macro_rules! hal {
229253
} else if sr.crcerr().is_no_match() {
230254
nb::Error::Other(Error::Crc)
231255
} else if sr.rxne().is_not_empty() {
232-
// NOTE(read_volatile) read only 1 byte (the svd2rust API only allows
233-
// reading a half-word)
234-
return Ok(unsafe {
235-
ptr::read_volatile(&self.spi.dr as *const _ as *const u8)
236-
});
256+
let read_ptr = &self.spi.dr as *const _ as *const WORD;
257+
// NOTE(unsafe) read from register owned by this Spi struct
258+
let value = unsafe { ptr::read_volatile(read_ptr) };
259+
return Ok(value);
237260
} else {
238261
nb::Error::WouldBlock
239262
})
240263
}
241264

242-
fn send(&mut self, byte: u8) -> nb::Result<(), Error> {
265+
fn send(&mut self, word: WORD) -> nb::Result<(), Error> {
243266
let sr = self.spi.sr.read();
244267

245268
Err(if sr.ovr().is_overrun() {
@@ -249,18 +272,18 @@ macro_rules! hal {
249272
} else if sr.crcerr().is_no_match() {
250273
nb::Error::Other(Error::Crc)
251274
} else if sr.txe().is_empty() {
252-
// NOTE(write_volatile) see note above
253-
unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, byte) }
275+
let write_ptr = &self.spi.dr as *const _ as *mut WORD;
276+
// NOTE(unsafe) write to register owned by this Spi struct
277+
unsafe { ptr::write_volatile(write_ptr, word) };
254278
return Ok(());
255279
} else {
256280
nb::Error::WouldBlock
257281
})
258282
}
259283
}
260284

261-
impl<PINS> crate::hal::blocking::spi::transfer::Default<u8> for Spi<$SPIX, PINS> {}
262-
263-
impl<PINS> crate::hal::blocking::spi::write::Default<u8> for Spi<$SPIX, PINS> {}
285+
impl<PINS, WORD> crate::hal::blocking::spi::transfer::Default<WORD> for Spi<$SPIX, PINS, WORD> {}
286+
impl<PINS, WORD> crate::hal::blocking::spi::write::Default<WORD> for Spi<$SPIX, PINS, WORD> {}
264287
)+
265288
}
266289
}

0 commit comments

Comments
 (0)