From ef4d9d243e4e833b3f52c8a1e651877116386894 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Wed, 14 Apr 2021 15:34:58 +0200
Subject: [PATCH] wip usart

---
 embassy-stm32-examples/src/bin/usart.rs | 130 ++++++++++++++++++++++++
 embassy-stm32/src/chip/f429.rs          |  11 +-
 embassy-stm32/src/lib.rs                |   1 +
 embassy-stm32/src/usart.rs              |  64 ++++++++++++
 4 files changed, 204 insertions(+), 2 deletions(-)
 create mode 100644 embassy-stm32-examples/src/bin/usart.rs
 create mode 100644 embassy-stm32/src/usart.rs

diff --git a/embassy-stm32-examples/src/bin/usart.rs b/embassy-stm32-examples/src/bin/usart.rs
new file mode 100644
index 000000000..c218b8ced
--- /dev/null
+++ b/embassy-stm32-examples/src/bin/usart.rs
@@ -0,0 +1,130 @@
+#![no_std]
+#![no_main]
+#![feature(trait_alias)]
+#![feature(min_type_alias_impl_trait)]
+#![feature(impl_trait_in_bindings)]
+#![feature(type_alias_impl_trait)]
+
+#[path = "../example_common.rs"]
+mod example_common;
+use embassy::executor::Executor;
+use embassy::time::Clock;
+use embassy::util::Forever;
+use embassy_stm32::exti::{self, ExtiInput};
+use embassy_stm32::gpio::{Input, Pull};
+use embassy_traits::gpio::{WaitForFallingEdge, WaitForRisingEdge};
+use example_common::*;
+
+use cortex_m_rt::entry;
+use pac::{interrupt, NVIC};
+use stm32f4::stm32f429 as pac;
+
+#[embassy::task]
+async fn main_task() {
+    let p = embassy_stm32::Peripherals::take().unwrap();
+    let button = Input::new(p.PC13, Pull::Down);
+    let mut button = ExtiInput::new(button, p.EXTI13);
+
+    info!("Press the USER button...");
+
+    loop {
+        button.wait_for_rising_edge().await;
+        info!("Pressed!");
+        button.wait_for_falling_edge().await;
+        info!("Released!");
+    }
+}
+
+struct ZeroClock;
+
+impl Clock for ZeroClock {
+    fn now(&self) -> u64 {
+        0
+    }
+}
+
+static EXECUTOR: Forever<Executor> = Forever::new();
+
+#[entry]
+fn main() -> ! {
+    info!("Hello World!");
+
+    let pp = pac::Peripherals::take().unwrap();
+
+    pp.DBGMCU.cr.modify(|_, w| {
+        w.dbg_sleep().set_bit();
+        w.dbg_standby().set_bit();
+        w.dbg_stop().set_bit()
+    });
+    pp.RCC.ahb1enr.modify(|_, w| w.dma1en().enabled());
+
+    pp.RCC.ahb1enr.modify(|_, w| {
+        w.gpioaen().enabled();
+        w.gpioben().enabled();
+        w.gpiocen().enabled();
+        w.gpioden().enabled();
+        w.gpioeen().enabled();
+        w.gpiofen().enabled();
+        w
+    });
+    pp.RCC.apb2enr.modify(|_, w| {
+        w.usart1en().enabled();
+        w.syscfgen().enabled();
+        w
+    });
+
+    unsafe { embassy::time::set_clock(&ZeroClock) };
+
+    unsafe {
+        NVIC::unmask(interrupt::EXTI0);
+        NVIC::unmask(interrupt::EXTI1);
+        NVIC::unmask(interrupt::EXTI2);
+        NVIC::unmask(interrupt::EXTI3);
+        NVIC::unmask(interrupt::EXTI4);
+        NVIC::unmask(interrupt::EXTI9_5);
+        NVIC::unmask(interrupt::EXTI15_10);
+    }
+
+    let executor = EXECUTOR.put(Executor::new());
+
+    executor.run(|spawner| {
+        unwrap!(spawner.spawn(main_task()));
+    })
+}
+
+// TODO for now irq handling is done by user code using the old pac, until we figure out how interrupts work in the metapac
+
+#[interrupt]
+unsafe fn EXTI0() {
+    exti::on_irq()
+}
+
+#[interrupt]
+unsafe fn EXTI1() {
+    exti::on_irq()
+}
+
+#[interrupt]
+unsafe fn EXTI2() {
+    exti::on_irq()
+}
+
+#[interrupt]
+unsafe fn EXTI3() {
+    exti::on_irq()
+}
+
+#[interrupt]
+unsafe fn EXTI4() {
+    exti::on_irq()
+}
+
+#[interrupt]
+unsafe fn EXTI9_5() {
+    exti::on_irq()
+}
+
+#[interrupt]
+unsafe fn EXTI15_10() {
+    exti::on_irq()
+}
diff --git a/embassy-stm32/src/chip/f429.rs b/embassy-stm32/src/chip/f429.rs
index db68faa5a..1209b9237 100644
--- a/embassy-stm32/src/chip/f429.rs
+++ b/embassy-stm32/src/chip/f429.rs
@@ -1,5 +1,6 @@
 use embassy_extras::peripherals;
 
