Skip to content

Commit 7e90edf

Browse files
committed
Make one struct Serial for USART and UART. Make inner traits with different implementation for USART and UART.
1 parent 258e10d commit 7e90edf

File tree

7 files changed

+702
-672
lines changed

7 files changed

+702
-672
lines changed

CHANGELOG.md

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

88
## [Unreleased]
99

10+
### Changed
11+
12+
- Join `Serial`, `Rx`, `Tx` for `USART` and `UART` again. Make inner traits with different implementation for USART and UART. [#636]
13+
1014
### Fixed
1115

1216
- map `$SpiSlave` into `SpiSlave` struct in `spi!` macro [#635]

src/prelude.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,12 @@ pub use crate::qei::QeiExt as _stm32f4xx_hal_QeiExt;
6969
pub use crate::rcc::RccExt as _stm32f4xx_hal_rcc_RccExt;
7070
#[cfg(all(feature = "device-selected", feature = "rng"))]
7171
pub use crate::rng::RngExt as _stm32f4xx_hal_rng_RngExt;
72+
pub use crate::serial::Listen as _stm32f4xx_hal_serial_Listen;
7273
pub use crate::serial::RxISR as _stm32f4xx_hal_serial_RxISR;
74+
pub use crate::serial::RxListen as _stm32f4xx_hal_serial_RxListen;
7375
pub use crate::serial::SerialExt as _stm32f4xx_hal_serial_SerialExt;
7476
pub use crate::serial::TxISR as _stm32f4xx_hal_serial_TxISR;
77+
pub use crate::serial::TxListen as _stm32f4xx_hal_serial_TxListen;
7578
pub use crate::spi::SpiExt as _stm32f4xx_hal_spi_SpiExt;
7679
pub use crate::syscfg::SysCfgExt as _stm32f4xx_hal_syscfg_SysCfgExt;
7780
pub use crate::time::U32Ext as _stm32f4xx_hal_time_U32Ext;
@@ -82,5 +85,3 @@ pub use crate::timer::PwmExt as _stm32f4xx_hal_timer_PwmExt;
8285
pub use crate::timer::SysMonoTimerExt as _stm32f4xx_hal_timer_SysMonoTimerExt;
8386
pub use crate::timer::SysTimerExt as _stm32f4xx_hal_timer_SysCounterExt;
8487
pub use crate::timer::TimerExt as _stm32f4xx_hal_timer_TimerExt;
85-
#[cfg(feature = "uart4")]
86-
pub use crate::uart::SerialExt as _stm32f4xx_hal_uart_SerialExt;

src/serial.rs

Lines changed: 171 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,14 @@
1414
//! the embedded-hal read and write traits with `u16` as the word type. You can use these
1515
//! implementations for 9-bit words.
1616
17-
use core::fmt;
1817
use core::marker::PhantomData;
19-
use core::ops::Deref;
20-
21-
use crate::rcc;
22-
use nb::block;
2318

2419
mod hal_02;
2520
mod hal_1;
26-
mod uart_impls;
21+
22+
pub(crate) mod uart_impls;
23+
pub use uart_impls::Instance;
24+
use uart_impls::RegisterBlockImpl;
2725

2826
use crate::gpio::{self, PushPull};
2927

@@ -32,8 +30,6 @@ use crate::pac;
3230
use crate::gpio::NoPin;
3331
use crate::rcc::Clocks;
3432

35-
use crate::dma::traits::PeriAddress;
36-
3733
/// Serial error
3834
pub use embedded_hal_one::serial::ErrorKind as Error;
3935

@@ -76,6 +72,51 @@ pub trait TxISR {
7672
fn is_tx_empty(&self) -> bool;
7773
}
7874

75+
/// Trait for listening [`Rx`] interrupt events.
76+
pub trait RxListen {
77+
/// Start listening for an rx not empty interrupt event
78+
///
79+
/// Note, you will also have to enable the corresponding interrupt
80+
/// in the NVIC to start receiving events.
81+
fn listen(&mut self);
82+
83+
/// Stop listening for the rx not empty interrupt event
84+
fn unlisten(&mut self);
85+
86+
/// Start listening for a line idle interrupt event
87+
///
88+
/// Note, you will also have to enable the corresponding interrupt
89+
/// in the NVIC to start receiving events.
90+
fn listen_idle(&mut self);
91+
92+
/// Stop listening for the line idle interrupt event
93+
fn unlisten_idle(&mut self);
94+
}
95+
96+
/// Trait for listening [`Tx`] interrupt event.
97+
pub trait TxListen {
98+
/// Start listening for a tx empty interrupt event
99+
///
100+
/// Note, you will also have to enable the corresponding interrupt
101+
/// in the NVIC to start receiving events.
102+
fn listen(&mut self);
103+
104+
/// Stop listening for the tx empty interrupt event
105+
fn unlisten(&mut self);
106+
}
107+
108+
/// Trait for listening [`Serial`] interrupt events.
109+
pub trait Listen {
110+
/// Starts listening for an interrupt event
111+
///
112+
/// Note, you will also have to enable the corresponding interrupt
113+
/// in the NVIC to start receiving events.
114+
fn listen(&mut self, event: Event);
115+
116+
/// Stop listening for an interrupt event
117+
fn unlisten(&mut self, event: Event);
118+
}
119+
79120
/// Serial abstraction
80121
pub struct Serial<USART: CommonPins, WORD = u8> {
81122
tx: Tx<USART, WORD>,
@@ -131,139 +172,35 @@ impl<USART: Instance, WORD> Serial<USART, WORD> {
131172
),
132173
config: impl Into<config::Config>,
133174
clocks: &Clocks,
134-
) -> Result<Self, config::InvalidConfig> {
135-
use self::config::*;
136-
137-
let config = config.into();
138-
unsafe {
139-
// Enable clock.
140-
USART::enable_unchecked();
141-
USART::reset_unchecked();
142-
}
143-
144-
let pclk_freq = USART::clock(clocks).raw();
145-
let baud = config.baudrate.0;
146-
147-
// The frequency to calculate USARTDIV is this:
148-
//
149-
// (Taken from STM32F411xC/E Reference Manual,
150-
// Section 19.3.4, Equation 1)
151-
//
152-
// 16 bit oversample: OVER8 = 0
153-
// 8 bit oversample: OVER8 = 1
154-
//
155-
// USARTDIV = (pclk)
156-
// ------------------------
157-
// 8 x (2 - OVER8) x (baud)
158-
//
159-
// BUT, the USARTDIV has 4 "fractional" bits, which effectively
160-
// means that we need to "correct" the equation as follows:
161-
//
162-
// USARTDIV = (pclk) * 16
163-
// ------------------------
164-
// 8 x (2 - OVER8) x (baud)
165-
//
166-
// When OVER8 is enabled, we can only use the lowest three
167-
// fractional bits, so we'll need to shift those last four bits
168-
// right one bit
169-
170-
// Calculate correct baudrate divisor on the fly
171-
let (over8, div) = if (pclk_freq / 16) >= baud {
172-
// We have the ability to oversample to 16 bits, take
173-
// advantage of it.
174-
//
175-
// We also add `baud / 2` to the `pclk_freq` to ensure
176-
// rounding of values to the closest scale, rather than the
177-
// floored behavior of normal integer division.
178-
let div = (pclk_freq + (baud / 2)) / baud;
179-
(false, div)
180-
} else if (pclk_freq / 8) >= baud {
181-
// We are close enough to pclk where we can only
182-
// oversample 8.
183-
//
184-
// See note above regarding `baud` and rounding.
185-
let div = ((pclk_freq * 2) + (baud / 2)) / baud;
186-
187-
// Ensure the the fractional bits (only 3) are
188-
// right-aligned.
189-
let frac = div & 0xF;
190-
let div = (div & !0xF) | (frac >> 1);
191-
(true, div)
192-
} else {
193-
return Err(config::InvalidConfig);
194-
};
195-
196-
usart.brr.write(|w| unsafe { w.bits(div) });
197-
198-
// Reset other registers to disable advanced USART features
199-
usart.cr2.reset();
200-
usart.cr3.reset();
201-
202-
// Enable transmission and receiving
203-
// and configure frame
204-
205-
usart.cr1.write(|w| {
206-
w.ue().set_bit();
207-
w.over8().bit(over8);
208-
w.te().set_bit();
209-
w.re().set_bit();
210-
w.m().bit(config.wordlength == WordLength::DataBits9);
211-
w.pce().bit(config.parity != Parity::ParityNone);
212-
w.ps().bit(config.parity == Parity::ParityOdd)
213-
});
214-
215-
match config.dma {
216-
DmaConfig::Tx => usart.cr3.write(|w| w.dmat().enabled()),
217-
DmaConfig::Rx => usart.cr3.write(|w| w.dmar().enabled()),
218-
DmaConfig::TxRx => usart.cr3.write(|w| w.dmar().enabled().dmat().enabled()),
219-
DmaConfig::None => {}
220-
}
175+
) -> Result<Self, config::InvalidConfig>
176+
where
177+
<USART as Instance>::RegisterBlock: uart_impls::RegisterBlockImpl,
178+
{
179+
<USART as Instance>::RegisterBlock::new(usart, pins, config, clocks)
180+
}
181+
}
221182

222-
Ok(Serial {
223-
tx: Tx::new(usart, pins.0.into()),
224-
rx: Rx::new(pins.1.into()),
225-
}
226-
.config_stop(config))
183+
impl<UART: CommonPins, WORD> Serial<UART, WORD> {
184+
pub fn split(self) -> (Tx<UART, WORD>, Rx<UART, WORD>) {
185+
(self.tx, self.rx)
227186
}
228187

229188
#[allow(clippy::type_complexity)]
230-
pub fn release(self) -> (USART, (USART::Tx<PushPull>, USART::Rx<PushPull>)) {
189+
pub fn release(self) -> (UART, (UART::Tx<PushPull>, UART::Rx<PushPull>)) {
231190
(self.tx.usart, (self.tx.pin, self.rx.pin))
232191
}
233192
}
234193

235-
impl<USART: Instance, WORD> Serial<USART, WORD> {
236-
fn config_stop(self, config: config::Config) -> Self {
237-
self.tx.usart.set_stopbits(config.stopbits);
238-
self
239-
}
240-
}
241-
242-
use crate::pac::usart1 as uart_base;
243-
244-
// Implemented by all USART instances
245-
pub trait Instance:
246-
crate::Sealed
247-
+ Deref<Target = uart_base::RegisterBlock>
248-
+ rcc::Enable
249-
+ rcc::Reset
250-
+ rcc::BusClock
251-
+ CommonPins
252-
{
253-
#[doc(hidden)]
254-
fn ptr() -> *const uart_base::RegisterBlock;
255-
#[doc(hidden)]
256-
fn set_stopbits(&self, bits: config::StopBits);
257-
}
258-
259194
macro_rules! halUsart {
260-
($USART:ty, $usart:ident, $Serial:ident, $Tx:ident, $Rx:ident) => {
195+
($USART:ty, $Serial:ident, $Tx:ident, $Rx:ident) => {
261196
pub type $Serial<WORD = u8> = Serial<$USART, WORD>;
262197
pub type $Tx<WORD = u8> = Tx<$USART, WORD>;
263198
pub type $Rx<WORD = u8> = Rx<$USART, WORD>;
264199

265200
impl Instance for $USART {
266-
fn ptr() -> *const uart_base::RegisterBlock {
201+
type RegisterBlock = crate::serial::uart_impls::RegisterBlockUsart;
202+
203+
fn ptr() -> *const crate::serial::uart_impls::RegisterBlockUsart {
267204
<$USART>::ptr() as *const _
268205
}
269206

@@ -285,9 +222,112 @@ macro_rules! halUsart {
285222
}
286223
pub(crate) use halUsart;
287224

288-
halUsart! { pac::USART1, usart1, Serial1, Rx1, Tx1 }
289-
halUsart! { pac::USART2, usart2, Serial2, Rx2, Tx2 }
290-
halUsart! { pac::USART6, usart6, Serial6, Rx6, Tx6 }
225+
halUsart! { pac::USART1, Serial1, Rx1, Tx1 }
226+
halUsart! { pac::USART2, Serial2, Rx2, Tx2 }
227+
halUsart! { pac::USART6, Serial6, Rx6, Tx6 }
291228

292229
#[cfg(feature = "usart3")]
293-
halUsart! { pac::USART3, usart3, Serial3, Rx3, Tx3 }
230+
halUsart! { pac::USART3, Serial3, Rx3, Tx3 }
231+
232+
impl<UART: CommonPins> Rx<UART, u8> {
233+
pub(crate) fn with_u16_data(self) -> Rx<UART, u16> {
234+
Rx::new(self.pin)
235+
}
236+
}
237+
238+
impl<UART: CommonPins> Rx<UART, u16> {
239+
pub(crate) fn with_u8_data(self) -> Rx<UART, u8> {
240+
Rx::new(self.pin)
241+
}
242+
}
243+
244+
impl<UART: CommonPins> Tx<UART, u8> {
245+
pub(crate) fn with_u16_data(self) -> Tx<UART, u16> {
246+
Tx::new(self.usart, self.pin)
247+
}
248+
}
249+
250+
impl<UART: CommonPins> Tx<UART, u16> {
251+
pub(crate) fn with_u8_data(self) -> Tx<UART, u8> {
252+
Tx::new(self.usart, self.pin)
253+
}
254+
}
255+
256+
impl<UART: CommonPins, WORD> Rx<UART, WORD> {
257+
pub(crate) fn new(pin: UART::Rx<PushPull>) -> Self {
258+
Self {
259+
_word: PhantomData,
260+
pin,
261+
}
262+
}
263+
264+
pub fn join(self, tx: Tx<UART, WORD>) -> Serial<UART, WORD> {
265+
Serial { tx, rx: self }
266+
}
267+
}
268+
269+
impl<UART: CommonPins, WORD> Tx<UART, WORD> {
270+
pub(crate) fn new(usart: UART, pin: UART::Tx<PushPull>) -> Self {
271+
Self {
272+
_word: PhantomData,
273+
usart,
274+
pin,
275+
}
276+
}
277+
278+
pub fn join(self, rx: Rx<UART, WORD>) -> Serial<UART, WORD> {
279+
Serial { tx: self, rx }
280+
}
281+
}
282+
283+
impl<UART: Instance, WORD> AsRef<Tx<UART, WORD>> for Serial<UART, WORD> {
284+
#[inline(always)]
285+
fn as_ref(&self) -> &Tx<UART, WORD> {
286+
&self.tx
287+
}
288+
}
289+
290+
impl<UART: Instance, WORD> AsRef<Rx<UART, WORD>> for Serial<UART, WORD> {
291+
#[inline(always)]
292+
fn as_ref(&self) -> &Rx<UART, WORD> {
293+
&self.rx
294+
}
295+
}
296+
297+
impl<UART: Instance, WORD> AsMut<Tx<UART, WORD>> for Serial<UART, WORD> {
298+
#[inline(always)]
299+
fn as_mut(&mut self) -> &mut Tx<UART, WORD> {
300+
&mut self.tx
301+
}
302+
}
303+
304+
impl<UART: Instance, WORD> AsMut<Rx<UART, WORD>> for Serial<UART, WORD> {
305+
#[inline(always)]
306+
fn as_mut(&mut self) -> &mut Rx<UART, WORD> {
307+
&mut self.rx
308+
}
309+
}
310+
311+
impl<UART: Instance> Serial<UART, u8> {
312+
/// Converts this Serial into a version that can read and write `u16` values instead of `u8`s
313+
///
314+
/// This can be used with a word length of 9 bits.
315+
pub fn with_u16_data(self) -> Serial<UART, u16> {
316+
Serial {
317+
tx: self.tx.with_u16_data(),
318+
rx: self.rx.with_u16_data(),
319+
}
320+
}
321+
}
322+
323+
impl<UART: Instance> Serial<UART, u16> {
324+
/// Converts this Serial into a version that can read and write `u8` values instead of `u16`s
325+
///
326+
/// This can be used with a word length of 8 bits.
327+
pub fn with_u8_data(self) -> Serial<UART, u8> {
328+
Serial {
329+
tx: self.tx.with_u8_data(),
330+
rx: self.rx.with_u8_data(),
331+
}
332+
}
333+
}

0 commit comments

Comments
 (0)