Skip to content

Commit a65e3b0

Browse files
committed
refactor(uart): simplify driver architecture with ownership and trait-based APIs
This commit restructures the UART driver to use reference-based peripheral management instead of owned register blocks, introducing the UartExt trait for streamlined instance creation. The Serial struct now operates on borrowed register blocks with lifetime tracking, reducing type complexity by eliminating redundant generic parameters. Error messages for invalid pad connections are optimized to use standard TX/RX abbreviations and clearer phrasing. Peripheral release semantics are adjusted in free() to return only pads, reflecting the shift to non-owning register access. Example code and HAL prelude are updated to leverage the new trait-based API, while macro expansions enable automatic UART instance implementations. These changes improve type safety, reduce code duplication, and provide more idiomatic embedded-Rust interfaces. Implement UartExt for UARTx or &'a mut UARTx. The former UARTx consumes and convert into &'static RegisterBlock, while &'a mut UARTx converts into &'a RegisterBlock. Signed-off-by: Zhouqi Jiang <luojia@hust.edu.cn>
1 parent ae6dff2 commit a65e3b0

File tree

7 files changed

+126
-74
lines changed

7 files changed

+126
-74
lines changed

allwinner-hal/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ pub mod uart;
2121

2222
#[doc(hidden)]
2323
pub mod prelude {
24+
pub use crate::uart::UartExt as _;
2425
pub use embedded_hal::{
2526
digital::{InputPin as _, OutputPin as _, StatefulOutputPin as _},
2627
spi::SpiBus as _,

allwinner-hal/src/uart.rs

Lines changed: 59 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -81,23 +81,39 @@ impl core::ops::Deref for RegisterBlock {
8181
}
8282
}
8383

84+
/// Extend constructor to owned UART register blocks.
85+
pub trait UartExt<'a, const I: usize> {
86+
/// Creates a polling serial instance, without interrupt or DMA configurations.
87+
fn serial<PADS>(
88+
self,
89+
pads: PADS,
90+
config: impl Into<Config>,
91+
clocks: &Clocks,
92+
ccu: &ccu::RegisterBlock,
93+
) -> Serial<'a, PADS>
94+
where
95+
PADS: Pads<I>;
96+
}
97+
8498
/// Managed serial structure with peripheral and pads.
85-
#[derive(Debug)]
86-
pub struct Serial<UART, const I: usize, PADS: Pads<I>> {
87-
uart: UART,
99+
pub struct Serial<'a, PADS> {
100+
uart: &'a RegisterBlock,
88101
pads: PADS,
89102
}
90103