+#[rustfmt::skip]
 peripherals!(
     // GPIO Port A
     PA0, PA1, PA2, PA3, PA4, PA5, PA6, PA7, PA8, PA9, PA10, PA11, PA12, PA13, PA14, PA15,
@@ -10,6 +11,12 @@ peripherals!(
     // todo more ports
 
     // EXTI
-    EXTI0, EXTI1, EXTI2, EXTI3, EXTI4, EXTI5, EXTI6, EXTI7, EXTI8, EXTI9, EXTI10, EXTI11, EXTI12,
-    EXTI13, EXTI14, EXTI15,
+    EXTI0, EXTI1, EXTI2, EXTI3, EXTI4, EXTI5, EXTI6, EXTI7, EXTI8, EXTI9, EXTI10, EXTI11, EXTI12, EXTI13, EXTI14, EXTI15,
+
+    // USART
+    USART1,
+    USART2,
+    USART3,
+    USART6,
+
 );
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index da266f75d..8fe53840f 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -32,5 +32,6 @@ pub mod exti;
 pub mod gpio;
 //pub mod rtc;
 //pub mod interrupt;
+pub mod usart;
 
 pub(crate) use stm32_metapac as pac;
diff --git a/embassy-stm32/src/usart.rs b/embassy-stm32/src/usart.rs
new file mode 100644
index 000000000..ad1376941
--- /dev/null
+++ b/embassy-stm32/src/usart.rs
@@ -0,0 +1,64 @@
+use embassy::util::PeripheralBorrow;
+
+use crate::pac::usart_v1::{regs, vals, Usart};
+use crate::peripherals;
+
+mod sealed {
+    use super::*;
+    pub trait Instance {
+        fn regs(&self) -> Usart;
+    }
+}
+
+#[non_exhaustive]
+pub struct Config {
+    pub baudrate: u32,
+    pub data_bits: u8,
+    pub stop_bits: u8,
+}
+
+impl Default for Config {
+    fn default() -> Self {
+        Self {
+            baudrate: 115200,
+            data_bits: 8,
+            stop_bits: 1,
+        }
+    }
+}
+
+pub struct Uart<'d, T: Instance> {
+    inner: T,
+    phantom: PhantomData<&'d mut T>,
+}
+
+impl<'d, T: Instance> Uart<'d, T> {
+    pub fn new(
+        inner: impl PeripheralBorrow<Target = T>,
+        tx: impl PeripheralBorrow<Target = impl TxPin<T>>,
+        rx: impl PeripheralBorrow<Target = impl RxPin<T>>,
+        cts: impl PeripheralBorrow<Target = impl CtsPin<T>>,
+        rts: impl PeripheralBorrow<Target = impl RtsPin<T>>,
+        config: Config,
+    ) -> Self {
+        unborrow!(inner, tx, rx, cts, rts);
+    }
+}
+
+pub trait Instance: sealed::Instance {}
+
+macro_rules! impl_instance {
+    ($type:ident, $addr:expr) => {
+        impl sealed::Instance for peripherals::$type {
+            fn regs(&self) -> Usart {
+                Usart($addr as _)
+            }
+        }
+        impl Instance for peripherals::$type {}
+    };
+}
+
+impl_instance!(USART1, 0x40011000);
+impl_instance!(USART2, 0x40004400);
+impl_instance!(USART3, 0x40004800);
+impl_instance!(USART6, 0x40011400);