Skip to content

Commit b7308b4

Browse files
committed
Notice that some UART peripherals have only PCLK as source
For some devices of the stm32f3 family, the source clock can not be adjusted and can only be the peripheral clock (PCLK). As usartXsw() (where X = 1, 2 or 3) would be called directly in any case, it would not compile for peripheral, which do not have this flag in their CFGR3 register. To circumvent this issue, split out the clock logic into it's own macro, which then can declare, which peripheral has a variable clock source and which have not. This conditional check can not be introduced in the former macro definition, as it is not possible to change the behavior of the macro depending on a type or name of an identifier.
1 parent fb374fa commit b7308b4

File tree

1 file changed

+91
-24
lines changed

1 file changed

+91
-24
lines changed

src/serial.rs

Lines changed: 91 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,14 @@ 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, RCC, USART1, USART2, USART3},
15+
pac::{self, rcc::cfgr3::USART1SW_A, usart1::RegisterBlock, USART1, USART2, USART3},
1616
rcc::{Clocks, APB1, APB2},
1717
time::rate::*,
1818
};
1919

20+
#[allow(unused_imports)]
21+
use crate::pac::RCC;
22+
2023
use cfg_if::cfg_if;
2124

2225
cfg_if! {
@@ -492,35 +495,32 @@ pub trait Instance: Deref<Target = RegisterBlock> + private::Sealed {
492495
}
493496

494497
macro_rules! usart {
495-
($($USARTX:ident: ($usartXen:ident, $APB:ident, $pclkX:ident, $usartXrst:ident, $usartXsw:ident),)+) => {
498+
(
499+
$(
500+
$USARTX:ident: (
501+
$usartXen:ident,
502+
$APB:ident,
503+
$pclkX:ident,
504+
$usartXrst:ident,
505+
$usartXsw:ident,
506+
$usartXclock:ident
507+
),
508+
)+
509+
) => {
496510
$(
497511
impl private::Sealed for $USARTX {}
498512
impl Instance for $USARTX {
499513
type APB = $APB;
500514
fn enable_clock(apb: &mut Self::APB) {
501515
apb.enr().modify(|_, w| w.$usartXen().enabled());
502516
apb.rstr().modify(|_, w| w.$usartXrst().reset());
503-
apb.rstr().modify(|_, w| w.$usartXrst().clear_bit());
504517
}
505518

506519
fn clock(clocks: &Clocks) -> Hertz {
507-
// NOTE(unsafe) atomic read with no side effects
508-
509-
// This is only partly sovable by this. The macro has to be adjusted, to give
510-
// information about, if sw is avalible for the uart implementation or not
511-
cfg_if::cfg_if! {
512-
if #[cfg(any(feature = "svd-f301", feature = "svd-f3x4"))] {
513-
clocks.$pclkX()
514-
} else {
515-
// FIXME usart2sw() is not avalible for stm32f318x8 for example
516-
match unsafe { (*RCC::ptr()).cfgr3.read().$usartXsw().variant() } {
517-
USART1SW_A::PCLK => clocks.$pclkX(),
518-
USART1SW_A::HSI => crate::rcc::HSI,
519-
USART1SW_A::SYSCLK => clocks.sysclk(),
520-
USART1SW_A::LSE => crate::rcc::LSE,
521-
}
522-
}
523-
}
520+
// Use the function created via another macro outside of this one,
521+
// because the implementation is dependend on the type $USARTX.
522+
// But macros can not differentiate between types.
523+
$usartXclock(clocks)
524524
}
525525
}
526526

@@ -552,12 +552,79 @@ macro_rules! usart {
552552
([ $(($X:literal, $APB:literal)),+ ]) => {
553553
paste::paste! {
554554
usart!(
555-
$([<USART $X>]: ([<usart $X en>], [<APB $APB>], [<pclk $APB>], [<usart $X rst>], [<usart $X sw>]),)+
555+
$(
556+
[<USART $X>]: (
557+
[<usart $X en>],
558+
[<APB $APB>],
559+
[<pclk $APB>],
560+
[<usart $X rst>],
561+
[<usart $X sw>],
562+
[<usart $X clock>]
563+
),
564+
)+
565+
);
566+
}
567+
};
568+
}
569+
570+
/// Generates a clock function for UART Peripherals, where
571+
/// the only clock source can be the peripheral clock
572+
#[allow(unused_macros)]
573+
macro_rules! usart_static_clock {
574+
($($usartXclock:ident, $pclkX:ident),+) => {
575+
$(
576+
/// Return the currently set source frequency the UART peripheral
577+
/// depending on the clock source.
578+
fn $usartXclock(clocks: &Clocks) -> Hertz {
579+
clocks.$pclkX()
580+
}
581+
)+
582+
};
583+
([ $(($X:literal, $APB:literal)),+ ]) => {
584+
paste::paste! {
585+
usart_static_clock!(
586+
$([<usart $X clock>], [<pclk $APB>]),+
556587
);
557588
}
558589
};
559590
}
560591

561-
usart!([(1, 2)]);
562-
usart!([(2, 1)]);
563-
usart!([(3, 1)]);
592+
/// Generates a clock function for UART Peripherals, where
593+
/// the clock source can vary.
594+
macro_rules! usart_var_clock {
595+
($($usartXclock:ident, $usartXsw:ident, $pclkX:ident),+) => {
596+
$(
597+
/// Return the currently set source frequency the UART peripheral
598+
/// depending on the clock source.
599+
fn $usartXclock(clocks: &Clocks) -> Hertz {
600+
// NOTE(unsafe): atomic read with no side effects
601+
match unsafe {(*RCC::ptr()).cfgr3.read().$usartXsw().variant()} {
602+
USART1SW_A::PCLK => clocks.$pclkX(),
603+
USART1SW_A::HSI => crate::rcc::HSI,
604+
USART1SW_A::SYSCLK => clocks.sysclk(),
605+
USART1SW_A::LSE => crate::rcc::LSE,
606+
}
607+
}
608+
)+
609+
};
610+
([ $(($X:literal, $APB:literal)),+ ]) => {
611+
paste::paste! {
612+
usart_var_clock!(
613+
$([<usart $X clock>], [<usart $X sw>], [<pclk $APB>]),+
614+
);
615+
}
616+
};
617+
}
618+
619+
cfg_if::cfg_if! {
620+
if #[cfg(any(feature = "svd-f301", feature = "svd-f3x4"))] {
621+
usart_var_clock!([(1,2)]);
622+
// These are uart peripherals, where the only clock source
623+
// is the PCLK (peripheral clock).
624+
usart_static_clock!([(2,1), (3,1)]);
625+
} else {
626+
usart_var_clock!([(1, 2), (2, 1), (3, 1)]);
627+
}
628+
}
629+
// TODO: what about uart 4 and uart 5?
630+
usart!([(1, 2), (2, 1), (3, 1)]);

0 commit comments

Comments
 (0)