Add stm32l0 with ExtiPin futures

This commit is contained in:
Michael Beaumont 2021-03-05 22:37:18 +01:00
parent 16e00669ae
commit b490c8a48d
No known key found for this signature in database
GPG Key ID: 94C1243E6859F368
6 changed files with 560 additions and 0 deletions

View File

@ -5,6 +5,7 @@ members = [
"embassy-traits",
"embassy-nrf",
"embassy-stm32f4",
"embassy-stm32l0",
"embassy-nrf-examples",
"embassy-stm32f4-examples",
"embassy-macros",

View File

@ -0,0 +1,26 @@
[package]
name = "embassy-stm32l0"
version = "0.1.0"
authors = ["Michael Beaumont <mjboamail@gmail.com>"]
edition = "2018"
[features]
defmt-trace = [ ]
defmt-debug = [ ]
defmt-info = [ ]
defmt-warn = [ ]
defmt-error = [ ]
stm32l0x1 = ["stm32l0xx-hal/stm32l0x1"]
stm32l0x2 = ["stm32l0xx-hal/stm32l0x2"]
stm32l0x3 = ["stm32l0xx-hal/stm32l0x3"]
[dependencies]
embassy = { version = "0.1.0", path = "../embassy" }
defmt = { version = "0.2.0", optional = true }
log = { version = "0.4.11", optional = true }
cortex-m-rt = "0.6.13"
cortex-m = "0.7.1"
embedded-hal = { version = "0.2.4" }
embedded-dma = { version = "0.1.2" }
stm32l0xx-hal = { version = "0.6.2", features = ["rt"], git = "https://github.com/stm32-rs/stm32l0xx-hal.git"}

220
embassy-stm32l0/src/exti.rs Normal file
View File

@ -0,0 +1,220 @@
use core::future::Future;
use core::mem;
use core::pin::Pin;
use embassy::interrupt::Interrupt;
use embassy::traits::gpio::{WaitForFallingEdge, WaitForRisingEdge};
use embassy::util::InterruptFuture;
use crate::hal::{
exti::{Exti, ExtiLine, GpioLine, TriggerEdge},
gpio,
syscfg::SYSCFG,
};
use crate::interrupt;
use crate::pac::EXTI;
pub struct ExtiManager {
syscfg: SYSCFG,
}
impl<'a> ExtiManager {
pub fn new(_exti: Exti, syscfg: SYSCFG) -> Self {
Self { syscfg }
}
pub fn new_pin<T, I>(&'static mut self, pin: T, interrupt: I) -> ExtiPin<T, I>
where
T: PinWithInterrupt<Interrupt = I>,
I: Interrupt,
{
ExtiPin {
pin,
interrupt,
mgr: self,
}
}
}
pub struct ExtiPin<T, I> {
pin: T,
interrupt: I,
mgr: &'static mut ExtiManager,
}
impl<T: PinWithInterrupt<Interrupt = I> + 'static, I: Interrupt + 'static> WaitForRisingEdge
for ExtiPin<T, I>
{
type Future<'a> = impl Future<Output = ()> + 'a;
fn wait_for_rising_edge<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> {
let s = unsafe { self.get_unchecked_mut() };
let line = s.pin.line();
Exti::unpend(line);
async move {
let exti: EXTI = unsafe { mem::transmute(()) };
let mut exti = Exti::new(exti);
let fut = InterruptFuture::new(&mut s.interrupt);
exti.listen_gpio(&mut s.mgr.syscfg, s.pin.port(), line, TriggerEdge::Rising);
fut.await;
Exti::unpend(line);
}
}
}
impl<T: PinWithInterrupt<Interrupt = I> + 'static, I: Interrupt + 'static> WaitForFallingEdge
for ExtiPin<T, I>
{
type Future<'a> = impl Future<Output = ()> + 'a;
fn wait_for_falling_edge<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> {
let s = unsafe { self.get_unchecked_mut() };
let line = s.pin.line();
Exti::unpend(line);
async move {
let exti: EXTI = unsafe { mem::transmute(()) };
let mut exti = Exti::new(exti);
let fut = InterruptFuture::new(&mut s.interrupt);
exti.listen_gpio(&mut s.mgr.syscfg, s.pin.port(), line, TriggerEdge::Falling);
fut.await;
Exti::unpend(line);
}
}
}
mod private {
pub trait Sealed {}
}
pub trait PinWithInterrupt: private::Sealed {
type Interrupt;
fn port(&self) -> gpio::Port;
fn line(&self) -> GpioLine;
}
macro_rules! exti {
($($PER:ident => ($set:ident, $pin:ident),)+) => {
$(
impl<T> private::Sealed for gpio::$set::$pin<T> {}
impl<T> PinWithInterrupt for gpio::$set::$pin<T> {
type Interrupt = interrupt::$PER;
fn port(&self) -> gpio::Port {
self.port()
}
fn line(&self) -> GpioLine {
GpioLine::from_raw_line(self.pin_number()).unwrap()
}
}
)+
}
}
exti! {
EXTI0_1 => (gpioa, PA0),
EXTI0_1 => (gpioa, PA1),
EXTI2_3 => (gpioa, PA2),
EXTI2_3 => (gpioa, PA3),
EXTI4_15 => (gpioa, PA4),
EXTI4_15 => (gpioa, PA5),
EXTI4_15 => (gpioa, PA6),
EXTI4_15 => (gpioa, PA7),
EXTI4_15 => (gpioa, PA8),
EXTI4_15 => (gpioa, PA9),
EXTI4_15 => (gpioa, PA10),
EXTI4_15 => (gpioa, PA11),
EXTI4_15 => (gpioa, PA12),
EXTI4_15 => (gpioa, PA13),
EXTI4_15 => (gpioa, PA14),
EXTI4_15 => (gpioa, PA15),
}
exti! {
EXTI0_1 => (gpiob, PB0),
EXTI0_1 => (gpiob, PB1),
EXTI2_3 => (gpiob, PB2),
EXTI2_3 => (gpiob, PB3),
EXTI4_15 => (gpiob, PB4),
EXTI4_15 => (gpiob, PB5),
EXTI4_15 => (gpiob, PB6),
EXTI4_15 => (gpiob, PB7),
EXTI4_15 => (gpiob, PB8),
EXTI4_15 => (gpiob, PB9),
EXTI4_15 => (gpiob, PB10),
EXTI4_15 => (gpiob, PB11),
EXTI4_15 => (gpiob, PB12),
EXTI4_15 => (gpiob, PB13),
EXTI4_15 => (gpiob, PB14),
EXTI4_15 => (gpiob, PB15),
}
exti! {
EXTI0_1 => (gpioc, PC0),
EXTI0_1 => (gpioc, PC1),
EXTI2_3 => (gpioc, PC2),
EXTI2_3 => (gpioc, PC3),
EXTI4_15 => (gpioc, PC4),
EXTI4_15 => (gpioc, PC5),
EXTI4_15 => (gpioc, PC6),
EXTI4_15 => (gpioc, PC7),
EXTI4_15 => (gpioc, PC8),
EXTI4_15 => (gpioc, PC9),
EXTI4_15 => (gpioc, PC10),
EXTI4_15 => (gpioc, PC11),
EXTI4_15 => (gpioc, PC12),
EXTI4_15 => (gpioc, PC13),
EXTI4_15 => (gpioc, PC14),
EXTI4_15 => (gpioc, PC15),
}
exti! {
EXTI0_1 => (gpiod, PD0),
EXTI0_1 => (gpiod, PD1),
EXTI2_3 => (gpiod, PD2),
EXTI2_3 => (gpiod, PD3),
EXTI4_15 => (gpiod, PD4),
EXTI4_15 => (gpiod, PD5),
EXTI4_15 => (gpiod, PD6),
EXTI4_15 => (gpiod, PD7),
EXTI4_15 => (gpiod, PD8),
EXTI4_15 => (gpiod, PD9),
EXTI4_15 => (gpiod, PD10),
EXTI4_15 => (gpiod, PD11),
EXTI4_15 => (gpiod, PD12),
EXTI4_15 => (gpiod, PD13),
EXTI4_15 => (gpiod, PD14),
EXTI4_15 => (gpiod, PD15),
}
exti! {
EXTI0_1 => (gpioe, PE0),
EXTI0_1 => (gpioe, PE1),
EXTI2_3 => (gpioe, PE2),
EXTI2_3 => (gpioe, PE3),
EXTI4_15 => (gpioe, PE4),
EXTI4_15 => (gpioe, PE5),
EXTI4_15 => (gpioe, PE6),
EXTI4_15 => (gpioe, PE7),
EXTI4_15 => (gpioe, PE8),
EXTI4_15 => (gpioe, PE9),
EXTI4_15 => (gpioe, PE10),
EXTI4_15 => (gpioe, PE11),
EXTI4_15 => (gpioe, PE12),
EXTI4_15 => (gpioe, PE13),
EXTI4_15 => (gpioe, PE14),
EXTI4_15 => (gpioe, PE15),
}
exti! {
EXTI0_1 => (gpioh, PH0),
EXTI0_1 => (gpioh, PH1),
EXTI4_15 => (gpioh, PH9),
EXTI4_15 => (gpioh, PH10),
}

119
embassy-stm32l0/src/fmt.rs Normal file
View File

@ -0,0 +1,119 @@
#![macro_use]
#![allow(clippy::module_inception)]
#[cfg(all(feature = "defmt", feature = "log"))]
compile_error!("You may not enable both `defmt` and `log` features.");
pub use fmt::*;
#[cfg(feature = "defmt")]
mod fmt {
pub use defmt::{
assert, assert_eq, assert_ne, debug, debug_assert, debug_assert_eq, debug_assert_ne, error,
info, panic, todo, trace, unreachable, unwrap, warn,
};
}
#[cfg(feature = "log")]
mod fmt {
pub use core::{
assert, assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne, panic, todo,
unreachable,
};
pub use log::{debug, error, info, trace, warn};
}
#[cfg(not(any(feature = "defmt", feature = "log")))]
mod fmt {
#![macro_use]
pub use core::{
assert, assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne, panic, todo,
unreachable,
};
#[macro_export]
macro_rules! trace {
($($msg:expr),+ $(,)?) => {
()
};
}
#[macro_export]
macro_rules! debug {
($($msg:expr),+ $(,)?) => {
()
};
}
#[macro_export]
macro_rules! info {
($($msg:expr),+ $(,)?) => {
()
};
}
#[macro_export]
macro_rules! warn {
($($msg:expr),+ $(,)?) => {
()
};
}
#[macro_export]
macro_rules! error {
($($msg:expr),+ $(,)?) => {
()
};
}
}
#[cfg(not(feature = "defmt"))]
#[macro_export]
macro_rules! unwrap {
($arg:expr) => {
match $crate::fmt::Try::into_result($arg) {
::core::result::Result::Ok(t) => t,
::core::result::Result::Err(e) => {
::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
}
}
};
($arg:expr, $($msg:expr),+ $(,)? ) => {
match $crate::fmt::Try::into_result($arg) {
::core::result::Result::Ok(t) => t,
::core::result::Result::Err(e) => {
::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
}
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct NoneError;
pub trait Try {
type Ok;
type Error;
fn into_result(self) -> Result<Self::Ok, Self::Error>;
}
impl<T> Try for Option<T> {
type Ok = T;
type Error = NoneError;
#[inline]
fn into_result(self) -> Result<T, NoneError> {
self.ok_or(NoneError)
}
}
impl<T, E> Try for Result<T, E> {
type Ok = T;
type Error = E;
#[inline]
fn into_result(self) -> Self {
self
}
}

View File

@ -0,0 +1,162 @@
//! Interrupt management
use crate::pac::NVIC_PRIO_BITS;
// Re-exports
pub use cortex_m::interrupt::{CriticalSection, Mutex};
pub use embassy::interrupt::{declare, take, Interrupt};
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)]
pub enum Priority {
Level0 = 0,
Level1 = 1,
Level2 = 2,
Level3 = 3,
Level4 = 4,
Level5 = 5,
Level6 = 6,
Level7 = 7,
Level8 = 8,
Level9 = 9,
Level10 = 10,
Level11 = 11,
Level12 = 12,
Level13 = 13,
Level14 = 14,
Level15 = 15,
}
impl From<u8> for Priority {
fn from(priority: u8) -> Self {
match priority >> (8 - NVIC_PRIO_BITS) {
0 => Self::Level0,
1 => Self::Level1,
2 => Self::Level2,
3 => Self::Level3,
4 => Self::Level4,
5 => Self::Level5,
6 => Self::Level6,
7 => Self::Level7,
8 => Self::Level8,
9 => Self::Level9,
10 => Self::Level10,
11 => Self::Level11,
12 => Self::Level12,
13 => Self::Level13,
14 => Self::Level14,
15 => Self::Level15,
_ => unreachable!(),
}
}
}
impl From<Priority> for u8 {
fn from(p: Priority) -> Self {
(p as u8) << (8 - NVIC_PRIO_BITS)
}
}
#[cfg(feature = "stm32l0x1")]
mod irqs {
use super::*;
declare!(WWDG);
declare!(PVD);
declare!(RTC);
declare!(FLASH);
declare!(RCC);
declare!(EXTI0_1);
declare!(EXTI2_3);
declare!(EXTI4_15);
declare!(DMA1_CHANNEL1);
declare!(DMA1_CHANNEL2_3);
declare!(DMA1_CHANNEL4_7);
declare!(ADC_COMP);
declare!(LPTIM1);
declare!(USART4_USART5);
declare!(TIM2);
declare!(TIM3);
declare!(TIM6);
declare!(TIM7);
declare!(TIM21);
declare!(I2C3);
declare!(TIM22);
declare!(I2C1);
declare!(I2C2);
declare!(SPI1);
declare!(SPI2);
declare!(USART1);
declare!(USART2);
declare!(AES_RNG_LPUART1);
}
#[cfg(feature = "stm32l0x2")]
mod irqs {
use super::*;
declare!(WWDG);
declare!(PVD);
declare!(RTC);
declare!(RCC);
declare!(EXTI0_1);
declare!(EXTI2_3);
declare!(EXTI4_15);
declare!(TSC);
declare!(DMA1_CHANNEL1);
declare!(DMA1_CHANNEL2_3);
declare!(DMA1_CHANNEL4_7);
declare!(ADC_COMP);
declare!(LPTIM1);
declare!(USART4_USART5);
declare!(TIM2);
declare!(TIM3);
declare!(TIM6_DAC);
declare!(TIM7);
declare!(TIM21);
declare!(I2C3);
declare!(TIM22);
declare!(I2C1);
declare!(I2C2);
declare!(SPI1);
declare!(SPI2);
declare!(USART1);
declare!(USART2);
declare!(AES_RNG_LPUART1);
declare!(USB);
}
#[cfg(feature = "stm32l0x3")]
mod irqs {
use super::*;
declare!(WWDG);
declare!(PVD);
declare!(RTC);
declare!(RCC);
declare!(EXTI0_1);
declare!(EXTI2_3);
declare!(EXTI4_15);
declare!(TSC);
declare!(DMA1_CHANNEL1);
declare!(DMA1_CHANNEL2_3);
declare!(DMA1_CHANNEL4_7);
declare!(ADC_COMP);
declare!(LPTIM1);
declare!(USART4_USART5);
declare!(TIM2);
declare!(TIM3);
declare!(TIM6_DAC);
declare!(TIM7);
declare!(TIM21);
declare!(I2C3);
declare!(TIM22);
declare!(I2C1);
declare!(I2C2);
declare!(SPI1);
declare!(SPI2);
declare!(USART1);
declare!(USART2);
declare!(AES_RNG_LPUART1);
declare!(LCD);
declare!(USB);
}
pub use irqs::*;

View File

@ -0,0 +1,32 @@
#![no_std]
#![feature(generic_associated_types)]
#![feature(asm)]
#![feature(type_alias_impl_trait)]
#![allow(incomplete_features)]
#[cfg(not(any(
feature = "stm32l0x1",
feature = "stm32l0x2",
feature = "stm32l0x3",
)))]
compile_error!(
"No chip feature activated. You must activate exactly one of the following features: "
);
#[cfg(any(
all(feature = "stm32l0x1", feature = "stm32l0x2"),
all(feature = "stm32l0x1", feature = "stm32l0x3"),
all(feature = "stm32l0x2", feature = "stm32l0x3"),
))]
compile_error!(
"Multile chip features activated. You must activate exactly one of the following features: "
);
pub use stm32l0xx_hal as hal;
pub use stm32l0xx_hal::pac;
// This mod MUST go first, so that the others see its macros.
pub(crate) mod fmt;
pub mod exti;
pub mod interrupt;