Skip to content

Commit 482def3

Browse files
committed
Implement spi config struct
1 parent 24fccac commit 482def3

File tree

7 files changed

+149
-35
lines changed

7 files changed

+149
-35
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
142142
- Rework SPI implementation: ([#273])
143143
- A generic `Instance` trait now represents all Spi peripherals.
144144
- `Spi::spi1` and so on are renamed to `Spi::new`.
145+
- Add SPI configuration type to be passed into `Spi::new`
145146

146147
## [v0.7.0] - 2021-06-18
147148

examples/spi.rs

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use cortex_m_rt::entry;
1212

1313
use hal::pac;
1414
use hal::prelude::*;
15-
use hal::spi::{Mode, Phase, Polarity, Spi};
15+
use hal::spi::Spi;
1616

1717
#[entry]
1818
fn main() -> ! {
@@ -40,19 +40,7 @@ fn main() -> ! {
4040
.pc12
4141
.into_af6_push_pull(&mut gpioc.moder, &mut gpioc.otyper, &mut gpioc.afrh);
4242

43-
let spi_mode = Mode {
44-
polarity: Polarity::IdleLow,
45-
phase: Phase::CaptureOnFirstTransition,
46-
};
47-
48-
let mut spi = Spi::new(
49-
dp.SPI3,
50-
(sck, miso, mosi),
51-
spi_mode,
52-
3_000_000.Hz(),
53-
clocks,
54-
&mut rcc.apb1,
55-
);
43+
let mut spi = Spi::new(dp.SPI3, (sck, miso, mosi), 3.MHz(), clocks, &mut rcc.apb1);
5644

5745
// Create an `u8` array, which can be transfered via SPI.
5846
let msg_send: [u8; 8] = [0xD, 0xE, 0xA, 0xD, 0xB, 0xE, 0xE, 0xF];

src/serial.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,7 @@ where
470470
Rx: RxPin<Usart>,
471471
Config: Into<config::Config>,
472472
{
473-
use self::config::*;
473+
use config::*;
474474

475475
let config = config.into();
476476

src/serial/config.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ pub enum Parity {
5858
}
5959

6060
/// Configuration struct for [`Serial`](super::Serial) providing all
61-
/// communication-related / parameters. `Serial` always uses eight data
61+
/// communication-related / parameters. [`Serial`](super::Serial) always uses eight data
6262
/// bits plus the parity bit - if selected.
6363
///
6464
/// Create a configuration by using `default` in combination with the

src/spi.rs

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use crate::pac::{
2222
use crate::{
2323
gpio::{self, PushPull, AF5, AF6},
2424
rcc::{self, Clocks},
25-
time::{fixed_point::FixedPoint, rate::Hertz},
25+
time::rate::{self, Hertz},
2626
};
2727

2828
/// SPI error
@@ -177,14 +177,30 @@ pub struct Spi<SPI, Pins, Word = u8> {
177177
_word: PhantomData<Word>,
178178
}
179179

180+
pub mod config;
181+
180182
impl<SPI, Sck, Miso, Mosi, WORD> Spi<SPI, (Sck, Miso, Mosi), WORD> {
181-
/// Configures the SPI peripheral to operate in full duplex master mode
183+
/// Configures the SPI peripheral to operate in full duplex master mode.
184+
///
185+
/// The most convinient way to get a device is like that:
186+
///
187+
/// ```ignore
188+
/// use stm32f3xx_hal::prelude::*;
189+
/// use stm32f3xx_hal::spi::Spi;
190+
///
191+
/// // ...
192+
///
193+
/// let spi = Spi::new(dp.SPI1, (sck_pin, mosi_pin, miso_pin), 1.MHz, clocks, &mut dp.abp1);
194+
///
195+
/// ```
196+
///
197+
/// To get a better example, look [here](https://github.com/stm32-rs/stm32f3xx-hal/blob/v0.7.0/examples/spi.rs).
198+
///
182199
// TODO(Sh3Rm4n): See alternative modes provided besides FullDuplex (as listed in Stm32CubeMx).
183-
pub fn new(
200+
pub fn new<Config>(
184201
spi: SPI,
185202
pins: (Sck, Miso, Mosi),
186-
mode: Mode,
187-
freq: Hertz,
203+
config: Config,
188204
clocks: Clocks,
189205
apb: &mut <SPI as Instance>::APB,
190206
) -> Self
@@ -194,7 +210,9 @@ impl<SPI, Sck, Miso, Mosi, WORD> Spi<SPI, (Sck, Miso, Mosi), WORD> {
194210
Miso: MisoPin<SPI>,
195211
Mosi: MosiPin<SPI>,
196212
WORD: Word,
213+
Config: Into<config::Config>,
197214
{
215+
let config = config.into();
198216
SPI::enable_clock(apb);
199217

200218
let (frxth, ds) = WORD::register_config();
@@ -218,17 +236,18 @@ impl<SPI, Sck, Miso, Mosi, WORD> Spi<SPI, (Sck, Miso, Mosi), WORD> {
218236
spi.cr1.write(|w| {
219237
w.mstr().master();
220238

221-
match mode.phase {
239+
match config.mode.phase {
222240
Phase::CaptureOnFirstTransition => w.cpha().first_edge(),
223241
Phase::CaptureOnSecondTransition => w.cpha().second_edge(),
224242
};
225243

226-
match mode.polarity {
244+
match config.mode.polarity {
227245
Polarity::IdleLow => w.cpol().idle_low(),
228246
Polarity::IdleHigh => w.cpol().idle_high(),
229247
};
230248

231-
w.br().variant(Self::compute_baud_rate(clocks, freq));
249+
w.br()
250+
.variant(Self::compute_baud_rate(clocks, config.frequency));
232251

233252
w.spe()
234253
.enabled()
@@ -262,18 +281,18 @@ where
262281
SPI: Instance,
263282
{
264283
/// Change the baud rate of the SPI
265-
pub fn reclock(&mut self, freq: Hertz, clocks: Clocks) {
284+
pub fn reclock(&mut self, freq: impl Into<rate::Generic<u32>>, clocks: Clocks) {
266285
self.spi.cr1.modify(|_, w| w.spe().disabled());
267286

268287
self.spi.cr1.modify(|_, w| {
269-
w.br().variant(Self::compute_baud_rate(clocks, freq));
288+
w.br().variant(Self::compute_baud_rate(clocks, freq.into()));
270289
w.spe().enabled()
271290
});
272291
}
273292

274-
fn compute_baud_rate(clocks: Clocks, freq: Hertz) -> spi1::cr1::BR_A {
293+
fn compute_baud_rate(clocks: Clocks, freq: rate::Generic<u32>) -> spi1::cr1::BR_A {
275294
use spi1::cr1::BR_A;
276-
match SPI::clock(&clocks).0 / freq.integer() {
295+
match SPI::clock(&clocks).0 / (freq.integer() * *freq.scaling_factor()) {
277296
0 => crate::unreachable!(),
278297
1..=2 => BR_A::DIV2,
279298
3..=5 => BR_A::DIV4,

src/spi/config.rs

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
//! Types for configuring a spi interface.
2+
3+
use crate::time::rate::{self, Extensions};
4+
use core::fmt;
5+
6+
use crate::hal::spi::{self, Mode};
7+
8+
/// Configuration struct for [`Spi`](super::Spi) providing all
9+
/// communication-related / parameters.
10+
///
11+
/// The default configruation can be obtain by:
12+
///
13+
/// ```
14+
/// # use stm32f3xx_hal::spi::config::Config;
15+
/// let config = Config::default();
16+
/// ````
17+
///
18+
/// [`Spi`](super::Spi) defaults to [`spi::MODE_0`] and a frequency of 1 MHz.
19+
///
20+
/// ```
21+
/// # use stm32f3xx_hal::spi::config::Config;
22+
/// let config = Config::default();
23+
/// ```
24+
///
25+
/// Create a configuration by using `default` in combination with the
26+
/// builder methods. The following snippet shows creating a configuration
27+
/// for 19,200 Baud, 8N1 by deriving it from the default value:
28+
/// ```
29+
/// # use stm32f3xx_hal::serial::config::*;
30+
/// # use stm32f3xx_hal::time::rate::{Baud, Extensions};
31+
/// let config = Config::default().baudrate(19_200.Bd());
32+
///
33+
/// assert!(config.baudrate == 19_200.Bd());
34+
/// assert!(config.parity == Parity::None);
35+
/// assert!(config.stopbits == StopBits::STOP1);
36+
/// ```
37+
#[derive(Clone, Copy, PartialEq)]
38+
#[non_exhaustive]
39+
pub struct Config {
40+
/// Operating frequency of the SPI peripheral.
41+
pub frequency: rate::Generic<u32>,
42+
/// Operation Mode as defined by the [`embedded-hal`]
43+
pub mode: Mode,
44+
}
45+
46+
impl fmt::Debug for Config {
47+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48+
let mode = if self.mode == spi::MODE_0 {
49+
0
50+
} else if self.mode == spi::MODE_1 {
51+
1
52+
} else if self.mode == spi::MODE_2 {
53+
2
54+
} else {
55+
3
56+
};
57+
58+
f.debug_struct("Config")
59+
.field("frequency", &format_args!("{:?}", self.frequency))
60+
.field("mode", &format_args!("MODE_{}", mode))
61+
.finish()
62+
}
63+
}
64+
65+
#[cfg(feature = "defmt")]
66+
impl defmt::Format for Config {
67+
fn format(&self, f: defmt::Formatter) {
68+
let mode = if self.mode == spi::MODE_0 {
69+
0
70+
} else if self.mode == spi::MODE_1 {
71+
1
72+
} else if self.mode == spi::MODE_2 {
73+
2
74+
} else {
75+
3
76+
};
77+
78+
defmt::write!(
79+
f,
80+
"Config {{ frequency: {} Hz, mode: MODE_{}}}",
81+
self.frequency.integer() * *self.frequency.scaling_factor(),
82+
mode,
83+
);
84+
}
85+
}
86+
87+
impl Default for Config {
88+
fn default() -> Self {
89+
Self {
90+
frequency: 1.MHz().into(),
91+
mode: spi::MODE_0,
92+
}
93+
}
94+
}
95+
96+
impl<T: Into<rate::Generic<u32>>> From<T> for Config {
97+
fn from(f: T) -> Config {
98+
Config {
99+
frequency: f.into(),
100+
..Default::default()
101+
}
102+
}
103+
}

testsuite/tests/spi.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,16 @@
44
use hal::rcc::{Clocks, APB1};
55
use testsuite as _;
66

7-
use core::convert::TryInto;
8-
97
use stm32f3xx_hal as hal;
108

119
use hal::prelude::*;
1210

1311
use hal::gpio::{PushPull, AF6};
1412
use hal::gpio::{PC10, PC11, PC12};
15-
use hal::hal::spi::MODE_0;
1613
use hal::pac;
1714
use hal::pac::SPI3;
1815
use hal::spi::Spi;
16+
use hal::time::rate::{self, Extensions};
1917

2018
const TEST_MSG: [u8; 8] = [0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xaa, 0xbb];
2119

@@ -65,8 +63,7 @@ mod tests {
6563
let spi = Spi::new(
6664
dp.SPI3,
6765
(spi_pins.0, spi_pins.1, spi_pins.2),
68-
MODE_0,
69-
10.MHz().try_into().unwrap(),
66+
10.MHz(),
7067
clocks,
7168
&mut rcc.apb1,
7269
);
@@ -80,10 +77,16 @@ mod tests {
8077

8178
#[test]
8279
fn test_transfer(state: &mut super::State) {
83-
for freq in [100.Hz(), 100_000.Hz(), 10_000_000.Hz(), 32_000_000.Hz()] {
80+
let rates: [rate::Generic<u32>; 4] = [
81+
100.Hz().into(),
82+
100.kHz().into(),
83+
10.MHz().into(),
84+
32.MHz().into(),
85+
];
86+
for freq in rates {
8487
let (spi, pins) = unwrap!(state.spi.take()).free();
8588

86-
let mut spi = Spi::new(spi, pins, MODE_0, freq, state.clocks, &mut state.apb1);
89+
let mut spi = Spi::new(spi, pins, freq, state.clocks, &mut state.apb1);
8790
let mut transfer_buffer = TEST_MSG;
8891

8992
unwrap!(spi.transfer(&mut transfer_buffer));

0 commit comments

Comments
 (0)