Skip to content

Commit 86fb3c3

Browse files
authored
Merge pull request #239 from sirhcel/serial-config-struct-on-uart-refactor
Add config struct for Serial
2 parents 2da75a7 + 45aef74 commit 86fb3c3

File tree

5 files changed

+284
-33
lines changed

5 files changed

+284
-33
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
2020
### Breaking Changes
2121

2222
- Refactor CAN to use the [`bxCan`](https://github.com/stm32-rs/bxcan) crate. ([#207])
23+
- Add support for configuring parity and stop bits in addition to baud rate for `Serial` with
24+
`serial::config::Config`. ([#239])
2325
- Implement `Serial::join` which allows to re-create the serial peripheral,
2426
when `Serial::split` was previously called. ([#252])
2527

@@ -350,6 +352,7 @@ let clocks = rcc
350352
[#252]: https://github.com/stm32-rs/stm32f3xx-hal/pull/252
351353
[#247]: https://github.com/stm32-rs/stm32f3xx-hal/pull/247
352354
[#246]: https://github.com/stm32-rs/stm32f3xx-hal/pull/246
355+
[#239]: https://github.com/stm32-rs/stm32f3xx-hal/pull/239
353356
[#238]: https://github.com/stm32-rs/stm32f3xx-hal/pull/238
354357
[#234]: https://github.com/stm32-rs/stm32f3xx-hal/pull/234
355358
[#232]: https://github.com/stm32-rs/stm32f3xx-hal/pull/232

src/serial.rs

Lines changed: 129 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,12 @@ use core::{convert::Infallible, ops::Deref};
1212
use crate::{
1313
gpio::{gpioa, gpiob, gpioc, AF7},
1414
hal::{blocking, serial},
15-
pac::{self, rcc::cfgr3::USART1SW_A, usart1::RegisterBlock, USART1, USART2, USART3},
15+
pac::{
16+
self,
17+
rcc::cfgr3::USART1SW_A,
18+
usart1::{cr1::M_A, cr1::PCE_A, cr1::PS_A, RegisterBlock},
19+
USART1, USART2, USART3,
20+
},
1621
rcc::{Clocks, APB1, APB2},
1722
time::rate::*,
1823
};
@@ -111,6 +116,100 @@ cfg_if! {
111116
}
112117
}
113118

119+
/// Types for configuring a serial interface.
120+
pub mod config {
121+
use crate::time::rate::{Baud, Extensions};
122+
123+
// Reexport stop bit enum from PAC. In case there is a breaking change,
124+
// provide a compatible enum from this HAL.
125+
pub use crate::pac::usart1::cr2::STOP_A as StopBits;
126+
127+
/// Parity generation and checking. If odd or even parity is selected, the
128+
/// underlying USART will be configured to send/receive the parity bit in
129+
/// addtion to the data bits.
130+
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
131+
#[derive(Clone, Copy, PartialEq)]
132+
pub enum Parity {
133+
/// No parity bit will be added/checked.
134+
None,
135+
/// The MSB transmitted/received will be generated/checked to have a
136+
/// even number of bits set.
137+
Even,
138+
/// The MSB transmitted/received will be generated/checked to have a
139+
/// odd number of bits set.
140+
Odd,
141+
}
142+
143+
/// Configuration struct for [`Serial`](super::Serial) providing all
144+
/// communication-related / parameters. `Serial` always uses eight data
145+
/// bits plus the parity bit - if selected.
146+
///
147+
/// Create a configuration by using `default` in combination with the
148+
/// builder methods. The following snippet shows creating a configuration
149+
/// for 19,200 Baud, 8N1 by deriving it from the default value:
150+
/// ```
151+
/// # use stm32f3xx_hal::serial::config::*;
152+
/// # use stm32f3xx_hal::time::rate::{Baud, Extensions};
153+
/// let config = Config::default().baudrate(19_200.Bd());
154+
///
155+
/// assert!(config.baudrate == 19_200.Bd());
156+
/// assert!(config.parity == Parity::None);
157+
/// assert!(config.stopbits == StopBits::STOP1);
158+
/// ```
159+
#[derive(Clone, Copy, PartialEq)]
160+
#[non_exhaustive]
161+
pub struct Config {
162+
/// Serial interface baud rate
163+
pub baudrate: Baud,
164+
/// Whether and how to generate/check a parity bit
165+
pub parity: Parity,
166+
/// The number of stop bits to follow the last data bit or the parity
167+
/// bit
168+
pub stopbits: StopBits,
169+
}
170+
171+
impl Config {
172+
/// Sets the given baudrate.
173+
pub fn baudrate(mut self, baudrate: impl Into<Baud>) -> Self {
174+
self.baudrate = baudrate.into();
175+
self
176+
}
177+
178+
/// Sets the given parity.
179+
pub fn parity(mut self, parity: Parity) -> Self {
180+
self.parity = parity;
181+
self
182+
}
183+
184+
/// Sets the stop bits to `stopbits`.
185+
pub fn stopbits(mut self, stopbits: StopBits) -> Self {
186+
self.stopbits = stopbits;
187+
self
188+
}
189+
}
190+
191+
impl Default for Config {
192+
/// Creates a new configuration with typically used parameters: 115,200
193+
/// Baud 8N1.
194+
fn default() -> Config {
195+
Config {
196+
baudrate: 115_200.Bd(),
197+
parity: Parity::None,
198+
stopbits: StopBits::STOP1,
199+
}
200+
}
201+
}
202+
203+
impl<T: Into<Baud>> From<T> for Config {
204+
fn from(b: T) -> Config {
205+
Config {
206+
baudrate: b.into(),
207+
..Default::default()
208+
}
209+
}
210+
}
211+
}
212+
114213
/// Serial abstraction
115214
pub struct Serial<Usart, Pins> {
116215
usart: Usart,
@@ -211,30 +310,55 @@ where
211310
Usart: Instance,
212311
{
213312
/// Configures a USART peripheral to provide serial communication
214-
pub fn new(
313+
pub fn new<Config>(
215314
usart: Usart,
216315
pins: (Tx, Rx),
217-
baud_rate: Baud,
316+
config: Config,
218317
clocks: Clocks,
219318
apb: &mut <Usart as Instance>::APB,
220319
) -> Self
221320
where
222321
Usart: Instance,
223322
Tx: TxPin<Usart>,
224323
Rx: RxPin<Usart>,
324+
Config: Into<config::Config>,
225325
{
326+
use self::config::*;
327+
328+
let config = config.into();
329+
330+
// Enable USART peripheral for any further interaction.
226331
Usart::enable_clock(apb);
332+
// Disable USART because some configuration bits could only be written
333+
// in this state.
334+
usart.cr1.modify(|_, w| w.ue().disabled());
227335

228-
let brr = Usart::clock(&clocks).integer() / baud_rate.integer();
336+
let brr = Usart::clock(&clocks).integer() / config.baudrate.integer();
229337
crate::assert!(brr >= 16, "impossible baud rate");
230338
usart.brr.write(|w| w.brr().bits(brr as u16));
231339

340+
// We currently support only eight data bits as supporting a full-blown
341+
// configuration gets complicated pretty fast. The USART counts data
342+
// and partiy bits together so the actual amount depends on the parity
343+
// selection.
344+
let (m0, ps, pce) = match config.parity {
345+
Parity::None => (M_A::BIT8, PS_A::EVEN, PCE_A::DISABLED),
346+
Parity::Even => (M_A::BIT9, PS_A::EVEN, PCE_A::ENABLED),
347+
Parity::Odd => (M_A::BIT9, PS_A::ODD, PCE_A::ENABLED),
348+
};
349+
350+
usart.cr2.modify(|_, w| w.stop().variant(config.stopbits));
232351
usart.cr1.modify(|_, w| {
233-
w.ue().enabled(); // enable USART
352+
w.ps().variant(ps); // set parity mode
353+
w.pce().variant(pce); // enable parity checking/generation
354+
w.m().variant(m0); // set data bits
234355
w.re().enabled(); // enable receiver
235356
w.te().enabled() // enable transmitter
236357
});
237358

359+
// Finally enable the configured UART.
360+
usart.cr1.modify(|_, w| w.ue().enabled());
361+
238362
Self { usart, pins }
239363
}
240364

testsuite/tests/adc.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,12 @@ mod tests {
6969
for _ in 0..10 {
7070
defmt::unwrap!(state.output.set_high());
7171
let adc_level: u16 = defmt::unwrap!(adc.read(&mut state.analog).ok());
72-
defmt::info!("{}", adc_level);
72+
defmt::debug!("{}", adc_level);
7373
defmt::unwrap!(state.output.set_low());
7474
// Vref is 3V so output should reach the maximum.
7575
assert!(adc_level >= 3900 && adc_level <= 4100);
7676
let adc_level: u16 = defmt::unwrap!(adc.read(&mut state.analog).ok());
77-
defmt::info!("{}", adc_level);
77+
defmt::debug!("{}", adc_level);
7878
// nearly zero (always zero can not be guaranteed)
7979
assert!(adc_level <= 100);
8080
}

0 commit comments

Comments
 (0)