91-
impl<UART: AsRef<RegisterBlock>, const I: usize, PADS: Pads<I>> Serial<UART, I, PADS> {
104+
impl<'a, PADS> Serial<'a, PADS> {
92105
/// Create a serial instance.
93106
#[inline]
94-
pub fn new(
95-
uart: UART,
107+
pub fn new<const I: usize>(
108+
uart: &'a RegisterBlock,
96109
pads: PADS,
97110
config: impl Into<Config>,
98111
clocks: &Clocks,
99112
ccu: &ccu::RegisterBlock,
100-
) -> Self {
113+
) -> Self
114+
where
115+
PADS: Pads<I>,
116+
{
101117
// 1. unwrap parameters
102118
let Config {
103119
baudrate,
@@ -111,8 +127,8 @@ impl<UART: AsRef<RegisterBlock>, const I: usize, PADS: Pads<I>> Serial<UART, I,
111127
unsafe { PADS::Clock::reset(ccu) };
112128
// 3. set interrupt configuration
113129
// on BT0 stage we disable all uart interrupts
114-
let interrupt_types = uart.as_ref().ier().read();
115-
uart.as_ref().ier().write(
130+
let interrupt_types = uart.ier().read();
131+
uart.ier().write(
116132
interrupt_types
117133
.disable_ms()
118134
.disable_rda()
@@ -121,7 +137,7 @@ impl<UART: AsRef<RegisterBlock>, const I: usize, PADS: Pads<I>> Serial<UART, I,
121137
);
122138
// 4. calculate and set baudrate
123139
let uart_clk = (clocks.apb1.0 + 8 * bps) / (16 * bps);
124-
uart.as_ref().write_divisor(uart_clk as u16);
140+
uart.write_divisor(uart_clk as u16);
125141
// 5. additional configurations
126142
let char_len = match wordlength {
127143
WordLength::Five => CharLen::FIVE,
@@ -135,8 +151,8 @@ impl<UART: AsRef<RegisterBlock>, const I: usize, PADS: Pads<I>> Serial<UART, I,
135151
Parity::Odd => PARITY::ODD,
136152
Parity::Even => PARITY::EVEN,
137153
};
138-
let lcr = uart.as_ref().lcr().read();
139-
uart.as_ref().lcr().write(
154+
let lcr = uart.lcr().read();
155+
uart.lcr().write(
140156
lcr.set_char_len(char_len)
141157
.set_one_stop_bit(one_stop_bit)
142158
.set_parity(parity),
@@ -154,22 +170,27 @@ impl<UART: AsRef<RegisterBlock>, const I: usize, PADS: Pads<I>> Serial<UART, I,
154170
}
155171
/// Close uart and release peripheral.
156172
#[inline]
157-
pub fn free(self, ccu: &ccu::RegisterBlock) -> (UART, PADS) {
173+
pub fn free<const I: usize>(self, ccu: &ccu::RegisterBlock) -> PADS
174+
where
175+
PADS: Pads<I>,
176+
{
158177
// clock is closed for self.clock_gate is dropped
159178
unsafe { PADS::Clock::free(ccu) };
160-
(self.uart, self.pads)
179+
self.pads
161180
}
162181
}
163182

164-
impl<UART: AsRef<RegisterBlock>, const I: usize, TX: Transmit<I>, RX: Receive<I>>
165-
Serial<UART, I, (TX, RX)>
166-
{
183+
impl<'a, TX, RX> Serial<'a, (TX, RX)> {
167184
/// Split serial instance into transmit and receive halves.
168185
#[inline]
169-
pub fn split(self) -> (TransmitHalf<UART, I, TX>, ReceiveHalf<UART, I, RX>) {
186+
pub fn split<const I: usize>(self) -> (TransmitHalf<'a, TX>, ReceiveHalf<'a, RX>)
187+
where
188+
TX: Transmit<I>,
189+
RX: Receive<I>,
190+
{
170191
(
171192
TransmitHalf {
172-
uart: unsafe { core::ptr::read_volatile(&self.uart) },
193+
uart: self.uart,
173194
_pads: self.pads.0,
174195
},
175196
ReceiveHalf {
@@ -181,16 +202,14 @@ impl<UART: AsRef<RegisterBlock>, const I: usize, TX: Transmit<I>, RX: Receive<I>
181202
}
182203

183204
/// Transmit half from splitted serial structure.
184-
#[derive(Debug)]
185-
pub struct TransmitHalf<UART, const I: usize, PADS: Transmit<I>> {
186-
uart: UART,
205+
pub struct TransmitHalf<'a, PADS> {
206+
uart: &'a RegisterBlock,
187207
_pads: PADS,
188208
}
189209

190210
/// Receive half from splitted serial structure.
191-
#[derive(Debug)]
192-
pub struct ReceiveHalf<UART, const I: usize, PADS: Receive<I>> {
193-
uart: UART,
211+
pub struct ReceiveHalf<'a, PADS> {
212+
uart: &'a RegisterBlock,
194213
_pads: PADS,
195214
}
196215

@@ -200,9 +219,11 @@ pub trait Pads<const I: usize> {
200219
}
201220

202221
/// Valid transmit pin for UART peripheral.
222+
#[diagnostic::on_unimplemented(message = "selected pad does not connect to UART{I} TX signal")]
203223
pub trait Transmit<const I: usize> {}
204224

205225
/// Valid receive pin for UART peripheral.
226+
#[diagnostic::on_unimplemented(message = "selected pad does not connect to UART{I} RX signal")]
206227
pub trait Receive<const I: usize> {}
207228

208229
#[inline]
@@ -251,67 +272,53 @@ where
251272
type Clock = ccu::UART<I>;
252273
}
253274

254-
impl<UART: AsRef<RegisterBlock>, const I: usize, PADS: Pads<I>> embedded_io::ErrorType
255-
for Serial<UART, I, PADS>
256-
{
275+
impl<'a, PADS> embedded_io::ErrorType for Serial<'a, PADS> {
257276
type Error = core::convert::Infallible;
258277
}
259278

260-
impl<UART: AsRef<RegisterBlock>, const I: usize, PADS: Transmit<I>> embedded_io::ErrorType
261-
for TransmitHalf<UART, I, PADS>
262-
{
279+
impl<'a, PADS> embedded_io::ErrorType for TransmitHalf<'a, PADS> {
263280
type Error = core::convert::Infallible;
264281
}
265282

266-
impl<UART: AsRef<RegisterBlock>, const I: usize, PADS: Receive<I>> embedded_io::ErrorType
267-
for ReceiveHalf<UART, I, PADS>
268-
{
283+
impl<'a, PADS> embedded_io::ErrorType for ReceiveHalf<'a, PADS> {
269284
type Error = core::convert::Infallible;
270285
}
271286

272-
impl<UART: AsRef<RegisterBlock>, const I: usize, PADS: Pads<I>> embedded_io::Write
273-
for Serial<UART, I, PADS>
274-
{
287+
impl<'a, PADS> embedded_io::Write for Serial<'a, PADS> {
275288
#[inline]
276289
fn write(&mut self, buffer: &[u8]) -> Result<usize, Self::Error> {
277-
uart_write_blocking(self.uart.as_ref(), buffer)
290+
uart_write_blocking(self.uart, buffer)
278291
}
279292

280293
#[inline]
281294
fn flush(&mut self) -> Result<(), Self::Error> {
282-
uart_flush_blocking(self.uart.as_ref())
295+
uart_flush_blocking(self.uart)
283296
}
284297
}
285298

286-
impl<UART: AsRef<RegisterBlock>, const I: usize, PADS: Transmit<I>> embedded_io::Write
287-
for TransmitHalf<UART, I, PADS>
288-
{
299+
impl<'a, PADS> embedded_io::Write for TransmitHalf<'a, PADS> {
289300
#[inline]
290301
fn write(&mut self, buffer: &[u8]) -> Result<usize, Self::Error> {
291-
uart_write_blocking(self.uart.as_ref(), buffer)
302+
uart_write_blocking(self.uart, buffer)
292303
}
293304

294305
#[inline]
295306
fn flush(&mut self) -> Result<(), Self::Error> {
296-
uart_flush_blocking(self.uart.as_ref())
307+
uart_flush_blocking(self.uart)
297308
}
298309
}
299310

300-
impl<UART: AsRef<RegisterBlock>, const I: usize, PADS: Pads<I>> embedded_io::Read
301-
for Serial<UART, I, PADS>
302-
{
311+
impl<'a, PADS> embedded_io::Read for Serial<'a, PADS> {
303312
#[inline]
304313
fn read(&mut self, buffer: &mut [u8]) -> Result<usize, Self::Error> {
305-
uart_read_blocking(self.uart.as_ref(), buffer)
314+
uart_read_blocking(self.uart, buffer)
306315
}
307316
}
308317

309-
impl<UART: AsRef<RegisterBlock>, const I: usize, PADS: Receive<I>> embedded_io::Read
310-
for ReceiveHalf<UART, I, PADS>
311-
{
318+
impl<'a, PADS> embedded_io::Read for ReceiveHalf<'a, PADS> {
312319
#[inline]
313320
fn read(&mut self, buffer: &mut [u8]) -> Result<usize, Self::Error> {
314-
uart_read_blocking(self.uart.as_ref(), buffer)
321+
uart_read_blocking(self.uart, buffer)
315322
}
316323
}
317324

allwinner-rt/examples/fn-main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
#![no_std]
77
#![no_main]
8-
use allwinner_hal::uart::{Config, Serial};
8+
use allwinner_hal::{prelude::*, uart::Config};
99
use allwinner_rt::{Clocks, Peripherals, entry};
1010
use embedded_hal::digital::{InputPin, OutputPin};
1111

@@ -19,7 +19,7 @@ fn main(p: Peripherals, c: Clocks) {
1919

2020
let tx = p.gpio.pb8.into_function::<7>();
2121
let rx = p.gpio.pb9.into_function::<7>();
22-
let mut serial = Serial::new(p.uart0, (tx, rx), Config::default(), &c, &p.ccu);
22+
let mut serial = p.uart0.serial((tx, rx), Config::default(), &c, &p.ccu);
2323

2424
let _borrow_input_high = serial.pads(|(_, rx)| rx.with_input(|pad| pad.is_high()));
2525
}

allwinner-rt/src/macros.rs

Lines changed: 54 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ macro_rules! soc {
22
(
33
$(
44
$(#[$doc:meta])*
5-
pub struct $Ty:ident => $paddr:expr_2021
6-
$(, $DerefTy:ty)+ ;
5+
pub struct $Ty:ident => $paddr:expr_2021, $DerefTy:ty;
76
)+
87
) => {
98
$(
@@ -12,24 +11,64 @@ macro_rules! soc {
1211
pub struct $Ty {
1312
_private: (),
1413
}
14+
impl $Ty {
15+
#[inline]
16+
pub const fn ptr() -> *const $DerefTy {
17+
$paddr as *const _
18+
}
19+
}
1520

16-
$(
17-
impl core::ops::Deref for $Ty {
18-
type Target = $DerefTy;
21+
impl core::ops::Deref for $Ty {
22+
type Target = $DerefTy;
23+
#[inline(always)]
24+
fn deref(&self) -> &Self::Target {
25+
unsafe { &*($paddr as *const _) }
26+
}
27+
}
28+
impl core::convert::AsRef<$DerefTy> for $Ty {
29+
#[inline(always)]
30+
fn as_ref(&self) -> &$DerefTy {
31+
unsafe { &*($paddr as *const _) }
32+
}
33+
}
34+
)+
35+
};
36+
}
1937

20-
#[inline(always)]
21-
fn deref(&self) -> &Self::Target {
22-
unsafe { &*($paddr as *const _) }
23-
}
38+
macro_rules! impl_uart {
39+
($($i:expr => $UARTi:ident,)+) => {
40+
$(
41+
impl<'a> UartExt<'a, $i> for &'a mut $UARTi {
42+
fn serial<PADS>(
43+
self,
44+
pads: PADS,
45+
config: impl Into<allwinner_hal::uart::Config>,
46+
clocks: &Clocks,
47+
ccu: &allwinner_hal::ccu::RegisterBlock,
48+
) -> allwinner_hal::uart::Serial<'a, PADS>
49+
where
50+
PADS: allwinner_hal::uart::Pads<$i>,
51+
{
52+
allwinner_hal::uart::Serial::new(self, pads, config, clocks, ccu)
2453
}
54+
}
2555

26-
impl core::convert::AsRef<$DerefTy> for $Ty {
27-
#[inline(always)]
28-
fn as_ref(&self) -> &$DerefTy {
29-
unsafe { &*($paddr as *const _) }
30-
}
56+
impl UartExt<'static, $i> for $UARTi {
57+
fn serial<PADS>(
58+
self,
59+
pads: PADS,
60+
config: impl Into<allwinner_hal::uart::Config>,
61+
clocks: &Clocks,
62+
ccu: &allwinner_hal::ccu::RegisterBlock,
63+
) -> allwinner_hal::uart::Serial<'static, PADS>
64+
where
65+
PADS: allwinner_hal::uart::Pads<$i>,
66+
{
67+
let uart = unsafe { &*$UARTi::ptr() };
68+
allwinner_hal::uart::Serial::new(uart, pads, config, clocks, ccu)
3169
}
32-
)+
70+
}
71+
3372
)+
3473
};
3574
}

allwinner-rt/src/soc/d1.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! D1-H, D1s, F133, F133A/B chip platforms.
22
3-
use allwinner_hal::{ccu::Clocks, gpio::Disabled, wafer::d1::Pads};
3+
use allwinner_hal::{ccu::Clocks, gpio::Disabled, uart::UartExt, wafer::d1::Pads};
44
use embedded_time::rate::Extensions;
55

66
/// ROM runtime peripheral ownership and configurations.
@@ -50,6 +50,10 @@ soc! {
5050
pub struct PLIC => 0x10000000, plic::Plic;
5151
}
5252

53+
impl_uart! {
54+
0 => UART0,
55+
}
56+
5357
#[doc(hidden)]
5458
#[inline]
5559
pub fn __rom_init_params() -> (Peripherals<'static>, Clocks) {

examples/nezha-d1/src/bin/uart.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#![no_std]
22
#![no_main]
33

4-
use allwinner_hal::uart::{Config, Serial};
4+
use allwinner_hal::{prelude::*, uart::Config};
55
use allwinner_rt::{Clocks, Peripherals, entry};
66
use embedded_io::{Read, Write};
77
use panic_halt as _;
@@ -10,7 +10,7 @@ use panic_halt as _;
1010
fn main(p: Peripherals, c: Clocks) {
1111
let tx = p.gpio.pb8.into_function::<6>();
1212
let rx = p.gpio.pb9.into_function::<6>();
13-
let mut serial = Serial::new(p.uart0, (tx, rx), Config::default(), &c, &p.ccu);
13+
let mut serial = p.uart0.serial((tx, rx), Config::default(), &c, &p.ccu);
1414

1515
writeln!(serial, "Hello World!").ok();
1616

examples/sdmmc/src/main.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
#![no_main]
33

44
use allwinner_hal::{
5+
prelude::*,
56
smhc::{SdCard, Smhc},
6-
uart::{Config, Serial},
7+
uart::Config,
78
};
89
use allwinner_rt::{Clocks, Peripherals, entry};
910
use embedded_io::Write;
@@ -23,7 +24,7 @@ impl embedded_sdmmc::TimeSource for MyTimeSource {
2324
fn main(p: Peripherals, c: Clocks) {
2425
let tx = p.gpio.pb8.into_function::<6>();
2526
let rx = p.gpio.pb9.into_function::<6>();
26-
let mut serial = Serial::new(p.uart0, (tx, rx), Config::default(), &c, &p.ccu);
27+
let mut serial = p.uart0.serial((tx, rx), Config::default(), &c, &p.ccu);
2728

2829
writeln!(serial, "Hello World!").ok();
2930

0 commit comments

Comments
 (0)