Skip to content

Commit 3859f52

Browse files
author
jonnyando
authored
Spi with 16bit framesize (#258)
* separated 8 and 16b dataframe operation * added conversion from 16b to 8b spi dataframe * added SpiReadWrite trait to reduce duplicate code * updated CHANGELOG.md
1 parent d976ba2 commit 3859f52

File tree

2 files changed

+155
-63
lines changed

2 files changed

+155
-63
lines changed

CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
99

1010
### Breaking changes
1111

12-
MonoTimer now takes ownership of the DCB register
12+
- MonoTimer now takes ownership of the DCB register
13+
- SPI objects now have a `FrameSize` type field
14+
15+
### Added
16+
17+
- Add 16 bit dataframe size for `SPI`
1318

1419
### Fixed
1520

src/spi.rs

Lines changed: 149 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,11 @@ pins_impl!(
109109
(MISO, SCK, MOSI), (Miso, Sck, Mosi), (_Miso, _Sck, _Mosi);
110110
);
111111

112-
pub struct Spi<SPI, REMAP, PINS> {
112+
pub struct Spi<SPI, REMAP, PINS, FRAMESIZE> {
113113
spi: SPI,
114114
pins: PINS,
115115
_remap: PhantomData<REMAP>,
116+
_framesize: PhantomData<FRAMESIZE>,
116117
}
117118

118119
/// A filler type for when the SCK pin is unnecessary
@@ -147,9 +148,9 @@ remap!(Spi3NoRemap, SPI3, false, PB3, PB4, PB5);
147148
#[cfg(feature = "connectivity")]
148149
remap!(Spi3Remap, SPI3, true, PC10, PC11, PC12);
149150

150-
impl<REMAP, PINS> Spi<SPI1, REMAP, PINS> {
151+
impl<REMAP, PINS> Spi<SPI1, REMAP, PINS, u8> {
151152
/**
152-
Constructs an SPI instance using SPI1.
153+
Constructs an SPI instance using SPI1 in 8bit dataframe mode.
153154
154155
The pin parameter tuple (sck, miso, mosi) should be `(PA5, PA6, PA7)` or `(PB3, PB4, PB5)` configured as `(Alternate<PushPull>, Input<Floating>, Alternate<PushPull>)`.
155156
@@ -170,13 +171,13 @@ impl<REMAP, PINS> Spi<SPI1, REMAP, PINS> {
170171
PINS: Pins<REMAP, POS>,
171172
{
172173
mapr.modify_mapr(|_, w| w.spi1_remap().bit(REMAP::REMAP));
173-
Spi::<SPI1, _, _>::_spi(spi, pins, mode, freq.into(), clocks, apb)
174+
Spi::<SPI1, _, _, u8>::_spi(spi, pins, mode, freq.into(), clocks, apb)
174175
}
175176
}
176177

177-
impl<REMAP, PINS> Spi<SPI2, REMAP, PINS> {
178+
impl<REMAP, PINS> Spi<SPI2, REMAP, PINS, u8> {
178179
/**
179-
Constructs an SPI instance using SPI2.
180+
Constructs an SPI instance using SPI2 in 8bit dataframe mode.
180181
181182
The pin parameter tuple (sck, miso, mosi) should be `(PB13, PB14, PB15)` configured as `(Alternate<PushPull>, Input<Floating>, Alternate<PushPull>)`.
182183
@@ -195,14 +196,14 @@ impl<REMAP, PINS> Spi<SPI2, REMAP, PINS> {
195196
REMAP: Remap<Periph = SPI2>,
196197
PINS: Pins<REMAP, POS>,
197198
{
198-
Spi::<SPI2, _, _>::_spi(spi, pins, mode, freq.into(), clocks, apb)
199+
Spi::<SPI2, _, _, u8>::_spi(spi, pins, mode, freq.into(), clocks, apb)
199200
}
200201
}
201202

202203
#[cfg(any(feature = "high", feature = "connectivity"))]
203-
impl<REMAP, PINS> Spi<SPI3, REMAP, PINS> {
204+
impl<REMAP, PINS> Spi<SPI3, REMAP, PINS, u8> {
204205
/**
205-
Constructs an SPI instance using SPI3.
206+
Constructs an SPI instance using SPI3 in 8bit dataframe mode.
206207
207208
The pin parameter tuple (sck, miso, mosi) should be `(PB3, PB4, PB5)` or `(PC10, PC11, PC12)` configured as `(Alternate<PushPull>, Input<Floating>, Alternate<PushPull>)`.
208209
@@ -221,13 +222,94 @@ impl<REMAP, PINS> Spi<SPI3, REMAP, PINS> {
221222
REMAP: Remap<Periph = SPI3>,
222223
PINS: Pins<REMAP, POS>,
223224
{
224-
Spi::<SPI3, _, _>::_spi(spi, pins, mode, freq.into(), clocks, apb)
225+
Spi::<SPI3, _, _, u8>::_spi(spi, pins, mode, freq.into(), clocks, apb)
225226
}
226227
}
227228

228229
pub type SpiRegisterBlock = crate::pac::spi1::RegisterBlock;
229230

230-
impl<SPI, REMAP, PINS> Spi<SPI, REMAP, PINS>
231+
pub trait SpiReadWrite<T> {
232+
fn read_data_reg(&mut self) -> T;
233+
fn write_data_reg(&mut self, data: T);
234+
fn spi_write(&mut self, words: &[T]) -> Result<(), Error>;
235+
}
236+
237+
impl<SPI, REMAP, PINS, FrameSize> SpiReadWrite<FrameSize> for Spi<SPI, REMAP, PINS, FrameSize>
238+
where
239+
SPI: Deref<Target = SpiRegisterBlock>,
240+
FrameSize: Copy,
241+
{
242+
fn read_data_reg(&mut self) -> FrameSize {
243+
// NOTE(read_volatile) read only 1 byte (the svd2rust API only allows
244+
// reading a half-word)
245+
return unsafe { ptr::read_volatile(&self.spi.dr as *const _ as *const FrameSize) };
246+
}
247+
248+
fn write_data_reg(&mut self, data: FrameSize) {
249+
// NOTE(write_volatile) see note above
250+
unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut FrameSize, data) }
251+
}
252+
253+
// Implement write as per the "Transmit only procedure" page 712
254+
// of RM0008 Rev 20. This is more than twice as fast as the
255+
// default Write<> implementation (which reads and drops each
256+
// received value)
257+
fn spi_write(&mut self, words: &[FrameSize]) -> Result<(), Error> {
258+
// Write each word when the tx buffer is empty
259+
for word in words {
260+
loop {
261+
let sr = self.spi.sr.read();
262+
if sr.txe().bit_is_set() {
263+
// NOTE(write_volatile) see note above
264+
// unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, *word) }
265+
self.write_data_reg(*word);
266+
if sr.modf().bit_is_set() {
267+
return Err(Error::ModeFault);
268+
}
269+
break;
270+
}
271+
}
272+
}
273+
// Wait for final TXE
274+
loop {
275+
let sr = self.spi.sr.read();
276+
if sr.txe().bit_is_set() {
277+
break;
278+
}
279+
}
280+
// Wait for final !BSY
281+
loop {
282+
let sr = self.spi.sr.read();
283+
if !sr.bsy().bit_is_set() {
284+
break;
285+
}
286+
}
287+
// Clear OVR set due to dropped received values
288+
// NOTE(read_volatile) see note above
289+
// unsafe {
290+
// let _ = ptr::read_volatile(&self.spi.dr as *const _ as *const u8);
291+
// }
292+
let _ = self.read_data_reg();
293+
let _ = self.spi.sr.read();
294+
Ok(())
295+
}
296+
}
297+
298+
impl<SPI, REMAP, PINS, FrameSize> Spi<SPI, REMAP, PINS, FrameSize>
299+
where
300+
SPI: Deref<Target = SpiRegisterBlock>,
301+
FrameSize: Copy,
302+
{
303+
#[deprecated(since = "0.6.0", note = "Please use release instead")]
304+
pub fn free(self) -> (SPI, PINS) {
305+
self.release()
306+
}
307+
pub fn release(self) -> (SPI, PINS) {
308+
(self.spi, self.pins)
309+
}
310+
}
311+
312+
impl<SPI, REMAP, PINS> Spi<SPI, REMAP, PINS, u8>
231313
where
232314
SPI: Deref<Target = SpiRegisterBlock> + Enable + Reset,
233315
SPI::Bus: GetBusFreq,
@@ -300,25 +382,50 @@ where
300382
spi,
301383
pins,
302384
_remap: PhantomData,
385+
_framesize: PhantomData,
303386
}
304387
}
305-
306-
#[deprecated(since = "0.6.0", note = "Please use release instead")]
307-
pub fn free(self) -> (SPI, PINS) {
308-
self.release()
388+
/// Converts from 8bit dataframe to 16bit.
389+
pub fn frame_size_16bit(self) -> Spi<SPI, REMAP, PINS, u16> {
390+
self.spi.cr1.modify(|_, w| w.spe().clear_bit());
391+
self.spi.cr1.modify(|_, w| w.dff().set_bit());
392+
self.spi.cr1.modify(|_, w| w.spe().set_bit());
393+
Spi {
394+
spi: self.spi,
395+
pins: self.pins,
396+
_remap: PhantomData,
397+
_framesize: PhantomData,
398+
}
309399
}
310-
pub fn release(self) -> (SPI, PINS) {
311-
(self.spi, self.pins)
400+
}
401+
402+
impl<SPI, REMAP, PINS> Spi<SPI, REMAP, PINS, u16>
403+
where
404+
SPI: Deref<Target = SpiRegisterBlock>,
405+
{
406+
/// Converts from 16bit dataframe to 8bit.
407+
pub fn frame_size_8bit(self) -> Spi<SPI, REMAP, PINS, u8> {
408+
self.spi.cr1.modify(|_, w| w.spe().clear_bit());
409+
self.spi.cr1.modify(|_, w| w.dff().clear_bit());
410+
self.spi.cr1.modify(|_, w| w.spe().set_bit());
411+
Spi {
412+
spi: self.spi,
413+
pins: self.pins,
414+
_remap: PhantomData,
415+
_framesize: PhantomData,
416+
}
312417
}
313418
}
314419

315-
impl<SPI, REMAP, PINS> crate::hal::spi::FullDuplex<u8> for Spi<SPI, REMAP, PINS>
420+
impl<SPI, REMAP, PINS, FrameSize> crate::hal::spi::FullDuplex<FrameSize>
421+
for Spi<SPI, REMAP, PINS, FrameSize>
316422
where
317423
SPI: Deref<Target = SpiRegisterBlock>,
424+
FrameSize: Copy,
318425
{
319426
type Error = Error;
320427

321-
fn read(&mut self) -> nb::Result<u8, Error> {
428+
fn read(&mut self) -> nb::Result<FrameSize, Error> {
322429
let sr = self.spi.sr.read();
323430

324431
Err(if sr.ovr().bit_is_set() {
@@ -330,13 +437,13 @@ where
330437
} else if sr.rxne().bit_is_set() {
331438
// NOTE(read_volatile) read only 1 byte (the svd2rust API only allows
332439
// reading a half-word)
333-
return Ok(unsafe { ptr::read_volatile(&self.spi.dr as *const _ as *const u8) });
440+
return Ok(self.read_data_reg());
334441
} else {
335442
nb::Error::WouldBlock
336443
})
337444
}
338445

339-
fn send(&mut self, byte: u8) -> nb::Result<(), Error> {
446+
fn send(&mut self, data: FrameSize) -> nb::Result<(), Error> {
340447
let sr = self.spi.sr.read();
341448

342449
Err(if sr.ovr().bit_is_set() {
@@ -347,20 +454,23 @@ where
347454
nb::Error::Other(Error::Crc)
348455
} else if sr.txe().bit_is_set() {
349456
// NOTE(write_volatile) see note above
350-
unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, byte) }
457+
self.write_data_reg(data);
351458
return Ok(());
352459
} else {
353460
nb::Error::WouldBlock
354461
})
355462
}
356463
}
357464

358-
impl<SPI, REMAP, PINS> crate::hal::blocking::spi::transfer::Default<u8> for Spi<SPI, REMAP, PINS> where
359-
SPI: Deref<Target = SpiRegisterBlock>
465+
impl<SPI, REMAP, PINS, FrameSize> crate::hal::blocking::spi::transfer::Default<FrameSize>
466+
for Spi<SPI, REMAP, PINS, FrameSize>
467+
where
468+
SPI: Deref<Target = SpiRegisterBlock>,
469+
FrameSize: Copy,
360470
{
361471
}
362472

363-
impl<SPI, REMAP, PINS> crate::hal::blocking::spi::Write<u8> for Spi<SPI, REMAP, PINS>
473+
impl<SPI, REMAP, PINS> crate::hal::blocking::spi::Write<u8> for Spi<SPI, REMAP, PINS, u8>
364474
where
365475
SPI: Deref<Target = SpiRegisterBlock>,
366476
{
@@ -371,48 +481,25 @@ where
371481
// default Write<> implementation (which reads and drops each
372482
// received value)
373483
fn write(&mut self, words: &[u8]) -> Result<(), Error> {
374-
// Write each word when the tx buffer is empty
375-
for word in words {
376-
loop {
377-
let sr = self.spi.sr.read();
378-
if sr.txe().bit_is_set() {
379-
// NOTE(write_volatile) see note above
380-
unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, *word) }
381-
if sr.modf().bit_is_set() {
382-
return Err(Error::ModeFault);
383-
}
384-
break;
385-
}
386-
}
387-
}
388-
// Wait for final TXE
389-
loop {
390-
let sr = self.spi.sr.read();
391-
if sr.txe().bit_is_set() {
392-
break;
393-
}
394-
}
395-
// Wait for final !BSY
396-
loop {
397-
let sr = self.spi.sr.read();
398-
if !sr.bsy().bit_is_set() {
399-
break;
400-
}
401-
}
402-
// Clear OVR set due to dropped received values
403-
// NOTE(read_volatile) see note above
404-
unsafe {
405-
let _ = ptr::read_volatile(&self.spi.dr as *const _ as *const u8);
406-
}
407-
let _ = self.spi.sr.read();
408-
Ok(())
484+
self.spi_write(words)
485+
}
486+
}
487+
488+
impl<SPI, REMAP, PINS> crate::hal::blocking::spi::Write<u16> for Spi<SPI, REMAP, PINS, u16>
489+
where
490+
SPI: Deref<Target = SpiRegisterBlock>,
491+
{
492+
type Error = Error;
493+
494+
fn write(&mut self, words: &[u16]) -> Result<(), Error> {
495+
self.spi_write(words)
409496
}
410497
}
411498

412499
// DMA
413500

414501
pub struct SpiPayload<SPI, REMAP, PINS> {
415-
spi: Spi<SPI, REMAP, PINS>,
502+
spi: Spi<SPI, REMAP, PINS, u8>,
416503
}
417504

418505
pub type SpiTxDma<SPI, REMAP, PINS, CHANNEL> = TxDma<SpiPayload<SPI, REMAP, PINS>, CHANNEL>;
@@ -424,7 +511,7 @@ macro_rules! spi_dma {
424511
type ReceivedWord = u8;
425512
}
426513

427-
impl<REMAP, PINS> Spi<$SPIi, REMAP, PINS> {
514+
impl<REMAP, PINS> Spi<$SPIi, REMAP, PINS, u8> {
428515
pub fn with_tx_dma(self, channel: $TCi) -> SpiTxDma<$SPIi, REMAP, PINS, $TCi> {
429516
let payload = SpiPayload { spi: self };
430517
SpiTxDma { payload, channel }

0 commit comments

Comments
 (0)