Skip to content

Commit 1ce0707

Browse files
Merge #636
636: Join Serial for USART and UART again. Make inner traits with different implementation for USART and UART. r=burrbull a=qwerty19106 cc #630 `@burrbull` ## Main idea ```rust #[cfg(feature = "uart4")] pub(crate) use crate::pac::uart4::RegisterBlock as RegisterBlockUart; pub(crate) use crate::pac::usart1::RegisterBlock as RegisterBlockUsart; pub trait RegisterBlockImpl { fn new<UART: Instance<RegisterBlock = Self>, WORD>( uart: UART, pins: (impl Into<UART::Tx<PushPull>>, impl Into<UART::Rx<PushPull>>), config: impl Into<config::Config>, clocks: &Clocks, ) -> Result<Serial<UART, WORD>, config::InvalidConfig>; fn read_u16(&self) -> nb::Result<u16, Error>; fn write_u16(&self, word: u16) -> nb::Result<(), Error>; fn read_u8(&self) -> nb::Result<u8, Error> { // Delegate to u16 version, then truncate to 8 bits self.read_u16().map(|word16| word16 as u8) } fn write_u8(&self, word: u8) -> nb::Result<(), Error> { // Delegate to u16 version self.write_u16(u16::from(word)) } fn flush(&self) -> nb::Result<(), Error>; fn bwrite_all_u8(&self, buffer: &[u8]) -> Result<(), Error> { for &b in buffer { nb::block!(self.write_u8(b))?; } Ok(()) } fn bwrite_all_u16(&self, buffer: &[u16]) -> Result<(), Error> { for &b in buffer { nb::block!(self.write_u16(b))?; } Ok(()) } fn bflush(&self) -> Result<(), Error> { nb::block!(self.flush()) } // RxISR fn is_idle(&self) -> bool; fn is_rx_not_empty(&self) -> bool; fn clear_idle_interrupt(&self); // TxISR fn is_tx_empty(&self) -> bool; // RxListen fn listen_rxne(&self); fn unlisten_rxne(&self); fn listen_idle(&self); fn unlisten_idle(&self); // TxListen fn listen_txe(&self); fn unlisten_txe(&self); // Listen fn listen(&self, event: Event); fn unlisten(&self, event: Event); // PeriAddress fn peri_address(&self) -> u32; } macro_rules! uartCommon { ($RegisterBlock:ty) => { impl RegisterBlockImpl for $RegisterBlock { ... } } } uartCommon! { RegisterBlockUsart } #[cfg(feature = "uart4")] uartCommon! { RegisterBlockUart } ``` Note that `RegisterBlockImpl` not exports from `stm32f4xx-hal`. ## Changes in public API - add `type RegisterBlock;` to `Instance` ```rust pub trait Instance: crate::Sealed + rcc::Enable + rcc::Reset + rcc::BusClock + CommonPins { type RegisterBlock; #[doc(hidden)] fn ptr() -> *const Self::RegisterBlock; #[doc(hidden)] fn set_stopbits(&self, bits: config::StopBits); } ``` - remove `uart::{Serial, Rx, Tx}` - add `RxListen`, `TxListen`, `Listen` traits ```rust /// Trait for listening [`Rx`] interrupt events. pub trait RxListen { /// Start listening for an rx not empty interrupt event /// /// Note, you will also have to enable the corresponding interrupt /// in the NVIC to start receiving events. fn listen(&mut self); /// Stop listening for the rx not empty interrupt event fn unlisten(&mut self); /// Start listening for a line idle interrupt event /// /// Note, you will also have to enable the corresponding interrupt /// in the NVIC to start receiving events. fn listen_idle(&mut self); /// Stop listening for the line idle interrupt event fn unlisten_idle(&mut self); } /// Trait for listening [`Tx`] interrupt event. pub trait TxListen { /// Start listening for a tx empty interrupt event /// /// Note, you will also have to enable the corresponding interrupt /// in the NVIC to start receiving events. fn listen(&mut self); /// Stop listening for the tx empty interrupt event fn unlisten(&mut self); } /// Trait for listening [`Serial`] interrupt events. pub trait Listen { /// Starts listening for an interrupt event /// /// Note, you will also have to enable the corresponding interrupt /// in the NVIC to start receiving events. fn listen(&mut self, event: Event); /// Stop listening for an interrupt event fn unlisten(&mut self, event: Event); } ``` - relax `Serial.split` and `Serial.release` trait bounds to `UART: CommonPins` - relax `Rx.join` and `Tx.join` trait bounds to `UART: CommonPins` ## Questions - Why `PeriAddress` and `DMASet` implemented for `Rx<UART, u8>`, not `Rx<UART, WORD>`? And Tx too. ## P.S. I have tried use `#![feature(specialization)]` and `#![feature(min_specialization)]` and failed miserably. The `min_specialization` not does not cover this case, the `specialization` cause ICE. Besides I think that current [specialization RFC](https://github.com/rust-lang/rfcs/blob/master/text/1210-impl-specialization.md) not suitable for our case at all, because we have `impl InstanceUsart` and `impl InstanceUart` with the same "specialization", but not trait bounds inheritance. Co-authored-by: Роман Кривенков <[email protected]>
2 parents 258e10d + 870b717 commit 1ce0707

File tree

7 files changed

+706
-672
lines changed

7 files changed

+706
-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)