33
									
								
								.github/workflows/rust.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										33
									
								
								.github/workflows/rust.yml
									
									
									
									
										vendored
									
									
								
							| @@ -30,40 +30,31 @@ jobs: | ||||
|             target: thumbv7em-none-eabi | ||||
|           - package: embassy-nrf | ||||
|             target: thumbv7em-none-eabi | ||||
|             features: 52810 | ||||
|             features: nrf52805 | ||||
|           - package: embassy-nrf | ||||
|             target: thumbv7em-none-eabi | ||||
|             features: 52832 | ||||
|             features: nrf52810 | ||||
|           - package: embassy-nrf | ||||
|             target: thumbv7em-none-eabi | ||||
|             features: 52833 | ||||
|             features: nrf52811 | ||||
|           - package: embassy-nrf | ||||
|             target: thumbv7em-none-eabi | ||||
|             features: 52840 | ||||
|             features: nrf52820 | ||||
|           - package: embassy-nrf | ||||
|             target: thumbv7em-none-eabi | ||||
|             features: 52840,log | ||||
|             features: nrf52832 | ||||
|           - package: embassy-nrf | ||||
|             target: thumbv7em-none-eabi | ||||
|             features: 52840,defmt | ||||
|           - package: embassy-stm32-examples | ||||
|             features: nrf52833 | ||||
|           - package: embassy-nrf | ||||
|             target: thumbv7em-none-eabi | ||||
|             features: stm32f405 | ||||
|           - package: embassy-stm32 | ||||
|             features: nrf52840 | ||||
|           - package: embassy-nrf | ||||
|             target: thumbv7em-none-eabi | ||||
|             features: stm32f405 | ||||
|           - package: embassy-stm32 | ||||
|             features: nrf52840,log | ||||
|           - package: embassy-nrf | ||||
|             target: thumbv7em-none-eabi | ||||
|             features: stm32f446 | ||||
|           - package: embassy-stm32 | ||||
|             target: thumbv7em-none-eabi | ||||
|             features: stm32f405,defmt | ||||
|           - package: embassy-stm32 | ||||
|             target: thumbv6m-none-eabi | ||||
|             features: stm32l0x2 | ||||
|           - package: embassy-stm32 | ||||
|             target: thumbv6m-none-eabi | ||||
|             features: stm32l0x2,defmt | ||||
|             features: nrf52840,defmt | ||||
|           - package: embassy-rp-examples | ||||
|             target: thumbv6m-none-eabi | ||||
|  | ||||
|   | ||||
| @@ -46,18 +46,17 @@ macro_rules! peripherals { | ||||
|         impl Peripherals { | ||||
|             ///Returns all the peripherals *once* | ||||
|             #[inline] | ||||
|             pub fn take() -> Option<Self> { | ||||
|             pub(crate) fn take() -> Self { | ||||
|  | ||||
|                 #[no_mangle] | ||||
|                 static mut _EMBASSY_DEVICE_PERIPHERALS: bool = false; | ||||
|  | ||||
|                 critical_section::with(|_| { | ||||
|                     if unsafe { _EMBASSY_DEVICE_PERIPHERALS } { | ||||
|                         None | ||||
|                     } else { | ||||
|                         unsafe { _EMBASSY_DEVICE_PERIPHERALS = true }; | ||||
|                         Some(unsafe { <Self as embassy::util::Steal>::steal() }) | ||||
|                 critical_section::with(|_| unsafe { | ||||
|                     if _EMBASSY_DEVICE_PERIPHERALS { | ||||
|                         panic!("init called more than once!") | ||||
|                     } | ||||
|                     _EMBASSY_DEVICE_PERIPHERALS = true; | ||||
|                     <Self as embassy::util::Steal>::steal() | ||||
|                 }) | ||||
|             } | ||||
|         } | ||||
|   | ||||
| @@ -14,7 +14,6 @@ proc-macro2 = "1.0.24" | ||||
| proc-macro = true | ||||
|  | ||||
| [features] | ||||
| stm32 = [] | ||||
| nrf = [] | ||||
| rp = [] | ||||
| std = [] | ||||
|   | ||||
| @@ -9,7 +9,7 @@ pub fn generate(embassy_prefix: &ModulePrefix, config: syn::Expr) -> TokenStream | ||||
|     quote!( | ||||
|         use #embassy_nrf_path::{interrupt, peripherals, rtc}; | ||||
|  | ||||
|         unsafe { #embassy_nrf_path::system::configure(#config) }; | ||||
|         let p = #embassy_nrf_path::init(#config); | ||||
|  | ||||
|         let mut rtc = rtc::RTC::new(unsafe { <peripherals::RTC1 as #embassy_path::util::Steal>::steal() }, interrupt::take!(RTC1)); | ||||
|         let rtc = unsafe { make_static(&mut rtc) }; | ||||
|   | ||||
| @@ -7,6 +7,6 @@ pub fn generate(embassy_prefix: &ModulePrefix, config: syn::Expr) -> TokenStream | ||||
|     quote!( | ||||
|         use #embassy_rp_path::{interrupt, peripherals}; | ||||
|  | ||||
|         unsafe { #embassy_rp_path::system::configure(#config) }; | ||||
|         let p = #embassy_rp_path::init(#config); | ||||
|     ) | ||||
| } | ||||
|   | ||||
| @@ -1,28 +0,0 @@ | ||||
| use crate::path::ModulePrefix; | ||||
| use proc_macro2::TokenStream; | ||||
| use quote::quote; | ||||
|  | ||||
| pub fn generate(embassy_prefix: &ModulePrefix, config: syn::Expr) -> TokenStream { | ||||
|     let embassy_path = embassy_prefix.append("embassy").path(); | ||||
|     let embassy_stm32_path = embassy_prefix.append("embassy_stm32").path(); | ||||
|  | ||||
|     quote!( | ||||
|         use #embassy_stm32_path::{rtc, interrupt, Peripherals, pac, hal::rcc::RccExt, hal::time::U32Ext}; | ||||
|  | ||||
|         unsafe { #embassy_stm32_path::system::configure(#config) }; | ||||
|  | ||||
|         let (dp, clocks) = Peripherals::take().unwrap(); | ||||
|  | ||||
|         let mut rtc = rtc::RTC::new(dp.TIM2, interrupt::take!(TIM2), clocks); | ||||
|         let rtc = unsafe { make_static(&mut rtc) }; | ||||
|         rtc.start(); | ||||
|         let mut alarm = rtc.alarm1(); | ||||
|  | ||||
|         unsafe { #embassy_path::time::set_clock(rtc) }; | ||||
|  | ||||
|         let alarm = unsafe { make_static(&mut alarm) }; | ||||
|         executor.set_alarm(alarm); | ||||
|  | ||||
|         unsafe { Peripherals::set_peripherals(clocks) }; | ||||
|     ) | ||||
| } | ||||
| @@ -3,9 +3,13 @@ | ||||
| extern crate proc_macro; | ||||
|  | ||||
| use darling::FromMeta; | ||||
| use proc_macro::{Span, TokenStream}; | ||||
| use proc_macro::TokenStream; | ||||
| use proc_macro2::Span; | ||||
| use quote::{format_ident, quote}; | ||||
| use std::iter; | ||||
| use syn::spanned::Spanned; | ||||
| use syn::{parse, Type, Visibility}; | ||||
| use syn::{ItemFn, ReturnType}; | ||||
|  | ||||
| mod path; | ||||
|  | ||||
| @@ -58,10 +62,9 @@ pub fn task(args: TokenStream, item: TokenStream) -> TokenStream { | ||||
|         fail = true; | ||||
|     } | ||||
|     if pool_size < 1 { | ||||
|         Span::call_site() | ||||
|             .error("pool_size must be 1 or greater") | ||||
|             .emit(); | ||||
|         fail = true | ||||
|         return parse::Error::new(Span::call_site(), "pool_size must be 1 or greater") | ||||
|             .to_compile_error() | ||||
|             .into(); | ||||
|     } | ||||
|  | ||||
|     let mut arg_names: syn::punctuated::Punctuated<syn::Ident, syn::Token![,]> = | ||||
| @@ -120,6 +123,66 @@ pub fn task(args: TokenStream, item: TokenStream) -> TokenStream { | ||||
|     result.into() | ||||
| } | ||||
|  | ||||
| #[proc_macro_attribute] | ||||
| pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream { | ||||
|     let mut f: ItemFn = syn::parse(input).expect("`#[interrupt]` must be applied to a function"); | ||||
|  | ||||
|     if !args.is_empty() { | ||||
|         return parse::Error::new(Span::call_site(), "This attribute accepts no arguments") | ||||
|             .to_compile_error() | ||||
|             .into(); | ||||
|     } | ||||
|  | ||||
|     let fspan = f.span(); | ||||
|     let ident = f.sig.ident.clone(); | ||||
|     let ident_s = ident.to_string(); | ||||
|  | ||||
|     // XXX should we blacklist other attributes? | ||||
|  | ||||
|     let valid_signature = f.sig.constness.is_none() | ||||
|         && f.vis == Visibility::Inherited | ||||
|         && f.sig.abi.is_none() | ||||
|         && f.sig.inputs.is_empty() | ||||
|         && f.sig.generics.params.is_empty() | ||||
|         && f.sig.generics.where_clause.is_none() | ||||
|         && f.sig.variadic.is_none() | ||||
|         && match f.sig.output { | ||||
|             ReturnType::Default => true, | ||||
|             ReturnType::Type(_, ref ty) => match **ty { | ||||
|                 Type::Tuple(ref tuple) => tuple.elems.is_empty(), | ||||
|                 Type::Never(..) => true, | ||||
|                 _ => false, | ||||
|             }, | ||||
|         }; | ||||
|  | ||||
|     if !valid_signature { | ||||
|         return parse::Error::new( | ||||
|             fspan, | ||||
|             "`#[interrupt]` handlers must have signature `[unsafe] fn() [-> !]`", | ||||
|         ) | ||||
|         .to_compile_error() | ||||
|         .into(); | ||||
|     } | ||||
|  | ||||
|     f.block.stmts = iter::once( | ||||
|         syn::parse2(quote! {{ | ||||
|             // Check that this interrupt actually exists | ||||
|             let __irq_exists_check: interrupt::#ident; | ||||
|         }}) | ||||
|         .unwrap(), | ||||
|     ) | ||||
|     .chain(f.block.stmts) | ||||
|     .collect(); | ||||
|  | ||||
|     quote!( | ||||
|         #[doc(hidden)] | ||||
|         #[export_name = #ident_s] | ||||
|         #[allow(non_snake_case)] | ||||
|         #f | ||||
|     ) | ||||
|     .into() | ||||
| } | ||||
|  | ||||
| #[proc_macro] | ||||
| pub fn interrupt_declare(item: TokenStream) -> TokenStream { | ||||
|     let name = syn::parse_macro_input!(item as syn::Ident); | ||||
| @@ -130,7 +193,7 @@ pub fn interrupt_declare(item: TokenStream) -> TokenStream { | ||||
|     let result = quote! { | ||||
|         #[allow(non_camel_case_types)] | ||||
|         pub struct #name_interrupt(()); | ||||
|         unsafe impl Interrupt for #name_interrupt { | ||||
|         unsafe impl ::embassy::interrupt::Interrupt for #name_interrupt { | ||||
|             type Priority = crate::interrupt::Priority; | ||||
|             fn number(&self) -> u16 { | ||||
|                 use cortex_m::interrupt::InterruptNumber; | ||||
| @@ -204,10 +267,6 @@ pub fn interrupt_take(item: TokenStream) -> TokenStream { | ||||
| #[path = "chip/nrf.rs"] | ||||
| mod chip; | ||||
|  | ||||
| #[cfg(feature = "stm32")] | ||||
| #[path = "chip/stm32.rs"] | ||||
| mod chip; | ||||
|  | ||||
| #[cfg(feature = "rp")] | ||||
| #[path = "chip/rp.rs"] | ||||
| mod chip; | ||||
| @@ -221,7 +280,7 @@ struct MainArgs { | ||||
|     config: Option<syn::LitStr>, | ||||
| } | ||||
|  | ||||
| #[cfg(any(feature = "nrf", feature = "stm32", feature = "rp"))] | ||||
| #[cfg(any(feature = "nrf", feature = "rp"))] | ||||
| #[proc_macro_attribute] | ||||
| pub fn main(args: TokenStream, item: TokenStream) -> TokenStream { | ||||
|     let macro_args = syn::parse_macro_input!(args as syn::AttributeArgs); | ||||
| @@ -256,12 +315,12 @@ pub fn main(args: TokenStream, item: TokenStream) -> TokenStream { | ||||
|  | ||||
|     let args = task_fn.sig.inputs.clone(); | ||||
|  | ||||
|     if args.len() != 1 { | ||||
|     if args.len() != 2 { | ||||
|         task_fn | ||||
|             .sig | ||||
|             .span() | ||||
|             .unwrap() | ||||
|             .error("main function must have one argument") | ||||
|             .error("main function must have 2 arguments") | ||||
|             .emit(); | ||||
|         fail = true; | ||||
|     } | ||||
| @@ -305,7 +364,7 @@ pub fn main(args: TokenStream, item: TokenStream) -> TokenStream { | ||||
|             #chip_setup | ||||
|  | ||||
|             executor.run(|spawner| { | ||||
|                 spawner.spawn(__embassy_main(spawner)).unwrap(); | ||||
|                 spawner.spawn(__embassy_main(spawner, p)).unwrap(); | ||||
|             }) | ||||
|  | ||||
|         } | ||||
|   | ||||
| @@ -19,7 +19,7 @@ defmt-error = [] | ||||
| [dependencies] | ||||
| embassy = { version = "0.1.0", path = "../embassy", features = ["defmt", "defmt-trace"] } | ||||
| embassy-traits = { version = "0.1.0", path = "../embassy-traits", features = ["defmt"] } | ||||
| embassy-nrf = { version = "0.1.0", path = "../embassy-nrf", features = ["defmt", "defmt-trace", "52840"] } | ||||
| embassy-nrf = { version = "0.1.0", path = "../embassy-nrf", features = ["defmt", "defmt-trace", "nrf52840"] } | ||||
|  | ||||
| defmt = "0.2.0" | ||||
| defmt-rtt = "0.2.0" | ||||
|   | ||||
| @@ -17,8 +17,7 @@ use embassy_nrf::Peripherals; | ||||
| use embedded_hal::digital::v2::OutputPin; | ||||
|  | ||||
| #[embassy::main] | ||||
| async fn main(spawner: Spawner) { | ||||
|     let p = Peripherals::take().unwrap(); | ||||
| async fn main(spawner: Spawner, p: Peripherals) { | ||||
|     let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard); | ||||
|  | ||||
|     loop { | ||||
|   | ||||
| @@ -17,9 +17,7 @@ use example_common::*; | ||||
| use futures::pin_mut; | ||||
|  | ||||
| #[embassy::main] | ||||
| async fn main(spawner: Spawner) { | ||||
|     let p = Peripherals::take().unwrap(); | ||||
|  | ||||
| async fn main(spawner: Spawner, p: Peripherals) { | ||||
|     let mut config = uarte::Config::default(); | ||||
|     config.parity = uarte::Parity::EXCLUDED; | ||||
|     config.baudrate = uarte::Baudrate::BAUD115200; | ||||
|   | ||||
| @@ -13,7 +13,7 @@ use core::task::Poll; | ||||
| use defmt::panic; | ||||
| use embassy::executor::Spawner; | ||||
| use embassy::time::{Duration, Instant, Timer}; | ||||
| use embassy_nrf::interrupt; | ||||
| use embassy_nrf::{interrupt, Peripherals}; | ||||
|  | ||||
| #[embassy::task] | ||||
| async fn run1() { | ||||
| @@ -40,7 +40,7 @@ async fn run3() { | ||||
| } | ||||
|  | ||||
| #[embassy::main] | ||||
| async fn main(spawner: Spawner) { | ||||
| async fn main(spawner: Spawner, p: Peripherals) { | ||||
|     unwrap!(spawner.spawn(run1())); | ||||
|     unwrap!(spawner.spawn(run2())); | ||||
|     unwrap!(spawner.spawn(run3())); | ||||
|   | ||||
| @@ -12,36 +12,29 @@ use example_common::*; | ||||
| use defmt::panic; | ||||
| use embassy::executor::Spawner; | ||||
| use embassy_nrf::gpio::{Input, Pull}; | ||||
| use embassy_nrf::gpiote::{self, InputChannel, InputChannelPolarity}; | ||||
| use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity}; | ||||
| use embassy_nrf::{interrupt, Peripherals}; | ||||
|  | ||||
| #[embassy::main] | ||||
| async fn main(spawner: Spawner) { | ||||
|     let p = Peripherals::take().unwrap(); | ||||
|     let g = gpiote::initialize(p.GPIOTE, interrupt::take!(GPIOTE)); | ||||
|  | ||||
| async fn main(spawner: Spawner, p: Peripherals) { | ||||
|     info!("Starting!"); | ||||
|  | ||||
|     let ch1 = InputChannel::new( | ||||
|         g, | ||||
|         p.GPIOTE_CH0, | ||||
|         Input::new(p.P0_11, Pull::Up), | ||||
|         InputChannelPolarity::HiToLo, | ||||
|     ); | ||||
|     let ch2 = InputChannel::new( | ||||
|         g, | ||||
|         p.GPIOTE_CH1, | ||||
|         Input::new(p.P0_12, Pull::Up), | ||||
|         InputChannelPolarity::LoToHi, | ||||
|     ); | ||||
|     let ch3 = InputChannel::new( | ||||
|         g, | ||||
|         p.GPIOTE_CH2, | ||||
|         Input::new(p.P0_24, Pull::Up), | ||||
|         InputChannelPolarity::Toggle, | ||||
|     ); | ||||
|     let ch4 = InputChannel::new( | ||||
|         g, | ||||
|         p.GPIOTE_CH3, | ||||
|         Input::new(p.P0_25, Pull::Up), | ||||
|         InputChannelPolarity::Toggle, | ||||
|   | ||||
| @@ -8,12 +8,11 @@ | ||||
| #[path = "../example_common.rs"] | ||||
| mod example_common; | ||||
|  | ||||
| use core::pin::Pin; | ||||
| use defmt::panic; | ||||
| use embassy::executor::Spawner; | ||||
| use embassy::traits::gpio::{WaitForHigh, WaitForLow}; | ||||
| use embassy_nrf::gpio::{AnyPin, Input, Pin as _, Pull}; | ||||
| use embassy_nrf::gpiote::{self, PortInput}; | ||||
| use embassy_nrf::gpiote::PortInput; | ||||
| use embassy_nrf::interrupt; | ||||
| use embassy_nrf::Peripherals; | ||||
| use example_common::*; | ||||
| @@ -29,15 +28,13 @@ async fn button_task(n: usize, mut pin: PortInput<'static, AnyPin>) { | ||||
| } | ||||
|  | ||||
| #[embassy::main] | ||||
| async fn main(spawner: Spawner) { | ||||
|     let p = Peripherals::take().unwrap(); | ||||
| async fn main(spawner: Spawner, p: Peripherals) { | ||||
|     info!("Starting!"); | ||||
|  | ||||
|     let g = gpiote::initialize(p.GPIOTE, interrupt::take!(GPIOTE)); | ||||
|  | ||||
|     let btn1 = PortInput::new(g, Input::new(p.P0_11.degrade(), Pull::Up)); | ||||
|     let btn2 = PortInput::new(g, Input::new(p.P0_12.degrade(), Pull::Up)); | ||||
|     let btn3 = PortInput::new(g, Input::new(p.P0_24.degrade(), Pull::Up)); | ||||
|     let btn4 = PortInput::new(g, Input::new(p.P0_25.degrade(), Pull::Up)); | ||||
|     let btn1 = PortInput::new(Input::new(p.P0_11.degrade(), Pull::Up)); | ||||
|     let btn2 = PortInput::new(Input::new(p.P0_12.degrade(), Pull::Up)); | ||||
|     let btn3 = PortInput::new(Input::new(p.P0_24.degrade(), Pull::Up)); | ||||
|     let btn4 = PortInput::new(Input::new(p.P0_25.degrade(), Pull::Up)); | ||||
|  | ||||
|     spawner.spawn(button_task(1, btn1)).unwrap(); | ||||
|     spawner.spawn(button_task(2, btn2)).unwrap(); | ||||
|   | ||||
| @@ -126,9 +126,8 @@ static EXECUTOR_LOW: Forever<Executor> = Forever::new(); | ||||
| fn main() -> ! { | ||||
|     info!("Hello World!"); | ||||
|  | ||||
|     let p = unwrap!(embassy_nrf::Peripherals::take()); | ||||
|     let p = embassy_nrf::init(Default::default()); | ||||
|  | ||||
|     unsafe { embassy_nrf::system::configure(Default::default()) }; | ||||
|     let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1))); | ||||
|     rtc.start(); | ||||
|     unsafe { embassy::time::set_clock(rtc) }; | ||||
|   | ||||
| @@ -19,46 +19,37 @@ use embassy_nrf::{interrupt, Peripherals}; | ||||
| use gpiote::{OutputChannel, OutputChannelPolarity}; | ||||
|  | ||||
| #[embassy::main] | ||||
| async fn main(spawner: Spawner) { | ||||
|     let p = Peripherals::take().unwrap(); | ||||
|     let g = gpiote::initialize(p.GPIOTE, interrupt::take!(GPIOTE)); | ||||
|  | ||||
| async fn main(spawner: Spawner, p: Peripherals) { | ||||
|     info!("Starting!"); | ||||
|  | ||||
|     let button1 = InputChannel::new( | ||||
|         g, | ||||
|         p.GPIOTE_CH0, | ||||
|         Input::new(p.P0_11, Pull::Up), | ||||
|         InputChannelPolarity::HiToLo, | ||||
|     ); | ||||
|     let button2 = InputChannel::new( | ||||
|         g, | ||||
|         p.GPIOTE_CH1, | ||||
|         Input::new(p.P0_12, Pull::Up), | ||||
|         InputChannelPolarity::HiToLo, | ||||
|     ); | ||||
|     let button3 = InputChannel::new( | ||||
|         g, | ||||
|         p.GPIOTE_CH2, | ||||
|         Input::new(p.P0_24, Pull::Up), | ||||
|         InputChannelPolarity::HiToLo, | ||||
|     ); | ||||
|     let button4 = InputChannel::new( | ||||
|         g, | ||||
|         p.GPIOTE_CH3, | ||||
|         Input::new(p.P0_25, Pull::Up), | ||||
|         InputChannelPolarity::HiToLo, | ||||
|     ); | ||||
|  | ||||
|     let led1 = OutputChannel::new( | ||||
|         g, | ||||
|         p.GPIOTE_CH4, | ||||
|         Output::new(p.P0_13, Level::Low, OutputDrive::Standard), | ||||
|         OutputChannelPolarity::Toggle, | ||||
|     ); | ||||
|  | ||||
|     let led2 = OutputChannel::new( | ||||
|         g, | ||||
|         p.GPIOTE_CH5, | ||||
|         Output::new(p.P0_14, Level::Low, OutputDrive::Standard), | ||||
|         OutputChannelPolarity::Toggle, | ||||
|   | ||||
							
								
								
									
										104
									
								
								embassy-nrf-examples/src/bin/pwm.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								embassy-nrf-examples/src/bin/pwm.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,104 @@ | ||||
| #![no_std] | ||||
| #![no_main] | ||||
| #![feature(min_type_alias_impl_trait)] | ||||
| #![feature(impl_trait_in_bindings)] | ||||
| #![feature(type_alias_impl_trait)] | ||||
| #![allow(incomplete_features)] | ||||
|  | ||||
| #[path = "../example_common.rs"] | ||||
| mod example_common; | ||||
| use defmt::{panic, *}; | ||||
| use embassy::executor::Spawner; | ||||
| use embassy::time::{Duration, Timer}; | ||||
| use embassy_nrf::pwm::{Prescaler, Pwm}; | ||||
| use embassy_nrf::{interrupt, Peripherals}; | ||||
|  | ||||
| // for i in range(1024): print(int((math.sin(i/512*math.pi)*0.4+0.5)**2*32767), ', ', end='') | ||||
| static DUTY: [u16; 1024] = [ | ||||
|     8191, 8272, 8353, 8434, 8516, 8598, 8681, 8764, 8847, 8931, 9015, 9099, 9184, 9269, 9354, 9440, | ||||
|     9526, 9613, 9700, 9787, 9874, 9962, 10050, 10139, 10227, 10316, 10406, 10495, 10585, 10675, | ||||
|     10766, 10857, 10948, 11039, 11131, 11223, 11315, 11407, 11500, 11592, 11685, 11779, 11872, | ||||
|     11966, 12060, 12154, 12248, 12343, 12438, 12533, 12628, 12723, 12818, 12914, 13010, 13106, | ||||
|     13202, 13298, 13394, 13491, 13587, 13684, 13781, 13878, 13975, 14072, 14169, 14266, 14364, | ||||
|     14461, 14558, 14656, 14754, 14851, 14949, 15046, 15144, 15242, 15339, 15437, 15535, 15632, | ||||
|     15730, 15828, 15925, 16023, 16120, 16218, 16315, 16412, 16510, 16607, 16704, 16801, 16898, | ||||
|     16995, 17091, 17188, 17284, 17380, 17477, 17572, 17668, 17764, 17859, 17955, 18050, 18145, | ||||
|     18239, 18334, 18428, 18522, 18616, 18710, 18803, 18896, 18989, 19082, 19174, 19266, 19358, | ||||
|     19449, 19540, 19631, 19722, 19812, 19902, 19991, 20081, 20169, 20258, 20346, 20434, 20521, | ||||
|     20608, 20695, 20781, 20867, 20952, 21037, 21122, 21206, 21290, 21373, 21456, 21538, 21620, | ||||
|     21701, 21782, 21863, 21943, 22022, 22101, 22179, 22257, 22335, 22412, 22488, 22564, 22639, | ||||
|     22714, 22788, 22861, 22934, 23007, 23079, 23150, 23220, 23290, 23360, 23429, 23497, 23564, | ||||
|     23631, 23698, 23763, 23828, 23892, 23956, 24019, 24081, 24143, 24204, 24264, 24324, 24383, | ||||
|     24441, 24499, 24555, 24611, 24667, 24721, 24775, 24828, 24881, 24933, 24983, 25034, 25083, | ||||
|     25132, 25180, 25227, 25273, 25319, 25363, 25407, 25451, 25493, 25535, 25575, 25615, 25655, | ||||
|     25693, 25731, 25767, 25803, 25838, 25873, 25906, 25939, 25971, 26002, 26032, 26061, 26089, | ||||
|     26117, 26144, 26170, 26195, 26219, 26242, 26264, 26286, 26307, 26327, 26346, 26364, 26381, | ||||
|     26397, 26413, 26427, 26441, 26454, 26466, 26477, 26487, 26496, 26505, 26512, 26519, 26525, | ||||
|     26530, 26534, 26537, 26539, 26540, 26541, 26540, 26539, 26537, 26534, 26530, 26525, 26519, | ||||
|     26512, 26505, 26496, 26487, 26477, 26466, 26454, 26441, 26427, 26413, 26397, 26381, 26364, | ||||
|     26346, 26327, 26307, 26286, 26264, 26242, 26219, 26195, 26170, 26144, 26117, 26089, 26061, | ||||
|     26032, 26002, 25971, 25939, 25906, 25873, 25838, 25803, 25767, 25731, 25693, 25655, 25615, | ||||
|     25575, 25535, 25493, 25451, 25407, 25363, 25319, 25273, 25227, 25180, 25132, 25083, 25034, | ||||
|     24983, 24933, 24881, 24828, 24775, 24721, 24667, 24611, 24555, 24499, 24441, 24383, 24324, | ||||
|     24264, 24204, 24143, 24081, 24019, 23956, 23892, 23828, 23763, 23698, 23631, 23564, 23497, | ||||
|     23429, 23360, 23290, 23220, 23150, 23079, 23007, 22934, 22861, 22788, 22714, 22639, 22564, | ||||
|     22488, 22412, 22335, 22257, 22179, 22101, 22022, 21943, 21863, 21782, 21701, 21620, 21538, | ||||
|     21456, 21373, 21290, 21206, 21122, 21037, 20952, 20867, 20781, 20695, 20608, 20521, 20434, | ||||
|     20346, 20258, 20169, 20081, 19991, 19902, 19812, 19722, 19631, 19540, 19449, 19358, 19266, | ||||
|     19174, 19082, 18989, 18896, 18803, 18710, 18616, 18522, 18428, 18334, 18239, 18145, 18050, | ||||
|     17955, 17859, 17764, 17668, 17572, 17477, 17380, 17284, 17188, 17091, 16995, 16898, 16801, | ||||
|     16704, 16607, 16510, 16412, 16315, 16218, 16120, 16023, 15925, 15828, 15730, 15632, 15535, | ||||
|     15437, 15339, 15242, 15144, 15046, 14949, 14851, 14754, 14656, 14558, 14461, 14364, 14266, | ||||
|     14169, 14072, 13975, 13878, 13781, 13684, 13587, 13491, 13394, 13298, 13202, 13106, 13010, | ||||
|     12914, 12818, 12723, 12628, 12533, 12438, 12343, 12248, 12154, 12060, 11966, 11872, 11779, | ||||
|     11685, 11592, 11500, 11407, 11315, 11223, 11131, 11039, 10948, 10857, 10766, 10675, 10585, | ||||
|     10495, 10406, 10316, 10227, 10139, 10050, 9962, 9874, 9787, 9700, 9613, 9526, 9440, 9354, 9269, | ||||
|     9184, 9099, 9015, 8931, 8847, 8764, 8681, 8598, 8516, 8434, 8353, 8272, 8191, 8111, 8031, 7952, | ||||
|     7873, 7794, 7716, 7638, 7561, 7484, 7407, 7331, 7255, 7180, 7105, 7031, 6957, 6883, 6810, 6738, | ||||
|     6665, 6594, 6522, 6451, 6381, 6311, 6241, 6172, 6104, 6036, 5968, 5901, 5834, 5767, 5702, 5636, | ||||
|     5571, 5507, 5443, 5379, 5316, 5253, 5191, 5130, 5068, 5008, 4947, 4888, 4828, 4769, 4711, 4653, | ||||
|     4596, 4539, 4482, 4426, 4371, 4316, 4261, 4207, 4153, 4100, 4047, 3995, 3943, 3892, 3841, 3791, | ||||
|     3741, 3691, 3642, 3594, 3546, 3498, 3451, 3404, 3358, 3312, 3267, 3222, 3178, 3134, 3090, 3047, | ||||
|     3005, 2962, 2921, 2879, 2839, 2798, 2758, 2719, 2680, 2641, 2603, 2565, 2528, 2491, 2454, 2418, | ||||
|     2382, 2347, 2312, 2278, 2244, 2210, 2177, 2144, 2112, 2080, 2048, 2017, 1986, 1956, 1926, 1896, | ||||
|     1867, 1838, 1810, 1781, 1754, 1726, 1699, 1673, 1646, 1620, 1595, 1570, 1545, 1520, 1496, 1472, | ||||
|     1449, 1426, 1403, 1380, 1358, 1336, 1315, 1294, 1273, 1252, 1232, 1212, 1192, 1173, 1154, 1135, | ||||
|     1117, 1099, 1081, 1063, 1046, 1029, 1012, 996, 980, 964, 948, 933, 918, 903, 888, 874, 860, | ||||
|     846, 833, 819, 806, 793, 781, 768, 756, 744, 733, 721, 710, 699, 688, 677, 667, 657, 647, 637, | ||||
|     627, 618, 609, 599, 591, 582, 574, 565, 557, 549, 541, 534, 526, 519, 512, 505, 498, 492, 485, | ||||
|     479, 473, 467, 461, 455, 450, 444, 439, 434, 429, 424, 419, 415, 410, 406, 402, 398, 394, 390, | ||||
|     386, 383, 379, 376, 373, 370, 367, 364, 361, 359, 356, 354, 351, 349, 347, 345, 343, 342, 340, | ||||
|     338, 337, 336, 334, 333, 332, 331, 330, 330, 329, 328, 328, 328, 327, 327, 327, 327, 327, 328, | ||||
|     328, 328, 329, 330, 330, 331, 332, 333, 334, 336, 337, 338, 340, 342, 343, 345, 347, 349, 351, | ||||
|     354, 356, 359, 361, 364, 367, 370, 373, 376, 379, 383, 386, 390, 394, 398, 402, 406, 410, 415, | ||||
|     419, 424, 429, 434, 439, 444, 450, 455, 461, 467, 473, 479, 485, 492, 498, 505, 512, 519, 526, | ||||
|     534, 541, 549, 557, 565, 574, 582, 591, 599, 609, 618, 627, 637, 647, 657, 667, 677, 688, 699, | ||||
|     710, 721, 733, 744, 756, 768, 781, 793, 806, 819, 833, 846, 860, 874, 888, 903, 918, 933, 948, | ||||
|     964, 980, 996, 1012, 1029, 1046, 1063, 1081, 1099, 1117, 1135, 1154, 1173, 1192, 1212, 1232, | ||||
|     1252, 1273, 1294, 1315, 1336, 1358, 1380, 1403, 1426, 1449, 1472, 1496, 1520, 1545, 1570, 1595, | ||||
|     1620, 1646, 1673, 1699, 1726, 1754, 1781, 1810, 1838, 1867, 1896, 1926, 1956, 1986, 2017, 2048, | ||||
|     2080, 2112, 2144, 2177, 2210, 2244, 2278, 2312, 2347, 2382, 2418, 2454, 2491, 2528, 2565, 2603, | ||||
|     2641, 2680, 2719, 2758, 2798, 2839, 2879, 2921, 2962, 3005, 3047, 3090, 3134, 3178, 3222, 3267, | ||||
|     3312, 3358, 3404, 3451, 3498, 3546, 3594, 3642, 3691, 3741, 3791, 3841, 3892, 3943, 3995, 4047, | ||||
|     4100, 4153, 4207, 4261, 4316, 4371, 4426, 4482, 4539, 4596, 4653, 4711, 4769, 4828, 4888, 4947, | ||||
|     5008, 5068, 5130, 5191, 5253, 5316, 5379, 5443, 5507, 5571, 5636, 5702, 5767, 5834, 5901, 5968, | ||||
|     6036, 6104, 6172, 6241, 6311, 6381, 6451, 6522, 6594, 6665, 6738, 6810, 6883, 6957, 7031, 7105, | ||||
|     7180, 7255, 7331, 7407, 7484, 7561, 7638, 7716, 7794, 7873, 7952, 8031, 8111, | ||||
| ]; | ||||
|  | ||||
| #[embassy::main] | ||||
| async fn main(spawner: Spawner, p: Peripherals) { | ||||
|     let pwm = Pwm::new(p.PWM0, p.P0_13, p.P0_14, p.P0_16, p.P0_15); | ||||
|     pwm.set_prescaler(Prescaler::Div1); | ||||
|     info!("pwm initialized!"); | ||||
|  | ||||
|     let mut i = 0; | ||||
|     loop { | ||||
|         i += 1; | ||||
|         pwm.set_duty(0, DUTY[i % 1024]); | ||||
|         pwm.set_duty(1, DUTY[(i + 256) % 1024]); | ||||
|         pwm.set_duty(2, DUTY[(i + 512) % 1024]); | ||||
|         pwm.set_duty(3, DUTY[(i + 768) % 1024]); | ||||
|         Timer::after(Duration::from_millis(3)).await; | ||||
|     } | ||||
| } | ||||
| @@ -23,9 +23,7 @@ const PAGE_SIZE: usize = 4096; | ||||
| struct AlignedBuf([u8; 4096]); | ||||
|  | ||||
| #[embassy::main] | ||||
| async fn main(spawner: Spawner) { | ||||
|     let p = Peripherals::take().unwrap(); | ||||
|  | ||||
| async fn main(spawner: Spawner, p: Peripherals) { | ||||
|     let csn = p.P0_17; | ||||
|     let sck = p.P0_19; | ||||
|     let io0 = p.P0_20; | ||||
|   | ||||
| @@ -37,9 +37,8 @@ static EXECUTOR: Forever<Executor> = Forever::new(); | ||||
| fn main() -> ! { | ||||
|     info!("Hello World!"); | ||||
|  | ||||
|     let p = unwrap!(embassy_nrf::Peripherals::take()); | ||||
|     let p = embassy_nrf::init(Default::default()); | ||||
|  | ||||
|     unsafe { embassy_nrf::system::configure(Default::default()) }; | ||||
|     let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1))); | ||||
|     rtc.start(); | ||||
|     unsafe { embassy::time::set_clock(rtc) }; | ||||
|   | ||||
| @@ -19,19 +19,14 @@ use embedded_hal::digital::v2::*; | ||||
| use example_common::*; | ||||
|  | ||||
| #[embassy::main] | ||||
| async fn main(spawner: Spawner) { | ||||
| async fn main(spawner: Spawner, p: Peripherals) { | ||||
|     info!("running!"); | ||||
|  | ||||
|     let p = unsafe { Peripherals::steal() }; | ||||
|  | ||||
|     let config = spim::Config { | ||||
|         frequency: spim::Frequency::M16, | ||||
|         mode: spim::MODE_0, | ||||
|         orc: 0x00, | ||||
|     }; | ||||
|     let mut config = spim::Config::default(); | ||||
|     config.frequency = spim::Frequency::M16; | ||||
|  | ||||
|     let irq = interrupt::take!(SPIM3); | ||||
|     let mut spim = spim::Spim::new(p.SPIM3, irq, p.P0_29, p.P0_28, p.P0_30, config); | ||||
|     let mut spim = spim::Spim::new(p.SPI3, irq, p.P0_29, p.P0_28, p.P0_30, config); | ||||
|  | ||||
|     let mut ncs = Output::new(p.P0_31, Level::High, OutputDrive::Standard); | ||||
|  | ||||
|   | ||||
| @@ -7,6 +7,7 @@ | ||||
|  | ||||
| #[path = "../example_common.rs"] | ||||
| mod example_common; | ||||
| use embassy_nrf::Peripherals; | ||||
| use example_common::*; | ||||
|  | ||||
| use defmt::panic; | ||||
| @@ -30,7 +31,7 @@ async fn run2() { | ||||
| } | ||||
|  | ||||
| #[embassy::main] | ||||
| async fn main(spawner: Spawner) { | ||||
| async fn main(spawner: Spawner, p: Peripherals) { | ||||
|     unwrap!(spawner.spawn(run1())); | ||||
|     unwrap!(spawner.spawn(run2())); | ||||
| } | ||||
|   | ||||
| @@ -17,9 +17,7 @@ use embassy_nrf::gpio::NoPin; | ||||
| use embassy_nrf::{interrupt, uarte, Peripherals}; | ||||
|  | ||||
| #[embassy::main] | ||||
| async fn main(spawner: Spawner) { | ||||
|     let p = unsafe { Peripherals::steal() }; | ||||
|  | ||||
| async fn main(spawner: Spawner, p: Peripherals) { | ||||
|     let mut config = uarte::Config::default(); | ||||
|     config.parity = uarte::Parity::EXCLUDED; | ||||
|     config.baudrate = uarte::Baudrate::BAUD115200; | ||||
| @@ -42,33 +40,5 @@ async fn main(spawner: Spawner) { | ||||
|         unwrap!(uart.read(&mut buf).await); | ||||
|         info!("writing..."); | ||||
|         unwrap!(uart.write(&buf).await); | ||||
|  | ||||
|         /* | ||||
|         // `receive()` doesn't return until the buffer has been completely filled with | ||||
|         // incoming data, which in this case is 8 bytes. | ||||
|         // | ||||
|         // This example shows how to use `select` to run an uart receive concurrently with a | ||||
|         // 1 second timer, effectively adding a timeout to the receive operation. | ||||
|         let recv_fut = uart.read(&mut buf); | ||||
|         let timer_fut = Timer::after(Duration::from_millis(1000)); | ||||
|         let received_len = match select(recv_fut, timer_fut).await { | ||||
|             // recv_fut completed first, so we've received `buf_len` bytes. | ||||
|             Either::Left(_) => buf_len, | ||||
|             // timer_fut completed first. `select` gives us back the future that didn't complete, which | ||||
|             // is `recv_fut` in this case, so we can do further stuff with it. | ||||
|             // | ||||
|             // The recv_fut would stop the uart read automatically when dropped. However, we want to know how | ||||
|             // many bytes have been received, so we have to "gracefully stop" it with `.stop()`. | ||||
|             Either::Right((_, recv_fut)) => recv_fut.stop().await, | ||||
|         }; | ||||
|         let received = &mut buf[..received_len]; | ||||
|  | ||||
|         if !received.is_empty() { | ||||
|             info!("read done, got {}", received); | ||||
|  | ||||
|             // Echo back received data | ||||
|             unwrap!(uart.write(received).await); | ||||
|         } | ||||
|          */ | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -18,9 +18,7 @@ use embassy_nrf::gpio::NoPin; | ||||
| use embassy_nrf::{interrupt, uarte, Peripherals}; | ||||
|  | ||||
| #[embassy::main] | ||||
| async fn main(spawner: Spawner) { | ||||
|     let p = unsafe { Peripherals::steal() }; | ||||
|  | ||||
| async fn main(spawner: Spawner, p: Peripherals) { | ||||
|     let mut config = uarte::Config::default(); | ||||
|     config.parity = uarte::Parity::EXCLUDED; | ||||
|     config.baudrate = uarte::Baudrate::BAUD115200; | ||||
|   | ||||
| @@ -11,11 +11,13 @@ defmt-info = [ ] | ||||
| defmt-warn = [ ] | ||||
| defmt-error = [ ] | ||||
|  | ||||
| 52810 = ["nrf52810-pac"] | ||||
| 52811 = ["nrf52811-pac"] | ||||
| 52832 = ["nrf52832-pac"] | ||||
| 52833 = ["nrf52833-pac"] | ||||
| 52840 = ["nrf52840-pac"] | ||||
| nrf52805 = ["nrf52805-pac"] | ||||
| nrf52810 = ["nrf52810-pac"] | ||||
| nrf52811 = ["nrf52811-pac"] | ||||
| nrf52820 = ["nrf52820-pac"] | ||||
| nrf52832 = ["nrf52832-pac"] | ||||
| nrf52833 = ["nrf52833-pac"] | ||||
| nrf52840 = ["nrf52840-pac"] | ||||
|  | ||||
|  | ||||
| [dependencies] | ||||
| @@ -30,10 +32,12 @@ cortex-m = "0.7.1" | ||||
| embedded-hal    = { version = "0.2.4" } | ||||
| embedded-dma    = { version = "0.1.2" } | ||||
| futures     = { version = "0.3.5", default-features = false } | ||||
| critical-section = "0.2.1" | ||||
|  | ||||
| nrf52805-pac  = { version = "0.1.0", optional = true, features = [ "rt" ], git = "https://github.com/Dirbaio/nrf52805-pac"} | ||||
| nrf52810-pac  = { version = "0.9.0", optional = true, features = [ "rt" ]} | ||||
| nrf52811-pac  = { version = "0.9.1", optional = true, features = [ "rt" ]} | ||||
| nrf52820-pac  = { version = "0.1.0", optional = true, features = [ "rt" ], git = "https://github.com/Dirbaio/nrf52820-pac"} | ||||
| nrf52832-pac  = { version = "0.9.0", optional = true, features = [ "rt" ]} | ||||
| nrf52833-pac  = { version = "0.9.0", optional = true, features = [ "rt" ]} | ||||
| nrf52840-pac  = { version = "0.9.0", optional = true, features = [ "rt" ]} | ||||
| critical-section = "0.2.1" | ||||
|   | ||||
							
								
								
									
										181
									
								
								embassy-nrf/src/chips/nrf52805.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								embassy-nrf/src/chips/nrf52805.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,181 @@ | ||||
| pub use nrf52805_pac as pac; | ||||
|  | ||||
| pub const EASY_DMA_SIZE: usize = (1 << 14) - 1; | ||||
| pub const FORCE_COPY_BUFFER_SIZE: usize = 256; | ||||
|  | ||||
| embassy_extras::peripherals! { | ||||
|     // RTC | ||||
|     RTC0, | ||||
|     RTC1, | ||||
|  | ||||
|     // UARTE | ||||
|     UARTE0, | ||||
|  | ||||
|     // SPI/TWI | ||||
|     TWI0, | ||||
|     SPI0, | ||||
|  | ||||
|     // SAADC | ||||
|     SAADC, | ||||
|  | ||||
|     // TIMER | ||||
|     TIMER0, | ||||
|     TIMER1, | ||||
|     TIMER2, | ||||
|  | ||||
|     // GPIOTE | ||||
|     GPIOTE_CH0, | ||||
|     GPIOTE_CH1, | ||||
|     GPIOTE_CH2, | ||||
|     GPIOTE_CH3, | ||||
|     GPIOTE_CH4, | ||||
|     GPIOTE_CH5, | ||||
|     GPIOTE_CH6, | ||||
|     GPIOTE_CH7, | ||||
|  | ||||
|     // PPI | ||||
|     PPI_CH0, | ||||
|     PPI_CH1, | ||||
|     PPI_CH2, | ||||
|     PPI_CH3, | ||||
|     PPI_CH4, | ||||
|     PPI_CH5, | ||||
|     PPI_CH6, | ||||
|     PPI_CH7, | ||||
|     PPI_CH8, | ||||
|     PPI_CH9, | ||||
|     PPI_CH10, | ||||
|     PPI_CH11, | ||||
|     PPI_CH12, | ||||
|     PPI_CH13, | ||||
|     PPI_CH14, | ||||
|     PPI_CH15, | ||||
|     PPI_CH16, | ||||
|     PPI_CH17, | ||||
|     PPI_CH18, | ||||
|     PPI_CH19, | ||||
|     PPI_CH20, | ||||
|     PPI_CH21, | ||||
|     PPI_CH22, | ||||
|     PPI_CH23, | ||||
|     PPI_CH24, | ||||
|     PPI_CH25, | ||||
|     PPI_CH26, | ||||
|     PPI_CH27, | ||||
|     PPI_CH28, | ||||
|     PPI_CH29, | ||||
|     PPI_CH30, | ||||
|     PPI_CH31, | ||||
|  | ||||
|     PPI_GROUP0, | ||||
|     PPI_GROUP1, | ||||
|     PPI_GROUP2, | ||||
|     PPI_GROUP3, | ||||
|     PPI_GROUP4, | ||||
|     PPI_GROUP5, | ||||
|  | ||||
|     // GPIO port 0 | ||||
|     P0_00, | ||||
|     P0_01, | ||||
|     P0_02, | ||||
|     P0_03, | ||||
|     P0_04, | ||||
|     P0_05, | ||||
|     P0_06, | ||||
|     P0_07, | ||||
|     P0_08, | ||||
|     P0_09, | ||||
|     P0_10, | ||||
|     P0_11, | ||||
|     P0_12, | ||||
|     P0_13, | ||||
|     P0_14, | ||||
|     P0_15, | ||||
|     P0_16, | ||||
|     P0_17, | ||||
|     P0_18, | ||||
|     P0_19, | ||||
|     P0_20, | ||||
|     P0_21, | ||||
|     P0_22, | ||||
|     P0_23, | ||||
|     P0_24, | ||||
|     P0_25, | ||||
|     P0_26, | ||||
|     P0_27, | ||||
|     P0_28, | ||||
|     P0_29, | ||||
|     P0_30, | ||||
|     P0_31, | ||||
| } | ||||
|  | ||||
| impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); | ||||
|  | ||||
| impl_spim!(SPI0, SPIM0, SPIM0_SPIS0_SPI0); | ||||
|  | ||||
| impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0); | ||||
|  | ||||
| impl_timer!(TIMER0, TIMER0, TIMER0); | ||||
| impl_timer!(TIMER1, TIMER1, TIMER1); | ||||
| impl_timer!(TIMER2, TIMER2, TIMER2); | ||||
|  | ||||
| impl_pin!(P0_00, 0, 0); | ||||
| impl_pin!(P0_01, 0, 1); | ||||
| impl_pin!(P0_02, 0, 2); | ||||
| impl_pin!(P0_03, 0, 3); | ||||
| impl_pin!(P0_04, 0, 4); | ||||
| impl_pin!(P0_05, 0, 5); | ||||
| impl_pin!(P0_06, 0, 6); | ||||
| impl_pin!(P0_07, 0, 7); | ||||
| impl_pin!(P0_08, 0, 8); | ||||
| impl_pin!(P0_09, 0, 9); | ||||
| impl_pin!(P0_10, 0, 10); | ||||
| impl_pin!(P0_11, 0, 11); | ||||
| impl_pin!(P0_12, 0, 12); | ||||
| impl_pin!(P0_13, 0, 13); | ||||
| impl_pin!(P0_14, 0, 14); | ||||
| impl_pin!(P0_15, 0, 15); | ||||
| impl_pin!(P0_16, 0, 16); | ||||
| impl_pin!(P0_17, 0, 17); | ||||
| impl_pin!(P0_18, 0, 18); | ||||
| impl_pin!(P0_19, 0, 19); | ||||
| impl_pin!(P0_20, 0, 20); | ||||
| impl_pin!(P0_21, 0, 21); | ||||
| impl_pin!(P0_22, 0, 22); | ||||
| impl_pin!(P0_23, 0, 23); | ||||
| impl_pin!(P0_24, 0, 24); | ||||
| impl_pin!(P0_25, 0, 25); | ||||
| impl_pin!(P0_26, 0, 26); | ||||
| impl_pin!(P0_27, 0, 27); | ||||
| impl_pin!(P0_28, 0, 28); | ||||
| impl_pin!(P0_29, 0, 29); | ||||
| impl_pin!(P0_30, 0, 30); | ||||
| impl_pin!(P0_31, 0, 31); | ||||
|  | ||||
| pub mod irqs { | ||||
|     use embassy_macros::interrupt_declare as declare; | ||||
|     declare!(POWER_CLOCK); | ||||
|     declare!(RADIO); | ||||
|     declare!(UARTE0_UART0); | ||||
|     declare!(TWIM0_TWIS0_TWI0); | ||||
|     declare!(SPIM0_SPIS0_SPI0); | ||||
|     declare!(GPIOTE); | ||||
|     declare!(SAADC); | ||||
|     declare!(TIMER0); | ||||
|     declare!(TIMER1); | ||||
|     declare!(TIMER2); | ||||
|     declare!(RTC0); | ||||
|     declare!(TEMP); | ||||
|     declare!(RNG); | ||||
|     declare!(ECB); | ||||
|     declare!(CCM_AAR); | ||||
|     declare!(WDT); | ||||
|     declare!(RTC1); | ||||
|     declare!(QDEC); | ||||
|     declare!(SWI0_EGU0); | ||||
|     declare!(SWI1_EGU1); | ||||
|     declare!(SWI2); | ||||
|     declare!(SWI3); | ||||
|     declare!(SWI4); | ||||
|     declare!(SWI5); | ||||
| } | ||||
							
								
								
									
										189
									
								
								embassy-nrf/src/chips/nrf52810.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								embassy-nrf/src/chips/nrf52810.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,189 @@ | ||||
| pub use nrf52810_pac as pac; | ||||
|  | ||||
| pub const EASY_DMA_SIZE: usize = (1 << 10) - 1; | ||||
| pub const FORCE_COPY_BUFFER_SIZE: usize = 256; | ||||
|  | ||||
| embassy_extras::peripherals! { | ||||
|     // RTC | ||||
|     RTC0, | ||||
|     RTC1, | ||||
|  | ||||
|     // UARTE | ||||
|     UARTE0, | ||||
|  | ||||
|     // SPI/TWI | ||||
|     TWI0, | ||||
|     SPI0, | ||||
|  | ||||
|     // SAADC | ||||
|     SAADC, | ||||
|  | ||||
|     // PWM | ||||
|     PWM0, | ||||
|  | ||||
|     // TIMER | ||||
|     TIMER0, | ||||
|     TIMER1, | ||||
|     TIMER2, | ||||
|  | ||||
|     // GPIOTE | ||||
|     GPIOTE_CH0, | ||||
|     GPIOTE_CH1, | ||||
|     GPIOTE_CH2, | ||||
|     GPIOTE_CH3, | ||||
|     GPIOTE_CH4, | ||||
|     GPIOTE_CH5, | ||||
|     GPIOTE_CH6, | ||||
|     GPIOTE_CH7, | ||||
|  | ||||
|     // PPI | ||||
|     PPI_CH0, | ||||
|     PPI_CH1, | ||||
|     PPI_CH2, | ||||
|     PPI_CH3, | ||||
|     PPI_CH4, | ||||
|     PPI_CH5, | ||||
|     PPI_CH6, | ||||
|     PPI_CH7, | ||||
|     PPI_CH8, | ||||
|     PPI_CH9, | ||||
|     PPI_CH10, | ||||
|     PPI_CH11, | ||||
|     PPI_CH12, | ||||
|     PPI_CH13, | ||||
|     PPI_CH14, | ||||
|     PPI_CH15, | ||||
|     PPI_CH16, | ||||
|     PPI_CH17, | ||||
|     PPI_CH18, | ||||
|     PPI_CH19, | ||||
|     PPI_CH20, | ||||
|     PPI_CH21, | ||||
|     PPI_CH22, | ||||
|     PPI_CH23, | ||||
|     PPI_CH24, | ||||
|     PPI_CH25, | ||||
|     PPI_CH26, | ||||
|     PPI_CH27, | ||||
|     PPI_CH28, | ||||
|     PPI_CH29, | ||||
|     PPI_CH30, | ||||
|     PPI_CH31, | ||||
|  | ||||
|     PPI_GROUP0, | ||||
|     PPI_GROUP1, | ||||
|     PPI_GROUP2, | ||||
|     PPI_GROUP3, | ||||
|     PPI_GROUP4, | ||||
|     PPI_GROUP5, | ||||
|  | ||||
|     // GPIO port 0 | ||||
|     P0_00, | ||||
|     P0_01, | ||||
|     P0_02, | ||||
|     P0_03, | ||||
|     P0_04, | ||||
|     P0_05, | ||||
|     P0_06, | ||||
|     P0_07, | ||||
|     P0_08, | ||||
|     P0_09, | ||||
|     P0_10, | ||||
|     P0_11, | ||||
|     P0_12, | ||||
|     P0_13, | ||||
|     P0_14, | ||||
|     P0_15, | ||||
|     P0_16, | ||||
|     P0_17, | ||||
|     P0_18, | ||||
|     P0_19, | ||||
|     P0_20, | ||||
|     P0_21, | ||||
|     P0_22, | ||||
|     P0_23, | ||||
|     P0_24, | ||||
|     P0_25, | ||||
|     P0_26, | ||||
|     P0_27, | ||||
|     P0_28, | ||||
|     P0_29, | ||||
|     P0_30, | ||||
|     P0_31, | ||||
| } | ||||
|  | ||||
| impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); | ||||
|  | ||||
| impl_spim!(SPI0, SPIM0, SPIM0_SPIS0_SPI0); | ||||
|  | ||||
| impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0); | ||||
|  | ||||
| impl_pwm!(PWM0, PWM0, PWM0); | ||||
|  | ||||
| impl_timer!(TIMER0, TIMER0, TIMER0); | ||||
| impl_timer!(TIMER1, TIMER1, TIMER1); | ||||
| impl_timer!(TIMER2, TIMER2, TIMER2); | ||||
|  | ||||
| impl_pin!(P0_00, 0, 0); | ||||
| impl_pin!(P0_01, 0, 1); | ||||
| impl_pin!(P0_02, 0, 2); | ||||
| impl_pin!(P0_03, 0, 3); | ||||
| impl_pin!(P0_04, 0, 4); | ||||
| impl_pin!(P0_05, 0, 5); | ||||
| impl_pin!(P0_06, 0, 6); | ||||
| impl_pin!(P0_07, 0, 7); | ||||
| impl_pin!(P0_08, 0, 8); | ||||
| impl_pin!(P0_09, 0, 9); | ||||
| impl_pin!(P0_10, 0, 10); | ||||
| impl_pin!(P0_11, 0, 11); | ||||
| impl_pin!(P0_12, 0, 12); | ||||
| impl_pin!(P0_13, 0, 13); | ||||
| impl_pin!(P0_14, 0, 14); | ||||
| impl_pin!(P0_15, 0, 15); | ||||
| impl_pin!(P0_16, 0, 16); | ||||
| impl_pin!(P0_17, 0, 17); | ||||
| impl_pin!(P0_18, 0, 18); | ||||
| impl_pin!(P0_19, 0, 19); | ||||
| impl_pin!(P0_20, 0, 20); | ||||
| impl_pin!(P0_21, 0, 21); | ||||
| impl_pin!(P0_22, 0, 22); | ||||
| impl_pin!(P0_23, 0, 23); | ||||
| impl_pin!(P0_24, 0, 24); | ||||
| impl_pin!(P0_25, 0, 25); | ||||
| impl_pin!(P0_26, 0, 26); | ||||
| impl_pin!(P0_27, 0, 27); | ||||
| impl_pin!(P0_28, 0, 28); | ||||
| impl_pin!(P0_29, 0, 29); | ||||
| impl_pin!(P0_30, 0, 30); | ||||
| impl_pin!(P0_31, 0, 31); | ||||
|  | ||||
| pub mod irqs { | ||||
|     use embassy_macros::interrupt_declare as declare; | ||||
|     declare!(POWER_CLOCK); | ||||
|     declare!(RADIO); | ||||
|     declare!(UARTE0_UART0); | ||||
|     declare!(TWIM0_TWIS0_TWI0); | ||||
|     declare!(SPIM0_SPIS0_SPI0); | ||||
|     declare!(GPIOTE); | ||||
|     declare!(SAADC); | ||||
|     declare!(TIMER0); | ||||
|     declare!(TIMER1); | ||||
|     declare!(TIMER2); | ||||
|     declare!(RTC0); | ||||
|     declare!(TEMP); | ||||
|     declare!(RNG); | ||||
|     declare!(ECB); | ||||
|     declare!(CCM_AAR); | ||||
|     declare!(WDT); | ||||
|     declare!(RTC1); | ||||
|     declare!(QDEC); | ||||
|     declare!(COMP); | ||||
|     declare!(SWI0_EGU0); | ||||
|     declare!(SWI1_EGU1); | ||||
|     declare!(SWI2); | ||||
|     declare!(SWI3); | ||||
|     declare!(SWI4); | ||||
|     declare!(SWI5); | ||||
|     declare!(PWM0); | ||||
|     declare!(PDM); | ||||
| } | ||||
							
								
								
									
										190
									
								
								embassy-nrf/src/chips/nrf52811.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										190
									
								
								embassy-nrf/src/chips/nrf52811.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,190 @@ | ||||
| pub use nrf52811_pac as pac; | ||||
|  | ||||
| pub const EASY_DMA_SIZE: usize = (1 << 14) - 1; | ||||
| pub const FORCE_COPY_BUFFER_SIZE: usize = 256; | ||||
|  | ||||
| embassy_extras::peripherals! { | ||||
|     // RTC | ||||
|     RTC0, | ||||
|     RTC1, | ||||
|  | ||||
|     // UARTE | ||||
|     UARTE0, | ||||
|  | ||||
|     // SPI/TWI | ||||
|     TWISPI0, | ||||
|     SPI1, | ||||
|  | ||||
|     // SAADC | ||||
|     SAADC, | ||||
|  | ||||
|     // PWM | ||||
|     PWM0, | ||||
|  | ||||
|     // TIMER | ||||
|     TIMER0, | ||||
|     TIMER1, | ||||
|     TIMER2, | ||||
|  | ||||
|     // GPIOTE | ||||
|     GPIOTE_CH0, | ||||
|     GPIOTE_CH1, | ||||
|     GPIOTE_CH2, | ||||
|     GPIOTE_CH3, | ||||
|     GPIOTE_CH4, | ||||
|     GPIOTE_CH5, | ||||
|     GPIOTE_CH6, | ||||
|     GPIOTE_CH7, | ||||
|  | ||||
|     // PPI | ||||
|     PPI_CH0, | ||||
|     PPI_CH1, | ||||
|     PPI_CH2, | ||||
|     PPI_CH3, | ||||
|     PPI_CH4, | ||||
|     PPI_CH5, | ||||
|     PPI_CH6, | ||||
|     PPI_CH7, | ||||
|     PPI_CH8, | ||||
|     PPI_CH9, | ||||
|     PPI_CH10, | ||||
|     PPI_CH11, | ||||
|     PPI_CH12, | ||||
|     PPI_CH13, | ||||
|     PPI_CH14, | ||||
|     PPI_CH15, | ||||
|     PPI_CH16, | ||||
|     PPI_CH17, | ||||
|     PPI_CH18, | ||||
|     PPI_CH19, | ||||
|     PPI_CH20, | ||||
|     PPI_CH21, | ||||
|     PPI_CH22, | ||||
|     PPI_CH23, | ||||
|     PPI_CH24, | ||||
|     PPI_CH25, | ||||
|     PPI_CH26, | ||||
|     PPI_CH27, | ||||
|     PPI_CH28, | ||||
|     PPI_CH29, | ||||
|     PPI_CH30, | ||||
|     PPI_CH31, | ||||
|  | ||||
|     PPI_GROUP0, | ||||
|     PPI_GROUP1, | ||||
|     PPI_GROUP2, | ||||
|     PPI_GROUP3, | ||||
|     PPI_GROUP4, | ||||
|     PPI_GROUP5, | ||||
|  | ||||
|     // GPIO port 0 | ||||
|     P0_00, | ||||
|     P0_01, | ||||
|     P0_02, | ||||
|     P0_03, | ||||
|     P0_04, | ||||
|     P0_05, | ||||
|     P0_06, | ||||
|     P0_07, | ||||
|     P0_08, | ||||
|     P0_09, | ||||
|     P0_10, | ||||
|     P0_11, | ||||
|     P0_12, | ||||
|     P0_13, | ||||
|     P0_14, | ||||
|     P0_15, | ||||
|     P0_16, | ||||
|     P0_17, | ||||
|     P0_18, | ||||
|     P0_19, | ||||
|     P0_20, | ||||
|     P0_21, | ||||
|     P0_22, | ||||
|     P0_23, | ||||
|     P0_24, | ||||
|     P0_25, | ||||
|     P0_26, | ||||
|     P0_27, | ||||
|     P0_28, | ||||
|     P0_29, | ||||
|     P0_30, | ||||
|     P0_31, | ||||
| } | ||||
|  | ||||
| impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); | ||||
|  | ||||
| impl_spim!(TWISPI0, SPIM0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0); | ||||
| impl_spim!(SPI1, SPIM1, SPIM1_SPIS1_SPI1); | ||||
|  | ||||
| impl_twim!(TWISPI0, TWIM0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0); | ||||
|  | ||||
| impl_pwm!(PWM0, PWM0, PWM0); | ||||
|  | ||||
| impl_timer!(TIMER0, TIMER0, TIMER0); | ||||
| impl_timer!(TIMER1, TIMER1, TIMER1); | ||||
| impl_timer!(TIMER2, TIMER2, TIMER2); | ||||
|  | ||||
| impl_pin!(P0_00, 0, 0); | ||||
| impl_pin!(P0_01, 0, 1); | ||||
| impl_pin!(P0_02, 0, 2); | ||||
| impl_pin!(P0_03, 0, 3); | ||||
| impl_pin!(P0_04, 0, 4); | ||||
| impl_pin!(P0_05, 0, 5); | ||||
| impl_pin!(P0_06, 0, 6); | ||||
| impl_pin!(P0_07, 0, 7); | ||||
| impl_pin!(P0_08, 0, 8); | ||||
| impl_pin!(P0_09, 0, 9); | ||||
| impl_pin!(P0_10, 0, 10); | ||||
| impl_pin!(P0_11, 0, 11); | ||||
| impl_pin!(P0_12, 0, 12); | ||||
| impl_pin!(P0_13, 0, 13); | ||||
| impl_pin!(P0_14, 0, 14); | ||||
| impl_pin!(P0_15, 0, 15); | ||||
| impl_pin!(P0_16, 0, 16); | ||||
| impl_pin!(P0_17, 0, 17); | ||||
| impl_pin!(P0_18, 0, 18); | ||||
| impl_pin!(P0_19, 0, 19); | ||||
| impl_pin!(P0_20, 0, 20); | ||||
| impl_pin!(P0_21, 0, 21); | ||||
| impl_pin!(P0_22, 0, 22); | ||||
| impl_pin!(P0_23, 0, 23); | ||||
| impl_pin!(P0_24, 0, 24); | ||||
| impl_pin!(P0_25, 0, 25); | ||||
| impl_pin!(P0_26, 0, 26); | ||||
| impl_pin!(P0_27, 0, 27); | ||||
| impl_pin!(P0_28, 0, 28); | ||||
| impl_pin!(P0_29, 0, 29); | ||||
| impl_pin!(P0_30, 0, 30); | ||||
| impl_pin!(P0_31, 0, 31); | ||||
|  | ||||
| pub mod irqs { | ||||
|     use embassy_macros::interrupt_declare as declare; | ||||
|     declare!(POWER_CLOCK); | ||||
|     declare!(RADIO); | ||||
|     declare!(UARTE0_UART0); | ||||
|     declare!(TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0); | ||||
|     declare!(SPIM1_SPIS1_SPI1); | ||||
|     declare!(GPIOTE); | ||||
|     declare!(SAADC); | ||||
|     declare!(TIMER0); | ||||
|     declare!(TIMER1); | ||||
|     declare!(TIMER2); | ||||
|     declare!(RTC0); | ||||
|     declare!(TEMP); | ||||
|     declare!(RNG); | ||||
|     declare!(ECB); | ||||
|     declare!(CCM_AAR); | ||||
|     declare!(WDT); | ||||
|     declare!(RTC1); | ||||
|     declare!(QDEC); | ||||
|     declare!(COMP); | ||||
|     declare!(SWI0_EGU0); | ||||
|     declare!(SWI1_EGU1); | ||||
|     declare!(SWI2); | ||||
|     declare!(SWI3); | ||||
|     declare!(SWI4); | ||||
|     declare!(SWI5); | ||||
|     declare!(PWM0); | ||||
|     declare!(PDM); | ||||
| } | ||||
							
								
								
									
										187
									
								
								embassy-nrf/src/chips/nrf52820.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								embassy-nrf/src/chips/nrf52820.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,187 @@ | ||||
| pub use nrf52820_pac as pac; | ||||
|  | ||||
| pub const EASY_DMA_SIZE: usize = (1 << 15) - 1; | ||||
| pub const FORCE_COPY_BUFFER_SIZE: usize = 512; | ||||
|  | ||||
| embassy_extras::peripherals! { | ||||
|     // RTC | ||||
|     RTC0, | ||||
|     RTC1, | ||||
|  | ||||
|     // UARTE | ||||
|     UARTE0, | ||||
|  | ||||
|     // SPI/TWI | ||||
|     TWISPI0, | ||||
|     TWISPI1, | ||||
|  | ||||
|     // SAADC | ||||
|     SAADC, | ||||
|  | ||||
|     // TIMER | ||||
|     TIMER0, | ||||
|     TIMER1, | ||||
|     TIMER2, | ||||
|     TIMER3, | ||||
|  | ||||
|     // GPIOTE | ||||
|     GPIOTE_CH0, | ||||
|     GPIOTE_CH1, | ||||
|     GPIOTE_CH2, | ||||
|     GPIOTE_CH3, | ||||
|     GPIOTE_CH4, | ||||
|     GPIOTE_CH5, | ||||
|     GPIOTE_CH6, | ||||
|     GPIOTE_CH7, | ||||
|  | ||||
|     // PPI | ||||
|     PPI_CH0, | ||||
|     PPI_CH1, | ||||
|     PPI_CH2, | ||||
|     PPI_CH3, | ||||
|     PPI_CH4, | ||||
|     PPI_CH5, | ||||
|     PPI_CH6, | ||||
|     PPI_CH7, | ||||
|     PPI_CH8, | ||||
|     PPI_CH9, | ||||
|     PPI_CH10, | ||||
|     PPI_CH11, | ||||
|     PPI_CH12, | ||||
|     PPI_CH13, | ||||
|     PPI_CH14, | ||||
|     PPI_CH15, | ||||
|     PPI_CH16, | ||||
|     PPI_CH17, | ||||
|     PPI_CH18, | ||||
|     PPI_CH19, | ||||
|     PPI_CH20, | ||||
|     PPI_CH21, | ||||
|     PPI_CH22, | ||||
|     PPI_CH23, | ||||
|     PPI_CH24, | ||||
|     PPI_CH25, | ||||
|     PPI_CH26, | ||||
|     PPI_CH27, | ||||
|     PPI_CH28, | ||||
|     PPI_CH29, | ||||
|     PPI_CH30, | ||||
|     PPI_CH31, | ||||
|  | ||||
|     PPI_GROUP0, | ||||
|     PPI_GROUP1, | ||||
|     PPI_GROUP2, | ||||
|     PPI_GROUP3, | ||||
|     PPI_GROUP4, | ||||
|     PPI_GROUP5, | ||||
|  | ||||
|     // GPIO port 0 | ||||
|     P0_00, | ||||
|     P0_01, | ||||
|     P0_02, | ||||
|     P0_03, | ||||
|     P0_04, | ||||
|     P0_05, | ||||
|     P0_06, | ||||
|     P0_07, | ||||
|     P0_08, | ||||
|     P0_09, | ||||
|     P0_10, | ||||
|     P0_11, | ||||
|     P0_12, | ||||
|     P0_13, | ||||
|     P0_14, | ||||
|     P0_15, | ||||
|     P0_16, | ||||
|     P0_17, | ||||
|     P0_18, | ||||
|     P0_19, | ||||
|     P0_20, | ||||
|     P0_21, | ||||
|     P0_22, | ||||
|     P0_23, | ||||
|     P0_24, | ||||
|     P0_25, | ||||
|     P0_26, | ||||
|     P0_27, | ||||
|     P0_28, | ||||
|     P0_29, | ||||
|     P0_30, | ||||
|     P0_31, | ||||
| } | ||||
|  | ||||
| impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); | ||||
|  | ||||
| impl_spim!(TWISPI0, SPIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||||
| impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||||
|  | ||||
| impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||||
| impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||||
|  | ||||
| impl_timer!(TIMER0, TIMER0, TIMER0); | ||||
| impl_timer!(TIMER1, TIMER1, TIMER1); | ||||
| impl_timer!(TIMER2, TIMER2, TIMER2); | ||||
| impl_timer!(TIMER3, TIMER3, TIMER3, extended); | ||||
|  | ||||
| impl_pin!(P0_00, 0, 0); | ||||
| impl_pin!(P0_01, 0, 1); | ||||
| impl_pin!(P0_02, 0, 2); | ||||
| impl_pin!(P0_03, 0, 3); | ||||
| impl_pin!(P0_04, 0, 4); | ||||
| impl_pin!(P0_05, 0, 5); | ||||
| impl_pin!(P0_06, 0, 6); | ||||
| impl_pin!(P0_07, 0, 7); | ||||
| impl_pin!(P0_08, 0, 8); | ||||
| impl_pin!(P0_09, 0, 9); | ||||
| impl_pin!(P0_10, 0, 10); | ||||
| impl_pin!(P0_11, 0, 11); | ||||
| impl_pin!(P0_12, 0, 12); | ||||
| impl_pin!(P0_13, 0, 13); | ||||
| impl_pin!(P0_14, 0, 14); | ||||
| impl_pin!(P0_15, 0, 15); | ||||
| impl_pin!(P0_16, 0, 16); | ||||
| impl_pin!(P0_17, 0, 17); | ||||
| impl_pin!(P0_18, 0, 18); | ||||
| impl_pin!(P0_19, 0, 19); | ||||
| impl_pin!(P0_20, 0, 20); | ||||
| impl_pin!(P0_21, 0, 21); | ||||
| impl_pin!(P0_22, 0, 22); | ||||
| impl_pin!(P0_23, 0, 23); | ||||
| impl_pin!(P0_24, 0, 24); | ||||
| impl_pin!(P0_25, 0, 25); | ||||
| impl_pin!(P0_26, 0, 26); | ||||
| impl_pin!(P0_27, 0, 27); | ||||
| impl_pin!(P0_28, 0, 28); | ||||
| impl_pin!(P0_29, 0, 29); | ||||
| impl_pin!(P0_30, 0, 30); | ||||
| impl_pin!(P0_31, 0, 31); | ||||
|  | ||||
| pub mod irqs { | ||||
|     use embassy_macros::interrupt_declare as declare; | ||||
|     declare!(POWER_CLOCK); | ||||
|     declare!(RADIO); | ||||
|     declare!(UARTE0_UART0); | ||||
|     declare!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||||
|     declare!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||||
|     declare!(GPIOTE); | ||||
|     declare!(TIMER0); | ||||
|     declare!(TIMER1); | ||||
|     declare!(TIMER2); | ||||
|     declare!(RTC0); | ||||
|     declare!(TEMP); | ||||
|     declare!(RNG); | ||||
|     declare!(ECB); | ||||
|     declare!(CCM_AAR); | ||||
|     declare!(WDT); | ||||
|     declare!(RTC1); | ||||
|     declare!(QDEC); | ||||
|     declare!(COMP); | ||||
|     declare!(SWI0_EGU0); | ||||
|     declare!(SWI1_EGU1); | ||||
|     declare!(SWI2_EGU2); | ||||
|     declare!(SWI3_EGU3); | ||||
|     declare!(SWI4_EGU4); | ||||
|     declare!(SWI5_EGU5); | ||||
|     declare!(TIMER3); | ||||
|     declare!(USBD); | ||||
| } | ||||
							
								
								
									
										213
									
								
								embassy-nrf/src/chips/nrf52832.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										213
									
								
								embassy-nrf/src/chips/nrf52832.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,213 @@ | ||||
| pub use nrf52832_pac as pac; | ||||
|  | ||||
| pub const EASY_DMA_SIZE: usize = (1 << 8) - 1; | ||||
| pub const FORCE_COPY_BUFFER_SIZE: usize = 255; | ||||
|  | ||||
| embassy_extras::peripherals! { | ||||
|     // RTC | ||||
|     RTC0, | ||||
|     RTC1, | ||||
|     RTC2, | ||||
|  | ||||
|     // UARTE | ||||
|     UARTE0, | ||||
|  | ||||
|     // SPI/TWI | ||||
|     TWISPI0, | ||||
|     TWISPI1, | ||||
|     SPI2, | ||||
|     SPI3, | ||||
|  | ||||
|     // SAADC | ||||
|     SAADC, | ||||
|  | ||||
|     // PWM | ||||
|     PWM0, | ||||
|     PWM1, | ||||
|     PWM2, | ||||
|  | ||||
|     // TIMER | ||||
|     TIMER0, | ||||
|     TIMER1, | ||||
|     TIMER2, | ||||
|     TIMER3, | ||||
|     TIMER4, | ||||
|  | ||||
|     // GPIOTE | ||||
|     GPIOTE_CH0, | ||||
|     GPIOTE_CH1, | ||||
|     GPIOTE_CH2, | ||||
|     GPIOTE_CH3, | ||||
|     GPIOTE_CH4, | ||||
|     GPIOTE_CH5, | ||||
|     GPIOTE_CH6, | ||||
|     GPIOTE_CH7, | ||||
|  | ||||
|     // PPI | ||||
|     PPI_CH0, | ||||
|     PPI_CH1, | ||||
|     PPI_CH2, | ||||
|     PPI_CH3, | ||||
|     PPI_CH4, | ||||
|     PPI_CH5, | ||||
|     PPI_CH6, | ||||
|     PPI_CH7, | ||||
|     PPI_CH8, | ||||
|     PPI_CH9, | ||||
|     PPI_CH10, | ||||
|     PPI_CH11, | ||||
|     PPI_CH12, | ||||
|     PPI_CH13, | ||||
|     PPI_CH14, | ||||
|     PPI_CH15, | ||||
|     PPI_CH16, | ||||
|     PPI_CH17, | ||||
|     PPI_CH18, | ||||
|     PPI_CH19, | ||||
|     PPI_CH20, | ||||
|     PPI_CH21, | ||||
|     PPI_CH22, | ||||
|     PPI_CH23, | ||||
|     PPI_CH24, | ||||
|     PPI_CH25, | ||||
|     PPI_CH26, | ||||
|     PPI_CH27, | ||||
|     PPI_CH28, | ||||
|     PPI_CH29, | ||||
|     PPI_CH30, | ||||
|     PPI_CH31, | ||||
|  | ||||
|     PPI_GROUP0, | ||||
|     PPI_GROUP1, | ||||
|     PPI_GROUP2, | ||||
|     PPI_GROUP3, | ||||
|     PPI_GROUP4, | ||||
|     PPI_GROUP5, | ||||
|  | ||||
|     // GPIO port 0 | ||||
|     P0_00, | ||||
|     P0_01, | ||||
|     P0_02, | ||||
|     P0_03, | ||||
|     P0_04, | ||||
|     P0_05, | ||||
|     P0_06, | ||||
|     P0_07, | ||||
|     P0_08, | ||||
|     P0_09, | ||||
|     P0_10, | ||||
|     P0_11, | ||||
|     P0_12, | ||||
|     P0_13, | ||||
|     P0_14, | ||||
|     P0_15, | ||||
|     P0_16, | ||||
|     P0_17, | ||||
|     P0_18, | ||||
|     P0_19, | ||||
|     P0_20, | ||||
|     P0_21, | ||||
|     P0_22, | ||||
|     P0_23, | ||||
|     P0_24, | ||||
|     P0_25, | ||||
|     P0_26, | ||||
|     P0_27, | ||||
|     P0_28, | ||||
|     P0_29, | ||||
|     P0_30, | ||||
|     P0_31, | ||||
| } | ||||
|  | ||||
| impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); | ||||
|  | ||||
| impl_spim!(TWISPI0, SPIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||||
| impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||||
| impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2); | ||||
|  | ||||
| impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||||
| impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||||
|  | ||||
| impl_pwm!(PWM0, PWM0, PWM0); | ||||
| impl_pwm!(PWM1, PWM1, PWM1); | ||||
| impl_pwm!(PWM2, PWM2, PWM2); | ||||
|  | ||||
| impl_timer!(TIMER0, TIMER0, TIMER0); | ||||
| impl_timer!(TIMER1, TIMER1, TIMER1); | ||||
| impl_timer!(TIMER2, TIMER2, TIMER2); | ||||
| impl_timer!(TIMER3, TIMER3, TIMER3, extended); | ||||
| impl_timer!(TIMER4, TIMER4, TIMER4, extended); | ||||
|  | ||||
| impl_pin!(P0_00, 0, 0); | ||||
| impl_pin!(P0_01, 0, 1); | ||||
| impl_pin!(P0_02, 0, 2); | ||||
| impl_pin!(P0_03, 0, 3); | ||||
| impl_pin!(P0_04, 0, 4); | ||||
| impl_pin!(P0_05, 0, 5); | ||||
| impl_pin!(P0_06, 0, 6); | ||||
| impl_pin!(P0_07, 0, 7); | ||||
| impl_pin!(P0_08, 0, 8); | ||||
| impl_pin!(P0_09, 0, 9); | ||||
| impl_pin!(P0_10, 0, 10); | ||||
| impl_pin!(P0_11, 0, 11); | ||||
| impl_pin!(P0_12, 0, 12); | ||||
| impl_pin!(P0_13, 0, 13); | ||||
| impl_pin!(P0_14, 0, 14); | ||||
| impl_pin!(P0_15, 0, 15); | ||||
| impl_pin!(P0_16, 0, 16); | ||||
| impl_pin!(P0_17, 0, 17); | ||||
| impl_pin!(P0_18, 0, 18); | ||||
| impl_pin!(P0_19, 0, 19); | ||||
| impl_pin!(P0_20, 0, 20); | ||||
| impl_pin!(P0_21, 0, 21); | ||||
| impl_pin!(P0_22, 0, 22); | ||||
| impl_pin!(P0_23, 0, 23); | ||||
| impl_pin!(P0_24, 0, 24); | ||||
| impl_pin!(P0_25, 0, 25); | ||||
| impl_pin!(P0_26, 0, 26); | ||||
| impl_pin!(P0_27, 0, 27); | ||||
| impl_pin!(P0_28, 0, 28); | ||||
| impl_pin!(P0_29, 0, 29); | ||||
| impl_pin!(P0_30, 0, 30); | ||||
| impl_pin!(P0_31, 0, 31); | ||||
|  | ||||
| pub mod irqs { | ||||
|     use embassy_macros::interrupt_declare as declare; | ||||
|     declare!(POWER_CLOCK); | ||||
|     declare!(RADIO); | ||||
|     declare!(UARTE0_UART0); | ||||
|     declare!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||||
|     declare!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||||
|     declare!(NFCT); | ||||
|     declare!(GPIOTE); | ||||
|     declare!(SAADC); | ||||
|     declare!(TIMER0); | ||||
|     declare!(TIMER1); | ||||
|     declare!(TIMER2); | ||||
|     declare!(RTC0); | ||||
|     declare!(TEMP); | ||||
|     declare!(RNG); | ||||
|     declare!(ECB); | ||||
|     declare!(CCM_AAR); | ||||
|     declare!(WDT); | ||||
|     declare!(RTC1); | ||||
|     declare!(QDEC); | ||||
|     declare!(COMP_LPCOMP); | ||||
|     declare!(SWI0_EGU0); | ||||
|     declare!(SWI1_EGU1); | ||||
|     declare!(SWI2_EGU2); | ||||
|     declare!(SWI3_EGU3); | ||||
|     declare!(SWI4_EGU4); | ||||
|     declare!(SWI5_EGU5); | ||||
|     declare!(TIMER3); | ||||
|     declare!(TIMER4); | ||||
|     declare!(PWM0); | ||||
|     declare!(PDM); | ||||
|     declare!(MWU); | ||||
|     declare!(PWM1); | ||||
|     declare!(PWM2); | ||||
|     declare!(SPIM2_SPIS2_SPI2); | ||||
|     declare!(RTC2); | ||||
|     declare!(I2S); | ||||
|     declare!(FPU); | ||||
| } | ||||
							
								
								
									
										257
									
								
								embassy-nrf/src/chips/nrf52833.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										257
									
								
								embassy-nrf/src/chips/nrf52833.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,257 @@ | ||||
| pub use nrf52833_pac as pac; | ||||
|  | ||||
| pub const EASY_DMA_SIZE: usize = (1 << 16) - 1; | ||||
| pub const FORCE_COPY_BUFFER_SIZE: usize = 512; | ||||
|  | ||||
| embassy_extras::peripherals! { | ||||
|     // RTC | ||||
|     RTC0, | ||||
|     RTC1, | ||||
|     RTC2, | ||||
|  | ||||
|     // UARTE | ||||
|     UARTE0, | ||||
|     UARTE1, | ||||
|  | ||||
|     // SPI/TWI | ||||
|     TWISPI0, | ||||
|     TWISPI1, | ||||
|     SPI2, | ||||
|     SPI3, | ||||
|  | ||||
|     // SAADC | ||||
|     SAADC, | ||||
|  | ||||
|     // PWM | ||||
|     PWM0, | ||||
|     PWM1, | ||||
|     PWM2, | ||||
|     PWM3, | ||||
|  | ||||
|     // TIMER | ||||
|     TIMER0, | ||||
|     TIMER1, | ||||
|     TIMER2, | ||||
|     TIMER3, | ||||
|     TIMER4, | ||||
|  | ||||
|     // GPIOTE | ||||
|     GPIOTE_CH0, | ||||
|     GPIOTE_CH1, | ||||
|     GPIOTE_CH2, | ||||
|     GPIOTE_CH3, | ||||
|     GPIOTE_CH4, | ||||
|     GPIOTE_CH5, | ||||
|     GPIOTE_CH6, | ||||
|     GPIOTE_CH7, | ||||
|  | ||||
|     // PPI | ||||
|     PPI_CH0, | ||||
|     PPI_CH1, | ||||
|     PPI_CH2, | ||||
|     PPI_CH3, | ||||
|     PPI_CH4, | ||||
|     PPI_CH5, | ||||
|     PPI_CH6, | ||||
|     PPI_CH7, | ||||
|     PPI_CH8, | ||||
|     PPI_CH9, | ||||
|     PPI_CH10, | ||||
|     PPI_CH11, | ||||
|     PPI_CH12, | ||||
|     PPI_CH13, | ||||
|     PPI_CH14, | ||||
|     PPI_CH15, | ||||
|     PPI_CH16, | ||||
|     PPI_CH17, | ||||
|     PPI_CH18, | ||||
|     PPI_CH19, | ||||
|     PPI_CH20, | ||||
|     PPI_CH21, | ||||
|     PPI_CH22, | ||||
|     PPI_CH23, | ||||
|     PPI_CH24, | ||||
|     PPI_CH25, | ||||
|     PPI_CH26, | ||||
|     PPI_CH27, | ||||
|     PPI_CH28, | ||||
|     PPI_CH29, | ||||
|     PPI_CH30, | ||||
|     PPI_CH31, | ||||
|  | ||||
|     PPI_GROUP0, | ||||
|     PPI_GROUP1, | ||||
|     PPI_GROUP2, | ||||
|     PPI_GROUP3, | ||||
|     PPI_GROUP4, | ||||
|     PPI_GROUP5, | ||||
|  | ||||
|     // GPIO port 0 | ||||
|     P0_00, | ||||
|     P0_01, | ||||
|     P0_02, | ||||
|     P0_03, | ||||
|     P0_04, | ||||
|     P0_05, | ||||
|     P0_06, | ||||
|     P0_07, | ||||
|     P0_08, | ||||
|     P0_09, | ||||
|     P0_10, | ||||
|     P0_11, | ||||
|     P0_12, | ||||
|     P0_13, | ||||
|     P0_14, | ||||
|     P0_15, | ||||
|     P0_16, | ||||
|     P0_17, | ||||
|     P0_18, | ||||
|     P0_19, | ||||
|     P0_20, | ||||
|     P0_21, | ||||
|     P0_22, | ||||
|     P0_23, | ||||
|     P0_24, | ||||
|     P0_25, | ||||
|     P0_26, | ||||
|     P0_27, | ||||
|     P0_28, | ||||
|     P0_29, | ||||
|     P0_30, | ||||
|     P0_31, | ||||
|  | ||||
|     // GPIO port 1 | ||||
|     P1_00, | ||||
|     P1_01, | ||||
|     P1_02, | ||||
|     P1_03, | ||||
|     P1_04, | ||||
|     P1_05, | ||||
|     P1_06, | ||||
|     P1_07, | ||||
|     P1_08, | ||||
|     P1_09, | ||||
|     P1_10, | ||||
|     P1_11, | ||||
|     P1_12, | ||||
|     P1_13, | ||||
|     P1_14, | ||||
|     P1_15, | ||||
| } | ||||
|  | ||||
| impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); | ||||
| impl_uarte!(UARTE1, UARTE1, UARTE1); | ||||
|  | ||||
| impl_spim!(TWISPI0, SPIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||||
| impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||||
| impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2); | ||||
| impl_spim!(SPI3, SPIM3, SPIM3); | ||||
|  | ||||
| impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||||
| impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||||
|  | ||||
| impl_pwm!(PWM0, PWM0, PWM0); | ||||
| impl_pwm!(PWM1, PWM1, PWM1); | ||||
| impl_pwm!(PWM2, PWM2, PWM2); | ||||
| impl_pwm!(PWM3, PWM3, PWM3); | ||||
|  | ||||
| impl_timer!(TIMER0, TIMER0, TIMER0); | ||||
| impl_timer!(TIMER1, TIMER1, TIMER1); | ||||
| impl_timer!(TIMER2, TIMER2, TIMER2); | ||||
| impl_timer!(TIMER3, TIMER3, TIMER3, extended); | ||||
| impl_timer!(TIMER4, TIMER4, TIMER4, extended); | ||||
|  | ||||
| impl_pin!(P0_00, 0, 0); | ||||
| impl_pin!(P0_01, 0, 1); | ||||
| impl_pin!(P0_02, 0, 2); | ||||
| impl_pin!(P0_03, 0, 3); | ||||
| impl_pin!(P0_04, 0, 4); | ||||
| impl_pin!(P0_05, 0, 5); | ||||
| impl_pin!(P0_06, 0, 6); | ||||
| impl_pin!(P0_07, 0, 7); | ||||
| impl_pin!(P0_08, 0, 8); | ||||
| impl_pin!(P0_09, 0, 9); | ||||
| impl_pin!(P0_10, 0, 10); | ||||
| impl_pin!(P0_11, 0, 11); | ||||
| impl_pin!(P0_12, 0, 12); | ||||
| impl_pin!(P0_13, 0, 13); | ||||
| impl_pin!(P0_14, 0, 14); | ||||
| impl_pin!(P0_15, 0, 15); | ||||
| impl_pin!(P0_16, 0, 16); | ||||
| impl_pin!(P0_17, 0, 17); | ||||
| impl_pin!(P0_18, 0, 18); | ||||
| impl_pin!(P0_19, 0, 19); | ||||
| impl_pin!(P0_20, 0, 20); | ||||
| impl_pin!(P0_21, 0, 21); | ||||
| impl_pin!(P0_22, 0, 22); | ||||
| impl_pin!(P0_23, 0, 23); | ||||
| impl_pin!(P0_24, 0, 24); | ||||
| impl_pin!(P0_25, 0, 25); | ||||
| impl_pin!(P0_26, 0, 26); | ||||
| impl_pin!(P0_27, 0, 27); | ||||
| impl_pin!(P0_28, 0, 28); | ||||
| impl_pin!(P0_29, 0, 29); | ||||
| impl_pin!(P0_30, 0, 30); | ||||
| impl_pin!(P0_31, 0, 31); | ||||
|  | ||||
| impl_pin!(P1_00, 1, 0); | ||||
| impl_pin!(P1_01, 1, 1); | ||||
| impl_pin!(P1_02, 1, 2); | ||||
| impl_pin!(P1_03, 1, 3); | ||||
| impl_pin!(P1_04, 1, 4); | ||||
| impl_pin!(P1_05, 1, 5); | ||||
| impl_pin!(P1_06, 1, 6); | ||||
| impl_pin!(P1_07, 1, 7); | ||||
| impl_pin!(P1_08, 1, 8); | ||||
| impl_pin!(P1_09, 1, 9); | ||||
| impl_pin!(P1_10, 1, 10); | ||||
| impl_pin!(P1_11, 1, 11); | ||||
| impl_pin!(P1_12, 1, 12); | ||||
| impl_pin!(P1_13, 1, 13); | ||||
| impl_pin!(P1_14, 1, 14); | ||||
| impl_pin!(P1_15, 1, 15); | ||||
|  | ||||
| pub mod irqs { | ||||
|     use embassy_macros::interrupt_declare as declare; | ||||
|     declare!(POWER_CLOCK); | ||||
|     declare!(RADIO); | ||||
|     declare!(UARTE0_UART0); | ||||
|     declare!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||||
|     declare!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||||
|     declare!(NFCT); | ||||
|     declare!(GPIOTE); | ||||
|     declare!(SAADC); | ||||
|     declare!(TIMER0); | ||||
|     declare!(TIMER1); | ||||
|     declare!(TIMER2); | ||||
|     declare!(RTC0); | ||||
|     declare!(TEMP); | ||||
|     declare!(RNG); | ||||
|     declare!(ECB); | ||||
|     declare!(CCM_AAR); | ||||
|     declare!(WDT); | ||||
|     declare!(RTC1); | ||||
|     declare!(QDEC); | ||||
|     declare!(COMP_LPCOMP); | ||||
|     declare!(SWI0_EGU0); | ||||
|     declare!(SWI1_EGU1); | ||||
|     declare!(SWI2_EGU2); | ||||
|     declare!(SWI3_EGU3); | ||||
|     declare!(SWI4_EGU4); | ||||
|     declare!(SWI5_EGU5); | ||||
|     declare!(TIMER3); | ||||
|     declare!(TIMER4); | ||||
|     declare!(PWM0); | ||||
|     declare!(PDM); | ||||
|     declare!(MWU); | ||||
|     declare!(PWM1); | ||||
|     declare!(PWM2); | ||||
|     declare!(SPIM2_SPIS2_SPI2); | ||||
|     declare!(RTC2); | ||||
|     declare!(I2S); | ||||
|     declare!(FPU); | ||||
|     declare!(USBD); | ||||
|     declare!(UARTE1); | ||||
|     declare!(PWM3); | ||||
|     declare!(SPIM3); | ||||
| } | ||||
							
								
								
									
										264
									
								
								embassy-nrf/src/chips/nrf52840.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										264
									
								
								embassy-nrf/src/chips/nrf52840.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,264 @@ | ||||
| pub use nrf52840_pac as pac; | ||||
|  | ||||
| pub const EASY_DMA_SIZE: usize = (1 << 16) - 1; | ||||
| pub const FORCE_COPY_BUFFER_SIZE: usize = 512; | ||||
|  | ||||
| embassy_extras::peripherals! { | ||||
|     // RTC | ||||
|     RTC0, | ||||
|     RTC1, | ||||
|     RTC2, | ||||
|  | ||||
|     // QSPI | ||||
|     QSPI, | ||||
|  | ||||
|     // UARTE | ||||
|     UARTE0, | ||||
|     UARTE1, | ||||
|  | ||||
|     // SPI/TWI | ||||
|     TWISPI0, | ||||
|     TWISPI1, | ||||
|     SPI2, | ||||
|     SPI3, | ||||
|  | ||||
|     // SAADC | ||||
|     SAADC, | ||||
|  | ||||
|     // PWM | ||||
|     PWM0, | ||||
|     PWM1, | ||||
|     PWM2, | ||||
|     PWM3, | ||||
|  | ||||
|     // TIMER | ||||
|     TIMER0, | ||||
|     TIMER1, | ||||
|     TIMER2, | ||||
|     TIMER3, | ||||
|     TIMER4, | ||||
|  | ||||
|     // GPIOTE | ||||
|     GPIOTE_CH0, | ||||
|     GPIOTE_CH1, | ||||
|     GPIOTE_CH2, | ||||
|     GPIOTE_CH3, | ||||
|     GPIOTE_CH4, | ||||
|     GPIOTE_CH5, | ||||
|     GPIOTE_CH6, | ||||
|     GPIOTE_CH7, | ||||
|  | ||||
|     // PPI | ||||
|     PPI_CH0, | ||||
|     PPI_CH1, | ||||
|     PPI_CH2, | ||||
|     PPI_CH3, | ||||
|     PPI_CH4, | ||||
|     PPI_CH5, | ||||
|     PPI_CH6, | ||||
|     PPI_CH7, | ||||
|     PPI_CH8, | ||||
|     PPI_CH9, | ||||
|     PPI_CH10, | ||||
|     PPI_CH11, | ||||
|     PPI_CH12, | ||||
|     PPI_CH13, | ||||
|     PPI_CH14, | ||||
|     PPI_CH15, | ||||
|     PPI_CH16, | ||||
|     PPI_CH17, | ||||
|     PPI_CH18, | ||||
|     PPI_CH19, | ||||
|     PPI_CH20, | ||||
|     PPI_CH21, | ||||
|     PPI_CH22, | ||||
|     PPI_CH23, | ||||
|     PPI_CH24, | ||||
|     PPI_CH25, | ||||
|     PPI_CH26, | ||||
|     PPI_CH27, | ||||
|     PPI_CH28, | ||||
|     PPI_CH29, | ||||
|     PPI_CH30, | ||||
|     PPI_CH31, | ||||
|  | ||||
|     PPI_GROUP0, | ||||
|     PPI_GROUP1, | ||||
|     PPI_GROUP2, | ||||
|     PPI_GROUP3, | ||||
|     PPI_GROUP4, | ||||
|     PPI_GROUP5, | ||||
|  | ||||
|     // GPIO port 0 | ||||
|     P0_00, | ||||
|     P0_01, | ||||
|     P0_02, | ||||
|     P0_03, | ||||
|     P0_04, | ||||
|     P0_05, | ||||
|     P0_06, | ||||
|     P0_07, | ||||
|     P0_08, | ||||
|     P0_09, | ||||
|     P0_10, | ||||
|     P0_11, | ||||
|     P0_12, | ||||
|     P0_13, | ||||
|     P0_14, | ||||
|     P0_15, | ||||
|     P0_16, | ||||
|     P0_17, | ||||
|     P0_18, | ||||
|     P0_19, | ||||
|     P0_20, | ||||
|     P0_21, | ||||
|     P0_22, | ||||
|     P0_23, | ||||
|     P0_24, | ||||
|     P0_25, | ||||
|     P0_26, | ||||
|     P0_27, | ||||
|     P0_28, | ||||
|     P0_29, | ||||
|     P0_30, | ||||
|     P0_31, | ||||
|  | ||||
|     // GPIO port 1 | ||||
|     P1_00, | ||||
|     P1_01, | ||||
|     P1_02, | ||||
|     P1_03, | ||||
|     P1_04, | ||||
|     P1_05, | ||||
|     P1_06, | ||||
|     P1_07, | ||||
|     P1_08, | ||||
|     P1_09, | ||||
|     P1_10, | ||||
|     P1_11, | ||||
|     P1_12, | ||||
|     P1_13, | ||||
|     P1_14, | ||||
|     P1_15, | ||||
| } | ||||
|  | ||||
| impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); | ||||
| impl_uarte!(UARTE1, UARTE1, UARTE1); | ||||
|  | ||||
| impl_spim!(TWISPI0, SPIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||||
| impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||||
| impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2); | ||||
| impl_spim!(SPI3, SPIM3, SPIM3); | ||||
|  | ||||
| impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||||
| impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||||
|  | ||||
| impl_pwm!(PWM0, PWM0, PWM0); | ||||
| impl_pwm!(PWM1, PWM1, PWM1); | ||||
| impl_pwm!(PWM2, PWM2, PWM2); | ||||
| impl_pwm!(PWM3, PWM3, PWM3); | ||||
|  | ||||
| impl_timer!(TIMER0, TIMER0, TIMER0); | ||||
| impl_timer!(TIMER1, TIMER1, TIMER1); | ||||
| impl_timer!(TIMER2, TIMER2, TIMER2); | ||||
| impl_timer!(TIMER3, TIMER3, TIMER3, extended); | ||||
| impl_timer!(TIMER4, TIMER4, TIMER4, extended); | ||||
|  | ||||
| impl_qspi!(QSPI, QSPI, QSPI); | ||||
|  | ||||
| impl_pin!(P0_00, 0, 0); | ||||
| impl_pin!(P0_01, 0, 1); | ||||
| impl_pin!(P0_02, 0, 2); | ||||
| impl_pin!(P0_03, 0, 3); | ||||
| impl_pin!(P0_04, 0, 4); | ||||
| impl_pin!(P0_05, 0, 5); | ||||
| impl_pin!(P0_06, 0, 6); | ||||
| impl_pin!(P0_07, 0, 7); | ||||
| impl_pin!(P0_08, 0, 8); | ||||
| impl_pin!(P0_09, 0, 9); | ||||
| impl_pin!(P0_10, 0, 10); | ||||
| impl_pin!(P0_11, 0, 11); | ||||
| impl_pin!(P0_12, 0, 12); | ||||
| impl_pin!(P0_13, 0, 13); | ||||
| impl_pin!(P0_14, 0, 14); | ||||
| impl_pin!(P0_15, 0, 15); | ||||
| impl_pin!(P0_16, 0, 16); | ||||
| impl_pin!(P0_17, 0, 17); | ||||
| impl_pin!(P0_18, 0, 18); | ||||
| impl_pin!(P0_19, 0, 19); | ||||
| impl_pin!(P0_20, 0, 20); | ||||
| impl_pin!(P0_21, 0, 21); | ||||
| impl_pin!(P0_22, 0, 22); | ||||
| impl_pin!(P0_23, 0, 23); | ||||
| impl_pin!(P0_24, 0, 24); | ||||
| impl_pin!(P0_25, 0, 25); | ||||
| impl_pin!(P0_26, 0, 26); | ||||
| impl_pin!(P0_27, 0, 27); | ||||
| impl_pin!(P0_28, 0, 28); | ||||
| impl_pin!(P0_29, 0, 29); | ||||
| impl_pin!(P0_30, 0, 30); | ||||
| impl_pin!(P0_31, 0, 31); | ||||
|  | ||||
| impl_pin!(P1_00, 1, 0); | ||||
| impl_pin!(P1_01, 1, 1); | ||||
| impl_pin!(P1_02, 1, 2); | ||||
| impl_pin!(P1_03, 1, 3); | ||||
| impl_pin!(P1_04, 1, 4); | ||||
| impl_pin!(P1_05, 1, 5); | ||||
| impl_pin!(P1_06, 1, 6); | ||||
| impl_pin!(P1_07, 1, 7); | ||||
| impl_pin!(P1_08, 1, 8); | ||||
| impl_pin!(P1_09, 1, 9); | ||||
| impl_pin!(P1_10, 1, 10); | ||||
| impl_pin!(P1_11, 1, 11); | ||||
| impl_pin!(P1_12, 1, 12); | ||||
| impl_pin!(P1_13, 1, 13); | ||||
| impl_pin!(P1_14, 1, 14); | ||||
| impl_pin!(P1_15, 1, 15); | ||||
|  | ||||
| pub mod irqs { | ||||
|     use embassy_macros::interrupt_declare as declare; | ||||
|     declare!(POWER_CLOCK); | ||||
|     declare!(RADIO); | ||||
|     declare!(UARTE0_UART0); | ||||
|     declare!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||||
|     declare!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||||
|     declare!(NFCT); | ||||
|     declare!(GPIOTE); | ||||
|     declare!(SAADC); | ||||
|     declare!(TIMER0); | ||||
|     declare!(TIMER1); | ||||
|     declare!(TIMER2); | ||||
|     declare!(RTC0); | ||||
|     declare!(TEMP); | ||||
|     declare!(RNG); | ||||
|     declare!(ECB); | ||||
|     declare!(CCM_AAR); | ||||
|     declare!(WDT); | ||||
|     declare!(RTC1); | ||||
|     declare!(QDEC); | ||||
|     declare!(COMP_LPCOMP); | ||||
|     declare!(SWI0_EGU0); | ||||
|     declare!(SWI1_EGU1); | ||||
|     declare!(SWI2_EGU2); | ||||
|     declare!(SWI3_EGU3); | ||||
|     declare!(SWI4_EGU4); | ||||
|     declare!(SWI5_EGU5); | ||||
|     declare!(TIMER3); | ||||
|     declare!(TIMER4); | ||||
|     declare!(PWM0); | ||||
|     declare!(PDM); | ||||
|     declare!(MWU); | ||||
|     declare!(PWM1); | ||||
|     declare!(PWM2); | ||||
|     declare!(SPIM2_SPIS2_SPI2); | ||||
|     declare!(RTC2); | ||||
|     declare!(I2S); | ||||
|     declare!(FPU); | ||||
|     declare!(USBD); | ||||
|     declare!(UARTE1); | ||||
|     declare!(QSPI); | ||||
|     declare!(CRYPTOCELL); | ||||
|     declare!(PWM3); | ||||
|     declare!(SPIM3); | ||||
| } | ||||
| @@ -1,3 +1,5 @@ | ||||
| #![macro_use] | ||||
|  | ||||
| use core::convert::Infallible; | ||||
| use core::hint::unreachable_unchecked; | ||||
| use core::marker::PhantomData; | ||||
| @@ -18,7 +20,7 @@ pub enum Port { | ||||
|     Port0, | ||||
|  | ||||
|     /// Port 1, only available on some nRF52 MCUs. | ||||
|     #[cfg(any(feature = "52833", feature = "52840"))] | ||||
|     #[cfg(any(feature = "nrf52833", feature = "nrf52840"))] | ||||
|     Port1, | ||||
| } | ||||
|  | ||||
| @@ -281,12 +283,12 @@ pub(crate) mod sealed { | ||||
|  | ||||
|         #[inline] | ||||
|         fn _pin(&self) -> u8 { | ||||
|             #[cfg(any(feature = "52833", feature = "52840"))] | ||||
|             #[cfg(any(feature = "nrf52833", feature = "nrf52840"))] | ||||
|             { | ||||
|                 self.pin_port() % 32 | ||||
|             } | ||||
|  | ||||
|             #[cfg(not(any(feature = "52833", feature = "52840")))] | ||||
|             #[cfg(not(any(feature = "nrf52833", feature = "nrf52840")))] | ||||
|             { | ||||
|                 self.pin_port() | ||||
|             } | ||||
| @@ -297,7 +299,7 @@ pub(crate) mod sealed { | ||||
|             unsafe { | ||||
|                 match self.pin_port() / 32 { | ||||
|                     0 => &*pac::P0::ptr(), | ||||
|                     #[cfg(any(feature = "52833", feature = "52840"))] | ||||
|                     #[cfg(any(feature = "nrf52833", feature = "nrf52840"))] | ||||
|                     1 => &*pac::P1::ptr(), | ||||
|                     _ => unreachable_unchecked(), | ||||
|                 } | ||||
| @@ -329,7 +331,7 @@ pub(crate) mod sealed { | ||||
|     pub trait OptionalPin {} | ||||
| } | ||||
|  | ||||
| pub trait Pin: sealed::Pin + Sized { | ||||
| pub trait Pin: Unborrow<Target = Self> + sealed::Pin + Sized { | ||||
|     /// Number of the pin within the port (0..31) | ||||
|     #[inline] | ||||
|     fn pin(&self) -> u8 { | ||||
| @@ -341,7 +343,7 @@ pub trait Pin: sealed::Pin + Sized { | ||||
|     fn port(&self) -> Port { | ||||
|         match self.pin_port() / 32 { | ||||
|             0 => Port::Port0, | ||||
|             #[cfg(any(feature = "52833", feature = "52840"))] | ||||
|             #[cfg(any(feature = "nrf52833", feature = "nrf52840"))] | ||||
|             1 => Port::Port1, | ||||
|             _ => unsafe { unreachable_unchecked() }, | ||||
|         } | ||||
| @@ -433,7 +435,7 @@ fn init_output<T: Pin>(pin: &T, drive: OutputDrive) { | ||||
|  | ||||
| // ==================== | ||||
|  | ||||
| pub trait OptionalPin: sealed::OptionalPin + Sized { | ||||
| pub trait OptionalPin: Unborrow<Target = Self> + sealed::OptionalPin + Sized { | ||||
|     type Pin: Pin; | ||||
|     fn pin(&self) -> Option<&Self::Pin>; | ||||
|     fn pin_mut(&mut self) -> Option<&mut Self::Pin>; | ||||
| @@ -488,8 +490,8 @@ impl OptionalPin for NoPin { | ||||
|  | ||||
| macro_rules! impl_pin { | ||||
|     ($type:ident, $port_num:expr, $pin_num:expr) => { | ||||
|         impl Pin for peripherals::$type {} | ||||
|         impl sealed::Pin for peripherals::$type { | ||||
|         impl crate::gpio::Pin for peripherals::$type {} | ||||
|         impl crate::gpio::sealed::Pin for peripherals::$type { | ||||
|             #[inline] | ||||
|             fn pin_port(&self) -> u8 { | ||||
|                 $port_num * 32 + $pin_num | ||||
| @@ -497,57 +499,3 @@ macro_rules! impl_pin { | ||||
|         } | ||||
|     }; | ||||
| } | ||||
|  | ||||
| impl_pin!(P0_00, 0, 0); | ||||
| impl_pin!(P0_01, 0, 1); | ||||
| impl_pin!(P0_02, 0, 2); | ||||
| impl_pin!(P0_03, 0, 3); | ||||
| impl_pin!(P0_04, 0, 4); | ||||
| impl_pin!(P0_05, 0, 5); | ||||
| impl_pin!(P0_06, 0, 6); | ||||
| impl_pin!(P0_07, 0, 7); | ||||
| impl_pin!(P0_08, 0, 8); | ||||
| impl_pin!(P0_09, 0, 9); | ||||
| impl_pin!(P0_10, 0, 10); | ||||
| impl_pin!(P0_11, 0, 11); | ||||
| impl_pin!(P0_12, 0, 12); | ||||
| impl_pin!(P0_13, 0, 13); | ||||
| impl_pin!(P0_14, 0, 14); | ||||
| impl_pin!(P0_15, 0, 15); | ||||
| impl_pin!(P0_16, 0, 16); | ||||
| impl_pin!(P0_17, 0, 17); | ||||
| impl_pin!(P0_18, 0, 18); | ||||
| impl_pin!(P0_19, 0, 19); | ||||
| impl_pin!(P0_20, 0, 20); | ||||
| impl_pin!(P0_21, 0, 21); | ||||
| impl_pin!(P0_22, 0, 22); | ||||
| impl_pin!(P0_23, 0, 23); | ||||
| impl_pin!(P0_24, 0, 24); | ||||
| impl_pin!(P0_25, 0, 25); | ||||
| impl_pin!(P0_26, 0, 26); | ||||
| impl_pin!(P0_27, 0, 27); | ||||
| impl_pin!(P0_28, 0, 28); | ||||
| impl_pin!(P0_29, 0, 29); | ||||
| impl_pin!(P0_30, 0, 30); | ||||
| impl_pin!(P0_31, 0, 31); | ||||
|  | ||||
| #[cfg(any(feature = "52833", feature = "52840"))] | ||||
| mod _p1 { | ||||
|     use super::*; | ||||
|     impl_pin!(P1_00, 1, 0); | ||||
|     impl_pin!(P1_01, 1, 1); | ||||
|     impl_pin!(P1_02, 1, 2); | ||||
|     impl_pin!(P1_03, 1, 3); | ||||
|     impl_pin!(P1_04, 1, 4); | ||||
|     impl_pin!(P1_05, 1, 5); | ||||
|     impl_pin!(P1_06, 1, 6); | ||||
|     impl_pin!(P1_07, 1, 7); | ||||
|     impl_pin!(P1_08, 1, 8); | ||||
|     impl_pin!(P1_09, 1, 9); | ||||
|     impl_pin!(P1_10, 1, 10); | ||||
|     impl_pin!(P1_11, 1, 11); | ||||
|     impl_pin!(P1_12, 1, 12); | ||||
|     impl_pin!(P1_13, 1, 13); | ||||
|     impl_pin!(P1_14, 1, 14); | ||||
|     impl_pin!(P1_15, 1, 15); | ||||
| } | ||||
|   | ||||
| @@ -2,7 +2,7 @@ use core::convert::Infallible; | ||||
| use core::future::Future; | ||||
| use core::marker::PhantomData; | ||||
| use core::task::{Context, Poll}; | ||||
| use embassy::interrupt::InterruptExt; | ||||
| use embassy::interrupt::{Interrupt, InterruptExt}; | ||||
| use embassy::traits::gpio::{WaitForAnyEdge, WaitForHigh, WaitForLow}; | ||||
| use embassy::util::AtomicWaker; | ||||
| use embassy_extras::impl_unborrow; | ||||
| @@ -17,9 +17,9 @@ use crate::{interrupt, peripherals}; | ||||
|  | ||||
| pub const CHANNEL_COUNT: usize = 8; | ||||
|  | ||||
| #[cfg(any(feature = "52833", feature = "52840"))] | ||||
| #[cfg(any(feature = "nrf52833", feature = "nrf52840"))] | ||||
| pub const PIN_COUNT: usize = 48; | ||||
| #[cfg(not(any(feature = "52833", feature = "52840")))] | ||||
| #[cfg(not(any(feature = "nrf52833", feature = "nrf52840")))] | ||||
| pub const PIN_COUNT: usize = 32; | ||||
|  | ||||
| const NEW_AW: AtomicWaker = AtomicWaker::new(); | ||||
| @@ -40,18 +40,10 @@ pub enum OutputChannelPolarity { | ||||
|     Toggle, | ||||
| } | ||||
|  | ||||
| /// Token indicating GPIOTE has been correctly initialized. | ||||
| /// | ||||
| /// This is not an owned singleton, it is Copy. Drivers that make use of GPIOTE require it. | ||||
| #[derive(Clone, Copy)] | ||||
| pub struct Initialized { | ||||
|     _private: (), | ||||
| } | ||||
|  | ||||
| pub fn initialize(_gpiote: peripherals::GPIOTE, irq: interrupt::GPIOTE) -> Initialized { | ||||
|     #[cfg(any(feature = "52833", feature = "52840"))] | ||||
| pub(crate) fn init() { | ||||
|     #[cfg(any(feature = "nrf52833", feature = "nrf52840"))] | ||||
|     let ports = unsafe { &[&*pac::P0::ptr(), &*pac::P1::ptr()] }; | ||||
|     #[cfg(not(any(feature = "52833", feature = "52840")))] | ||||
|     #[cfg(not(any(feature = "nrf52833", feature = "nrf52840")))] | ||||
|     let ports = unsafe { &[&*pac::P0::ptr()] }; | ||||
|  | ||||
|     for &p in ports { | ||||
| @@ -62,17 +54,18 @@ pub fn initialize(_gpiote: peripherals::GPIOTE, irq: interrupt::GPIOTE) -> Initi | ||||
|     } | ||||
|  | ||||
|     // Enable interrupts | ||||
|     let g = unsafe { &*pac::GPIOTE::ptr() }; | ||||
|     g.events_port.write(|w| w); | ||||
|     g.intenset.write(|w| w.port().set()); | ||||
|     irq.set_handler(on_irq); | ||||
|  | ||||
|     let irq = unsafe { interrupt::GPIOTE::steal() }; | ||||
|     irq.unpend(); | ||||
|     irq.enable(); | ||||
|  | ||||
|     Initialized { _private: () } | ||||
|     let g = unsafe { &*pac::GPIOTE::ptr() }; | ||||
|     g.events_port.write(|w| w); | ||||
|     g.intenset.write(|w| w.port().set()); | ||||
| } | ||||
|  | ||||
| unsafe fn on_irq(_ctx: *mut ()) { | ||||
| #[interrupt] | ||||
| unsafe fn GPIOTE() { | ||||
|     let g = &*pac::GPIOTE::ptr(); | ||||
|  | ||||
|     for i in 0..CHANNEL_COUNT { | ||||
| @@ -85,9 +78,9 @@ unsafe fn on_irq(_ctx: *mut ()) { | ||||
|     if g.events_port.read().bits() != 0 { | ||||
|         g.events_port.write(|w| w); | ||||
|  | ||||
|         #[cfg(any(feature = "52833", feature = "52840"))] | ||||
|         #[cfg(any(feature = "nrf52833", feature = "nrf52840"))] | ||||
|         let ports = &[&*pac::P0::ptr(), &*pac::P1::ptr()]; | ||||
|         #[cfg(not(any(feature = "52833", feature = "52840")))] | ||||
|         #[cfg(not(any(feature = "nrf52833", feature = "nrf52840")))] | ||||
|         let ports = &[&*pac::P0::ptr()]; | ||||
|  | ||||
|         for (port, &p) in ports.iter().enumerate() { | ||||
| @@ -133,12 +126,7 @@ impl<'d, C: Channel, T: GpioPin> Drop for InputChannel<'d, C, T> { | ||||
| } | ||||
|  | ||||
| impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> { | ||||
|     pub fn new( | ||||
|         _init: Initialized, | ||||
|         ch: C, | ||||
|         pin: Input<'d, T>, | ||||
|         polarity: InputChannelPolarity, | ||||
|     ) -> Self { | ||||
|     pub fn new(ch: C, pin: Input<'d, T>, polarity: InputChannelPolarity) -> Self { | ||||
|         let g = unsafe { &*pac::GPIOTE::ptr() }; | ||||
|         let num = ch.number(); | ||||
|  | ||||
| @@ -149,7 +137,7 @@ impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> { | ||||
|                 InputChannelPolarity::None => w.mode().event().polarity().none(), | ||||
|                 InputChannelPolarity::Toggle => w.mode().event().polarity().toggle(), | ||||
|             }; | ||||
|             #[cfg(any(feature = "52833", feature = "52840"))] | ||||
|             #[cfg(any(feature = "nrf52833", feature = "nrf52840"))] | ||||
|             w.port().bit(match pin.pin.port() { | ||||
|                 Port::Port0 => false, | ||||
|                 Port::Port1 => true, | ||||
| @@ -217,12 +205,7 @@ impl<'d, C: Channel, T: GpioPin> Drop for OutputChannel<'d, C, T> { | ||||
| } | ||||
|  | ||||
| impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> { | ||||
|     pub fn new( | ||||
|         _init: Initialized, | ||||
|         ch: C, | ||||
|         pin: Output<'d, T>, | ||||
|         polarity: OutputChannelPolarity, | ||||
|     ) -> Self { | ||||
|     pub fn new(ch: C, pin: Output<'d, T>, polarity: OutputChannelPolarity) -> Self { | ||||
|         let g = unsafe { &*pac::GPIOTE::ptr() }; | ||||
|         let num = ch.number(); | ||||
|  | ||||
| @@ -237,7 +220,7 @@ impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> { | ||||
|                 OutputChannelPolarity::Clear => w.polarity().hi_to_lo(), | ||||
|                 OutputChannelPolarity::Toggle => w.polarity().toggle(), | ||||
|             }; | ||||
|             #[cfg(any(feature = "52833", feature = "52840"))] | ||||
|             #[cfg(any(feature = "nrf52833", feature = "nrf52840"))] | ||||
|             w.port().bit(match pin.pin.port() { | ||||
|                 Port::Port0 => false, | ||||
|                 Port::Port1 => true, | ||||
| @@ -297,7 +280,7 @@ pub struct PortInput<'d, T: GpioPin> { | ||||
| impl<'d, T: GpioPin> Unpin for PortInput<'d, T> {} | ||||
|  | ||||
| impl<'d, T: GpioPin> PortInput<'d, T> { | ||||
|     pub fn new(_init: Initialized, pin: Input<'d, T>) -> Self { | ||||
|     pub fn new(pin: Input<'d, T>) -> Self { | ||||
|         Self { pin } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,210 +0,0 @@ | ||||
| //! Interrupt management | ||||
| //! | ||||
| //! This module implements an API for managing interrupts compatible with | ||||
| //! nrf_softdevice::interrupt. Intended for switching between the two at compile-time. | ||||
|  | ||||
| // Re-exports | ||||
| pub use embassy::interrupt::{declare, take, Interrupt}; | ||||
| pub use embassy_extras::interrupt::Priority3 as Priority; | ||||
|  | ||||
| #[cfg(feature = "52810")] | ||||
| mod irqs { | ||||
|     use super::*; | ||||
|     declare!(POWER_CLOCK); | ||||
|     declare!(RADIO); | ||||
|     declare!(UARTE0_UART0); | ||||
|     declare!(TWIM0_TWIS0_TWI0); | ||||
|     declare!(SPIM0_SPIS0_SPI0); | ||||
|     declare!(GPIOTE); | ||||
|     declare!(SAADC); | ||||
|     declare!(TIMER0); | ||||
|     declare!(TIMER1); | ||||
|     declare!(TIMER2); | ||||
|     declare!(RTC0); | ||||
|     declare!(TEMP); | ||||
|     declare!(RNG); | ||||
|     declare!(ECB); | ||||
|     declare!(CCM_AAR); | ||||
|     declare!(WDT); | ||||
|     declare!(RTC1); | ||||
|     declare!(QDEC); | ||||
|     declare!(COMP); | ||||
|     declare!(SWI0_EGU0); | ||||
|     declare!(SWI1_EGU1); | ||||
|     declare!(SWI2); | ||||
|     declare!(SWI3); | ||||
|     declare!(SWI4); | ||||
|     declare!(SWI5); | ||||
|     declare!(PWM0); | ||||
|     declare!(PDM); | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "52811")] | ||||
| mod irqs { | ||||
|     use super::*; | ||||
|     declare!(POWER_CLOCK); | ||||
|     declare!(RADIO); | ||||
|     declare!(UARTE0_UART0); | ||||
|     declare!(TWIM0_TWIS0_TWI0_SPIM1_SPIS1_SPI1); | ||||
|     declare!(SPIM0_SPIS0_SPI0); | ||||
|     declare!(GPIOTE); | ||||
|     declare!(SAADC); | ||||
|     declare!(TIMER0); | ||||
|     declare!(TIMER1); | ||||
|     declare!(TIMER2); | ||||
|     declare!(RTC0); | ||||
|     declare!(TEMP); | ||||
|     declare!(RNG); | ||||
|     declare!(ECB); | ||||
|     declare!(CCM_AAR); | ||||
|     declare!(WDT); | ||||
|     declare!(RTC1); | ||||
|     declare!(QDEC); | ||||
|     declare!(COMP); | ||||
|     declare!(SWI0_EGU0); | ||||
|     declare!(SWI1_EGU1); | ||||
|     declare!(SWI2); | ||||
|     declare!(SWI3); | ||||
|     declare!(SWI4); | ||||
|     declare!(SWI5); | ||||
|     declare!(PWM0); | ||||
|     declare!(PDM); | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "52832")] | ||||
| mod irqs { | ||||
|     use super::*; | ||||
|     declare!(POWER_CLOCK); | ||||
|     declare!(RADIO); | ||||
|     declare!(UARTE0_UART0); | ||||
|     declare!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||||
|     declare!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||||
|     declare!(NFCT); | ||||
|     declare!(GPIOTE); | ||||
|     declare!(SAADC); | ||||
|     declare!(TIMER0); | ||||
|     declare!(TIMER1); | ||||
|     declare!(TIMER2); | ||||
|     declare!(RTC0); | ||||
|     declare!(TEMP); | ||||
|     declare!(RNG); | ||||
|     declare!(ECB); | ||||
|     declare!(CCM_AAR); | ||||
|     declare!(WDT); | ||||
|     declare!(RTC1); | ||||
|     declare!(QDEC); | ||||
|     declare!(COMP_LPCOMP); | ||||
|     declare!(SWI0_EGU0); | ||||
|     declare!(SWI1_EGU1); | ||||
|     declare!(SWI2_EGU2); | ||||
|     declare!(SWI3_EGU3); | ||||
|     declare!(SWI4_EGU4); | ||||
|     declare!(SWI5_EGU5); | ||||
|     declare!(TIMER3); | ||||
|     declare!(TIMER4); | ||||
|     declare!(PWM0); | ||||
|     declare!(PDM); | ||||
|     declare!(MWU); | ||||
|     declare!(PWM1); | ||||
|     declare!(PWM2); | ||||
|     declare!(SPIM2_SPIS2_SPI2); | ||||
|     declare!(RTC2); | ||||
|     declare!(I2S); | ||||
|     declare!(FPU); | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "52833")] | ||||
| mod irqs { | ||||
|     use super::*; | ||||
|     declare!(POWER_CLOCK); | ||||
|     declare!(RADIO); | ||||
|     declare!(UARTE0_UART0); | ||||
|     declare!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||||
|     declare!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||||
|     declare!(NFCT); | ||||
|     declare!(GPIOTE); | ||||
|     declare!(SAADC); | ||||
|     declare!(TIMER0); | ||||
|     declare!(TIMER1); | ||||
|     declare!(TIMER2); | ||||
|     declare!(RTC0); | ||||
|     declare!(TEMP); | ||||
|     declare!(RNG); | ||||
|     declare!(ECB); | ||||
|     declare!(CCM_AAR); | ||||
|     declare!(WDT); | ||||
|     declare!(RTC1); | ||||
|     declare!(QDEC); | ||||
|     declare!(COMP_LPCOMP); | ||||
|     declare!(SWI0_EGU0); | ||||
|     declare!(SWI1_EGU1); | ||||
|     declare!(SWI2_EGU2); | ||||
|     declare!(SWI3_EGU3); | ||||
|     declare!(SWI4_EGU4); | ||||
|     declare!(SWI5_EGU5); | ||||
|     declare!(TIMER3); | ||||
|     declare!(TIMER4); | ||||
|     declare!(PWM0); | ||||
|     declare!(PDM); | ||||
|     declare!(MWU); | ||||
|     declare!(PWM1); | ||||
|     declare!(PWM2); | ||||
|     declare!(SPIM2_SPIS2_SPI2); | ||||
|     declare!(RTC2); | ||||
|     declare!(I2S); | ||||
|     declare!(FPU); | ||||
|     declare!(USBD); | ||||
|     declare!(UARTE1); | ||||
|     declare!(PWM3); | ||||
|     declare!(SPIM3); | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "52840")] | ||||
| mod irqs { | ||||
|     use super::*; | ||||
|     declare!(POWER_CLOCK); | ||||
|     declare!(RADIO); | ||||
|     declare!(UARTE0_UART0); | ||||
|     declare!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||||
|     declare!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||||
|     declare!(NFCT); | ||||
|     declare!(GPIOTE); | ||||
|     declare!(SAADC); | ||||
|     declare!(TIMER0); | ||||
|     declare!(TIMER1); | ||||
|     declare!(TIMER2); | ||||
|     declare!(RTC0); | ||||
|     declare!(TEMP); | ||||
|     declare!(RNG); | ||||
|     declare!(ECB); | ||||
|     declare!(CCM_AAR); | ||||
|     declare!(WDT); | ||||
|     declare!(RTC1); | ||||
|     declare!(QDEC); | ||||
|     declare!(COMP_LPCOMP); | ||||
|     declare!(SWI0_EGU0); | ||||
|     declare!(SWI1_EGU1); | ||||
|     declare!(SWI2_EGU2); | ||||
|     declare!(SWI3_EGU3); | ||||
|     declare!(SWI4_EGU4); | ||||
|     declare!(SWI5_EGU5); | ||||
|     declare!(TIMER3); | ||||
|     declare!(TIMER4); | ||||
|     declare!(PWM0); | ||||
|     declare!(PDM); | ||||
|     declare!(MWU); | ||||
|     declare!(PWM1); | ||||
|     declare!(PWM2); | ||||
|     declare!(SPIM2_SPIS2_SPI2); | ||||
|     declare!(RTC2); | ||||
|     declare!(I2S); | ||||
|     declare!(FPU); | ||||
|     declare!(USBD); | ||||
|     declare!(UARTE1); | ||||
|     declare!(QSPI); | ||||
|     declare!(CRYPTOCELL); | ||||
|     declare!(PWM3); | ||||
|     declare!(SPIM3); | ||||
| } | ||||
|  | ||||
| pub use irqs::*; | ||||
| @@ -7,257 +7,155 @@ | ||||
| #![allow(incomplete_features)] | ||||
|  | ||||
| #[cfg(not(any( | ||||
|     feature = "52810", | ||||
|     feature = "52811", | ||||
|     feature = "52832", | ||||
|     feature = "52833", | ||||
|     feature = "52840", | ||||
|     feature = "nrf51", | ||||
|     feature = "nrf52805", | ||||
|     feature = "nrf52810", | ||||
|     feature = "nrf52811", | ||||
|     feature = "nrf52820", | ||||
|     feature = "nrf52832", | ||||
|     feature = "nrf52833", | ||||
|     feature = "nrf52840", | ||||
|     feature = "nrf5340-app", | ||||
|     feature = "nrf5340-net", | ||||
|     feature = "nrf9160", | ||||
| )))] | ||||
| compile_error!("No chip feature activated. You must activate exactly one of the following features: 52810, 52811, 52832, 52833, 52840"); | ||||
|  | ||||
| #[cfg(any( | ||||
|     all(feature = "52810", feature = "52811"), | ||||
|     all(feature = "52810", feature = "52832"), | ||||
|     all(feature = "52810", feature = "52833"), | ||||
|     all(feature = "52810", feature = "52840"), | ||||
|     all(feature = "52811", feature = "52832"), | ||||
|     all(feature = "52811", feature = "52833"), | ||||
|     all(feature = "52811", feature = "52840"), | ||||
|     all(feature = "52832", feature = "52833"), | ||||
|     all(feature = "52832", feature = "52840"), | ||||
|     all(feature = "52833", feature = "52840"), | ||||
| ))] | ||||
| compile_error!("Multile chip features activated. You must activate exactly one of the following features: 52810, 52811, 52832, 52833, 52840"); | ||||
|  | ||||
| #[cfg(feature = "52810")] | ||||
| pub use nrf52810_pac as pac; | ||||
| #[cfg(feature = "52811")] | ||||
| pub use nrf52811_pac as pac; | ||||
| #[cfg(feature = "52832")] | ||||
| pub use nrf52832_pac as pac; | ||||
| #[cfg(feature = "52833")] | ||||
| pub use nrf52833_pac as pac; | ||||
| #[cfg(feature = "52840")] | ||||
| pub use nrf52840_pac as pac; | ||||
|  | ||||
| /// Length of Nordic EasyDMA differs for MCUs | ||||
| #[cfg(any( | ||||
|     feature = "52810", | ||||
|     feature = "52811", | ||||
|     feature = "52832", | ||||
|     feature = "51" | ||||
| ))] | ||||
| pub mod target_constants { | ||||
|     // NRF52832 8 bits1..0xFF | ||||
|     pub const EASY_DMA_SIZE: usize = 255; | ||||
|     // Easy DMA can only read from data ram | ||||
|     pub const SRAM_LOWER: usize = 0x2000_0000; | ||||
|     pub const SRAM_UPPER: usize = 0x3000_0000; | ||||
| } | ||||
| #[cfg(any(feature = "52840", feature = "52833", feature = "9160"))] | ||||
| pub mod target_constants { | ||||
|     // NRF52840 and NRF9160 16 bits 1..0xFFFF | ||||
|     pub const EASY_DMA_SIZE: usize = 65535; | ||||
|     // Limits for Easy DMA - it can only read from data ram | ||||
|     pub const SRAM_LOWER: usize = 0x2000_0000; | ||||
|     pub const SRAM_UPPER: usize = 0x3000_0000; | ||||
| } | ||||
|  | ||||
| /// Does this slice reside entirely within RAM? | ||||
| pub(crate) fn slice_in_ram(slice: &[u8]) -> bool { | ||||
|     let ptr = slice.as_ptr() as usize; | ||||
|     ptr >= target_constants::SRAM_LOWER && (ptr + slice.len()) < target_constants::SRAM_UPPER | ||||
| } | ||||
|  | ||||
| /// Return an error if slice is not in RAM. | ||||
| #[cfg(not(feature = "51"))] | ||||
| pub(crate) fn slice_in_ram_or<T>(slice: &[u8], err: T) -> Result<(), T> { | ||||
|     if slice.len() == 0 || slice_in_ram(slice) { | ||||
|         Ok(()) | ||||
|     } else { | ||||
|         Err(err) | ||||
|     } | ||||
| } | ||||
| compile_error!("No chip feature activated. You must activate exactly one of the following features: nrf52810, nrf52811, nrf52832, nrf52833, nrf52840"); | ||||
|  | ||||
| // This mod MUST go first, so that the others see its macros. | ||||
| pub(crate) mod fmt; | ||||
| pub(crate) mod util; | ||||
|  | ||||
| pub mod buffered_uarte; | ||||
| pub mod gpio; | ||||
| pub mod gpiote; | ||||
| pub mod interrupt; | ||||
| pub mod ppi; | ||||
| #[cfg(feature = "52840")] | ||||
| #[cfg(not(any(feature = "nrf52805", feature = "nrf52820")))] | ||||
| pub mod pwm; | ||||
| #[cfg(feature = "nrf52840")] | ||||
| pub mod qspi; | ||||
| pub mod rtc; | ||||
| #[cfg(not(feature = "nrf52820"))] | ||||
| pub mod saadc; | ||||
| pub mod spim; | ||||
| pub mod system; | ||||
| pub mod timer; | ||||
| pub mod twim; | ||||
| pub mod uarte; | ||||
|  | ||||
| embassy_extras::peripherals! { | ||||
|     // RTC | ||||
|     RTC0, | ||||
|     RTC1, | ||||
|     #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] | ||||
|     RTC2, | ||||
| // This mod MUST go last, so that it sees all the `impl_foo!` macros | ||||
| #[cfg(feature = "nrf52805")] | ||||
| #[path = "chips/nrf52805.rs"] | ||||
| mod chip; | ||||
| #[cfg(feature = "nrf52810")] | ||||
| #[path = "chips/nrf52810.rs"] | ||||
| mod chip; | ||||
| #[cfg(feature = "nrf52811")] | ||||
| #[path = "chips/nrf52811.rs"] | ||||
| mod chip; | ||||
| #[cfg(feature = "nrf52820")] | ||||
| #[path = "chips/nrf52820.rs"] | ||||
| mod chip; | ||||
| #[cfg(feature = "nrf52832")] | ||||
| #[path = "chips/nrf52832.rs"] | ||||
| mod chip; | ||||
| #[cfg(feature = "nrf52833")] | ||||
| #[path = "chips/nrf52833.rs"] | ||||
| mod chip; | ||||
| #[cfg(feature = "nrf52840")] | ||||
| #[path = "chips/nrf52840.rs"] | ||||
| mod chip; | ||||
|  | ||||
|     // QSPI | ||||
|     #[cfg(feature = "52840")] | ||||
|     QSPI, | ||||
| pub(crate) use chip::pac; | ||||
| pub use chip::{peripherals, Peripherals}; | ||||
|  | ||||
|     // UARTE | ||||
|     UARTE0, | ||||
|     #[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] | ||||
|     UARTE1, | ||||
|  | ||||
|     // SPIM | ||||
|     // TODO this is actually shared with SPI, SPIM, SPIS, TWI, TWIS, TWIS. | ||||
|     // When they're all implemented, they should be only one peripheral here. | ||||
|     SPIM0, | ||||
|     #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] | ||||
|     SPIM1, | ||||
|     #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] | ||||
|     SPIM2, | ||||
|     #[cfg(any(feature = "52833", feature = "52840"))] | ||||
|     SPIM3, | ||||
|  | ||||
|     // SAADC | ||||
|     SAADC, | ||||
|  | ||||
|     // TIMER | ||||
|     TIMER0, | ||||
|     TIMER1, | ||||
|     TIMER2, | ||||
|     #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] | ||||
|     TIMER3, | ||||
|     #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] | ||||
|     TIMER4, | ||||
|  | ||||
|     // GPIOTE | ||||
|     GPIOTE, | ||||
|     GPIOTE_CH0, | ||||
|     GPIOTE_CH1, | ||||
|     GPIOTE_CH2, | ||||
|     GPIOTE_CH3, | ||||
|     GPIOTE_CH4, | ||||
|     GPIOTE_CH5, | ||||
|     GPIOTE_CH6, | ||||
|     GPIOTE_CH7, | ||||
|  | ||||
|     // PPI | ||||
|     PPI_CH0, | ||||
|     PPI_CH1, | ||||
|     PPI_CH2, | ||||
|     PPI_CH3, | ||||
|     PPI_CH4, | ||||
|     PPI_CH5, | ||||
|     PPI_CH6, | ||||
|     PPI_CH7, | ||||
|     PPI_CH8, | ||||
|     PPI_CH9, | ||||
|     PPI_CH10, | ||||
|     PPI_CH11, | ||||
|     PPI_CH12, | ||||
|     PPI_CH13, | ||||
|     PPI_CH14, | ||||
|     PPI_CH15, | ||||
|     #[cfg(not(feature = "51"))] | ||||
|     PPI_CH16, | ||||
|     #[cfg(not(feature = "51"))] | ||||
|     PPI_CH17, | ||||
|     #[cfg(not(feature = "51"))] | ||||
|     PPI_CH18, | ||||
|     #[cfg(not(feature = "51"))] | ||||
|     PPI_CH19, | ||||
|     PPI_CH20, | ||||
|     PPI_CH21, | ||||
|     PPI_CH22, | ||||
|     PPI_CH23, | ||||
|     PPI_CH24, | ||||
|     PPI_CH25, | ||||
|     PPI_CH26, | ||||
|     PPI_CH27, | ||||
|     PPI_CH28, | ||||
|     PPI_CH29, | ||||
|     PPI_CH30, | ||||
|     PPI_CH31, | ||||
|  | ||||
|     PPI_GROUP0, | ||||
|     PPI_GROUP1, | ||||
|     PPI_GROUP2, | ||||
|     PPI_GROUP3, | ||||
|     #[cfg(not(feature = "51"))] | ||||
|     PPI_GROUP4, | ||||
|     #[cfg(not(feature = "51"))] | ||||
|     PPI_GROUP5, | ||||
|  | ||||
|     // GPIO port 0 | ||||
|     P0_00, | ||||
|     P0_01, | ||||
|     P0_02, | ||||
|     P0_03, | ||||
|     P0_04, | ||||
|     P0_05, | ||||
|     P0_06, | ||||
|     P0_07, | ||||
|     P0_08, | ||||
|     P0_09, | ||||
|     P0_10, | ||||
|     P0_11, | ||||
|     P0_12, | ||||
|     P0_13, | ||||
|     P0_14, | ||||
|     P0_15, | ||||
|     P0_16, | ||||
|     P0_17, | ||||
|     P0_18, | ||||
|     P0_19, | ||||
|     P0_20, | ||||
|     P0_21, | ||||
|     P0_22, | ||||
|     P0_23, | ||||
|     P0_24, | ||||
|     P0_25, | ||||
|     P0_26, | ||||
|     P0_27, | ||||
|     P0_28, | ||||
|     P0_29, | ||||
|     P0_30, | ||||
|     P0_31, | ||||
|  | ||||
|     // GPIO port 1 | ||||
|     #[cfg(any(feature = "52833", feature = "52840"))] | ||||
|     P1_00, | ||||
|     #[cfg(any(feature = "52833", feature = "52840"))] | ||||
|     P1_01, | ||||
|     #[cfg(any(feature = "52833", feature = "52840"))] | ||||
|     P1_02, | ||||
|     #[cfg(any(feature = "52833", feature = "52840"))] | ||||
|     P1_03, | ||||
|     #[cfg(any(feature = "52833", feature = "52840"))] | ||||
|     P1_04, | ||||
|     #[cfg(any(feature = "52833", feature = "52840"))] | ||||
|     P1_05, | ||||
|     #[cfg(any(feature = "52833", feature = "52840"))] | ||||
|     P1_06, | ||||
|     #[cfg(any(feature = "52833", feature = "52840"))] | ||||
|     P1_07, | ||||
|     #[cfg(any(feature = "52833", feature = "52840"))] | ||||
|     P1_08, | ||||
|     #[cfg(any(feature = "52833", feature = "52840"))] | ||||
|     P1_09, | ||||
|     #[cfg(any(feature = "52833", feature = "52840"))] | ||||
|     P1_10, | ||||
|     #[cfg(any(feature = "52833", feature = "52840"))] | ||||
|     P1_11, | ||||
|     #[cfg(any(feature = "52833", feature = "52840"))] | ||||
|     P1_12, | ||||
|     #[cfg(any(feature = "52833", feature = "52840"))] | ||||
|     P1_13, | ||||
|     #[cfg(any(feature = "52833", feature = "52840"))] | ||||
|     P1_14, | ||||
|     #[cfg(any(feature = "52833", feature = "52840"))] | ||||
|     P1_15, | ||||
| pub mod interrupt { | ||||
|     pub use crate::chip::irqs::*; | ||||
|     pub use cortex_m::interrupt::{CriticalSection, Mutex}; | ||||
|     pub use embassy::interrupt::{declare, take, Interrupt}; | ||||
|     pub use embassy_extras::interrupt::Priority3 as Priority; | ||||
| } | ||||
| pub use embassy_macros::interrupt; | ||||
|  | ||||
| pub mod config { | ||||
|     pub enum HfclkSource { | ||||
|         Internal, | ||||
|         ExternalXtal, | ||||
|     } | ||||
|  | ||||
|     pub enum LfclkSource { | ||||
|         InternalRC, | ||||
|         Synthesized, | ||||
|         ExternalXtal, | ||||
|         ExternalLowSwing, | ||||
|         ExternalFullSwing, | ||||
|     } | ||||
|  | ||||
|     #[non_exhaustive] | ||||
|     pub struct Config { | ||||
|         pub hfclk_source: HfclkSource, | ||||
|         pub lfclk_source: LfclkSource, | ||||
|     } | ||||
|  | ||||
|     impl Default for Config { | ||||
|         fn default() -> Self { | ||||
|             Self { | ||||
|                 // There are hobby nrf52 boards out there without external XTALs... | ||||
|                 // Default everything to internal so it Just Works. User can enable external | ||||
|                 // xtals if they know they have them. | ||||
|                 hfclk_source: HfclkSource::Internal, | ||||
|                 lfclk_source: LfclkSource::InternalRC, | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub fn init(config: config::Config) -> Peripherals { | ||||
|     // Do this first, so that it panics if user is calling `init` a second time | ||||
|     // before doing anything important. | ||||
|     let peripherals = Peripherals::take(); | ||||
|  | ||||
|     let r = unsafe { &*pac::CLOCK::ptr() }; | ||||
|  | ||||
|     // Start HFCLK. | ||||
|     match config.hfclk_source { | ||||
|         config::HfclkSource::Internal => {} | ||||
|         config::HfclkSource::ExternalXtal => { | ||||
|             // Datasheet says this is likely to take 0.36ms | ||||
|             r.events_hfclkstarted.write(|w| unsafe { w.bits(0) }); | ||||
|             r.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); | ||||
|             while r.events_hfclkstarted.read().bits() == 0 {} | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // Configure LFCLK. | ||||
|     match config.lfclk_source { | ||||
|         config::LfclkSource::InternalRC => r.lfclksrc.write(|w| w.src().rc()), | ||||
|         config::LfclkSource::Synthesized => r.lfclksrc.write(|w| w.src().synth()), | ||||
|  | ||||
|         config::LfclkSource::ExternalXtal => r.lfclksrc.write(|w| w.src().xtal()), | ||||
|  | ||||
|         config::LfclkSource::ExternalLowSwing => r.lfclksrc.write(|w| { | ||||
|             w.src().xtal(); | ||||
|             w.external().enabled(); | ||||
|             w.bypass().disabled(); | ||||
|             w | ||||
|         }), | ||||
|         config::LfclkSource::ExternalFullSwing => r.lfclksrc.write(|w| { | ||||
|             w.src().xtal(); | ||||
|             w.external().enabled(); | ||||
|             w.bypass().enabled(); | ||||
|             w | ||||
|         }), | ||||
|     } | ||||
|  | ||||
|     // Start LFCLK. | ||||
|     // Datasheet says this could take 100us from synth source | ||||
|     // 600us from rc source, 0.25s from an external source. | ||||
|     r.events_lfclkstarted.write(|w| unsafe { w.bits(0) }); | ||||
|     r.tasks_lfclkstart.write(|w| unsafe { w.bits(1) }); | ||||
|     while r.events_lfclkstarted.read().bits() == 0 {} | ||||
|  | ||||
|     // Init GPIOTE | ||||
|     crate::gpiote::init(); | ||||
|  | ||||
|     peripherals | ||||
| } | ||||
|   | ||||
							
								
								
									
										233
									
								
								embassy-nrf/src/pwm.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										233
									
								
								embassy-nrf/src/pwm.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,233 @@ | ||||
| #![macro_use] | ||||
|  | ||||
| use core::cell::UnsafeCell; | ||||
| use core::marker::PhantomData; | ||||
| use core::sync::atomic::{compiler_fence, Ordering}; | ||||
| use embassy::util::Unborrow; | ||||
| use embassy_extras::unborrow; | ||||
|  | ||||
| use crate::fmt::{assert, panic, unreachable, *}; | ||||
| use crate::gpio::sealed::Pin as _; | ||||
| use crate::gpio::OptionalPin as GpioOptionalPin; | ||||
| use crate::interrupt::Interrupt; | ||||
| use crate::pac; | ||||
|  | ||||
| #[derive(Debug, Eq, PartialEq, Clone, Copy)] | ||||
| pub enum Prescaler { | ||||
|     Div1, | ||||
|     Div2, | ||||
|     Div4, | ||||
|     Div8, | ||||
|     Div16, | ||||
|     Div32, | ||||
|     Div64, | ||||
|     Div128, | ||||
| } | ||||
|  | ||||
| /// Interface to the UARTE peripheral | ||||
| pub struct Pwm<'d, T: Instance> { | ||||
|     peri: T, | ||||
|     phantom: PhantomData<&'d mut T>, | ||||
| } | ||||
|  | ||||
| impl<'d, T: Instance> Pwm<'d, T> { | ||||
|     /// Creates the interface to a UARTE instance. | ||||
|     /// Sets the baud rate, parity and assigns the pins to the UARTE peripheral. | ||||
|     /// | ||||
|     /// # Safety | ||||
|     /// | ||||
|     /// The returned API is safe unless you use `mem::forget` (or similar safe mechanisms) | ||||
|     /// on stack allocated buffers which which have been passed to [`send()`](Pwm::send) | ||||
|     /// or [`receive`](Pwm::receive). | ||||
|     #[allow(unused_unsafe)] | ||||
|     pub fn new( | ||||
|         pwm: impl Unborrow<Target = T> + 'd, | ||||
|         ch0: impl Unborrow<Target = impl GpioOptionalPin> + 'd, | ||||
|         ch1: impl Unborrow<Target = impl GpioOptionalPin> + 'd, | ||||
|         ch2: impl Unborrow<Target = impl GpioOptionalPin> + 'd, | ||||
|         ch3: impl Unborrow<Target = impl GpioOptionalPin> + 'd, | ||||
|     ) -> Self { | ||||
|         unborrow!(pwm, ch0, ch1, ch2, ch3); | ||||
|  | ||||
|         let r = T::regs(); | ||||
|         let s = T::state(); | ||||
|  | ||||
|         if let Some(pin) = ch0.pin_mut() { | ||||
|             pin.set_low(); | ||||
|             pin.conf().write(|w| w.dir().output()); | ||||
|         } | ||||
|         if let Some(pin) = ch1.pin_mut() { | ||||
|             pin.set_low(); | ||||
|             pin.conf().write(|w| w.dir().output()); | ||||
|         } | ||||
|         if let Some(pin) = ch2.pin_mut() { | ||||
|             pin.set_low(); | ||||
|             pin.conf().write(|w| w.dir().output()); | ||||
|         } | ||||
|         if let Some(pin) = ch3.pin_mut() { | ||||
|             pin.set_low(); | ||||
|             pin.conf().write(|w| w.dir().output()); | ||||
|         } | ||||
|         r.psel.out[0].write(|w| unsafe { w.bits(ch0.psel_bits()) }); | ||||
|         r.psel.out[1].write(|w| unsafe { w.bits(ch1.psel_bits()) }); | ||||
|         r.psel.out[2].write(|w| unsafe { w.bits(ch2.psel_bits()) }); | ||||
|         r.psel.out[3].write(|w| unsafe { w.bits(ch3.psel_bits()) }); | ||||
|  | ||||
|         // Disable all interrupts | ||||
|         r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); | ||||
|  | ||||
|         // Enable | ||||
|         r.enable.write(|w| w.enable().enabled()); | ||||
|  | ||||
|         r.seq0 | ||||
|             .ptr | ||||
|             .write(|w| unsafe { w.bits(&s.duty as *const _ as u32) }); | ||||
|         r.seq0.cnt.write(|w| unsafe { w.bits(4) }); | ||||
|         r.seq0.refresh.write(|w| unsafe { w.bits(32) }); | ||||
|         r.seq0.enddelay.write(|w| unsafe { w.bits(0) }); | ||||
|  | ||||
|         r.decoder.write(|w| { | ||||
|             w.load().individual(); | ||||
|             w.mode().refresh_count() | ||||
|         }); | ||||
|         r.mode.write(|w| w.updown().up()); | ||||
|         r.prescaler.write(|w| w.prescaler().div_1()); | ||||
|         r.countertop | ||||
|             .write(|w| unsafe { w.countertop().bits(32767) }); | ||||
|         r.loop_.write(|w| w.cnt().disabled()); | ||||
|  | ||||
|         Self { | ||||
|             peri: pwm, | ||||
|             phantom: PhantomData, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Enables the PWM generator. | ||||
|     #[inline(always)] | ||||
|     pub fn enable(&self) { | ||||
|         let r = T::regs(); | ||||
|         r.enable.write(|w| w.enable().enabled()); | ||||
|     } | ||||
|  | ||||
|     /// Disables the PWM generator. | ||||
|     #[inline(always)] | ||||
|     pub fn disable(&self) { | ||||
|         let r = T::regs(); | ||||
|         r.enable.write(|w| w.enable().disabled()); | ||||
|     } | ||||
|  | ||||
|     /// Sets duty cycle (15 bit) for a PWM channel. | ||||
|     pub fn set_duty(&self, channel: usize, duty: u16) { | ||||
|         let s = T::state(); | ||||
|         unsafe { (*s.duty.get())[channel] = duty & 0x7FFF }; | ||||
|  | ||||
|         compiler_fence(Ordering::SeqCst); | ||||
|         T::regs().tasks_seqstart[0].write(|w| unsafe { w.bits(1) }); | ||||
|     } | ||||
|  | ||||
|     /// Sets the PWM clock prescaler. | ||||
|     #[inline(always)] | ||||
|     pub fn set_prescaler(&self, div: Prescaler) { | ||||
|         T::regs().prescaler.write(|w| w.prescaler().bits(div as u8)); | ||||
|     } | ||||
|  | ||||
|     /// Sets the PWM clock prescaler. | ||||
|     #[inline(always)] | ||||
|     pub fn prescaler(&self) -> Prescaler { | ||||
|         match T::regs().prescaler.read().prescaler().bits() { | ||||
|             0 => Prescaler::Div1, | ||||
|             1 => Prescaler::Div2, | ||||
|             2 => Prescaler::Div4, | ||||
|             3 => Prescaler::Div8, | ||||
|             4 => Prescaler::Div16, | ||||
|             5 => Prescaler::Div32, | ||||
|             6 => Prescaler::Div64, | ||||
|             7 => Prescaler::Div128, | ||||
|             _ => unreachable!(), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Sets the maximum duty cycle value. | ||||
|     #[inline(always)] | ||||
|     pub fn set_max_duty(&self, duty: u16) { | ||||
|         T::regs() | ||||
|             .countertop | ||||
|             .write(|w| unsafe { w.countertop().bits(duty.min(32767u16)) }); | ||||
|     } | ||||
|  | ||||
|     /// Returns the maximum duty cycle value. | ||||
|     #[inline(always)] | ||||
|     pub fn max_duty(&self) -> u16 { | ||||
|         T::regs().countertop.read().countertop().bits() | ||||
|     } | ||||
|  | ||||
|     /// Sets the PWM output frequency. | ||||
|     #[inline(always)] | ||||
|     pub fn set_period(&self, freq: u32) { | ||||
|         let clk = 16_000_000u32 >> (self.prescaler() as u8); | ||||
|         let duty = clk / freq; | ||||
|         self.set_max_duty(duty.min(32767) as u16); | ||||
|     } | ||||
|  | ||||
|     /// Returns the PWM output frequency. | ||||
|     #[inline(always)] | ||||
|     pub fn period(&self) -> u32 { | ||||
|         let clk = 16_000_000u32 >> (self.prescaler() as u8); | ||||
|         let max_duty = self.max_duty() as u32; | ||||
|         clk / max_duty | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'a, T: Instance> Drop for Pwm<'a, T> { | ||||
|     fn drop(&mut self) { | ||||
|         let r = T::regs(); | ||||
|         r.enable.write(|w| w.enable().disabled()); | ||||
|  | ||||
|         info!("pwm drop: done"); | ||||
|  | ||||
|         // TODO: disable pins | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub(crate) mod sealed { | ||||
|     use super::*; | ||||
|  | ||||
|     pub struct State { | ||||
|         pub duty: UnsafeCell<[u16; 4]>, | ||||
|     } | ||||
|     unsafe impl Sync for State {} | ||||
|  | ||||
|     impl State { | ||||
|         pub const fn new() -> Self { | ||||
|             Self { | ||||
|                 duty: UnsafeCell::new([0; 4]), | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub trait Instance { | ||||
|         fn regs() -> &'static pac::pwm0::RegisterBlock; | ||||
|         fn state() -> &'static State; | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub trait Instance: Unborrow<Target = Self> + sealed::Instance + 'static { | ||||
|     type Interrupt: Interrupt; | ||||
| } | ||||
|  | ||||
| macro_rules! impl_pwm { | ||||
|     ($type:ident, $pac_type:ident, $irq:ident) => { | ||||
|         impl crate::pwm::sealed::Instance for peripherals::$type { | ||||
|             fn regs() -> &'static pac::pwm0::RegisterBlock { | ||||
|                 unsafe { &*pac::$pac_type::ptr() } | ||||
|             } | ||||
|             fn state() -> &'static crate::pwm::sealed::State { | ||||
|                 static STATE: crate::pwm::sealed::State = crate::pwm::sealed::State::new(); | ||||
|                 &STATE | ||||
|             } | ||||
|         } | ||||
|         impl crate::pwm::Instance for peripherals::$type { | ||||
|             type Interrupt = crate::interrupt::$irq; | ||||
|         } | ||||
|     }; | ||||
| } | ||||
| @@ -1,3 +1,5 @@ | ||||
| #![macro_use] | ||||
|  | ||||
| use core::future::Future; | ||||
| use core::marker::PhantomData; | ||||
| use core::task::Poll; | ||||
| @@ -361,7 +363,7 @@ impl<'d, T: Instance> Flash for Qspi<'d, T> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| mod sealed { | ||||
| pub(crate) mod sealed { | ||||
|     use super::*; | ||||
|  | ||||
|     pub struct State { | ||||
| @@ -381,25 +383,23 @@ mod sealed { | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub trait Instance: sealed::Instance + 'static { | ||||
| pub trait Instance: Unborrow<Target = Self> + sealed::Instance + 'static { | ||||
|     type Interrupt: Interrupt; | ||||
| } | ||||
|  | ||||
| macro_rules! impl_instance { | ||||
|     ($type:ident, $irq:ident) => { | ||||
|         impl sealed::Instance for peripherals::$type { | ||||
| macro_rules! impl_qspi { | ||||
|     ($type:ident, $pac_type:ident, $irq:ident) => { | ||||
|         impl crate::qspi::sealed::Instance for peripherals::$type { | ||||
|             fn regs() -> &'static pac::qspi::RegisterBlock { | ||||
|                 unsafe { &*pac::$type::ptr() } | ||||
|                 unsafe { &*pac::$pac_type::ptr() } | ||||
|             } | ||||
|             fn state() -> &'static sealed::State { | ||||
|                 static STATE: sealed::State = sealed::State::new(); | ||||
|             fn state() -> &'static crate::qspi::sealed::State { | ||||
|                 static STATE: crate::qspi::sealed::State = crate::qspi::sealed::State::new(); | ||||
|                 &STATE | ||||
|             } | ||||
|         } | ||||
|         impl Instance for peripherals::$type { | ||||
|             type Interrupt = interrupt::$irq; | ||||
|         impl crate::qspi::Instance for peripherals::$type { | ||||
|             type Interrupt = crate::interrupt::$irq; | ||||
|         } | ||||
|     }; | ||||
| } | ||||
|  | ||||
| impl_instance!(QSPI, QSPI); | ||||
|   | ||||
| @@ -3,7 +3,7 @@ use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; | ||||
| use critical_section::CriticalSection; | ||||
| use embassy::interrupt::InterruptExt; | ||||
| use embassy::time::Clock; | ||||
| use embassy::util::CriticalSectionMutex as Mutex; | ||||
| use embassy::util::{CriticalSectionMutex as Mutex, Unborrow}; | ||||
|  | ||||
| use crate::interrupt::Interrupt; | ||||
| use crate::pac; | ||||
| @@ -283,7 +283,7 @@ macro_rules! impl_instance { | ||||
| } | ||||
|  | ||||
| /// Implemented by all RTC instances. | ||||
| pub trait Instance: sealed::Instance + 'static { | ||||
| pub trait Instance: Unborrow<Target = Self> + sealed::Instance + 'static { | ||||
|     /// The interrupt associated with this RTC instance. | ||||
|     type Interrupt: Interrupt; | ||||
| } | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| #![macro_use] | ||||
|  | ||||
| use core::future::Future; | ||||
| use core::marker::PhantomData; | ||||
| use core::sync::atomic::{compiler_fence, Ordering}; | ||||
| @@ -12,7 +14,7 @@ use traits::spi::FullDuplex; | ||||
| use crate::gpio::sealed::Pin as _; | ||||
| use crate::gpio::{OptionalPin, Pin as GpioPin}; | ||||
| use crate::interrupt::{self, Interrupt}; | ||||
| use crate::{pac, peripherals, slice_in_ram_or}; | ||||
| use crate::{pac, peripherals, util::slice_in_ram_or}; | ||||
|  | ||||
| pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; | ||||
| pub use pac::spim0::frequency::FREQUENCY_A as Frequency; | ||||
| @@ -33,12 +35,23 @@ pub struct Spim<'d, T: Instance> { | ||||
|     phantom: PhantomData<&'d mut T>, | ||||
| } | ||||
|  | ||||
| #[non_exhaustive] | ||||
| pub struct Config { | ||||
|     pub frequency: Frequency, | ||||
|     pub mode: Mode, | ||||
|     pub orc: u8, | ||||
| } | ||||
|  | ||||
| impl Default for Config { | ||||
|     fn default() -> Self { | ||||
|         Self { | ||||
|             frequency: Frequency::M1, | ||||
|             mode: MODE_0, | ||||
|             orc: 0x00, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'d, T: Instance> Spim<'d, T> { | ||||
|     pub fn new( | ||||
|         spim: impl Unborrow<Target = T> + 'd, | ||||
| @@ -315,7 +328,7 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u8> for Spim<'d, T> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| mod sealed { | ||||
| pub(crate) mod sealed { | ||||
|     use super::*; | ||||
|  | ||||
|     pub struct State { | ||||
| @@ -336,37 +349,23 @@ mod sealed { | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub trait Instance: sealed::Instance + 'static { | ||||
| pub trait Instance: Unborrow<Target = Self> + sealed::Instance + 'static { | ||||
|     type Interrupt: Interrupt; | ||||
| } | ||||
|  | ||||
| macro_rules! impl_instance { | ||||
|     ($type:ident, $irq:ident) => { | ||||
|         impl sealed::Instance for peripherals::$type { | ||||
| macro_rules! impl_spim { | ||||
|     ($type:ident, $pac_type:ident, $irq:ident) => { | ||||
|         impl crate::spim::sealed::Instance for peripherals::$type { | ||||
|             fn regs() -> &'static pac::spim0::RegisterBlock { | ||||
|                 unsafe { &*pac::$type::ptr() } | ||||
|                 unsafe { &*pac::$pac_type::ptr() } | ||||
|             } | ||||
|             fn state() -> &'static sealed::State { | ||||
|                 static STATE: sealed::State = sealed::State::new(); | ||||
|             fn state() -> &'static crate::spim::sealed::State { | ||||
|                 static STATE: crate::spim::sealed::State = crate::spim::sealed::State::new(); | ||||
|                 &STATE | ||||
|             } | ||||
|         } | ||||
|         impl Instance for peripherals::$type { | ||||
|             type Interrupt = interrupt::$irq; | ||||
|         impl crate::spim::Instance for peripherals::$type { | ||||
|             type Interrupt = crate::interrupt::$irq; | ||||
|         } | ||||
|     }; | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "52810")] | ||||
| impl_instance!(SPIM0, SPIM0_SPIS0_SPI0); | ||||
| #[cfg(not(feature = "52810"))] | ||||
| impl_instance!(SPIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||||
|  | ||||
| #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] | ||||
| impl_instance!(SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||||
|  | ||||
| #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] | ||||
| impl_instance!(SPIM2, SPIM2_SPIS2_SPI2); | ||||
|  | ||||
| #[cfg(any(feature = "52833", feature = "52840"))] | ||||
| impl_instance!(SPIM3, SPIM3); | ||||
|   | ||||
| @@ -1,76 +0,0 @@ | ||||
| use crate::pac; | ||||
|  | ||||
| pub enum HfclkSource { | ||||
|     Internal, | ||||
|     ExternalXtal, | ||||
| } | ||||
|  | ||||
| pub enum LfclkSource { | ||||
|     InternalRC, | ||||
|     Synthesized, | ||||
|     ExternalXtal, | ||||
|     ExternalLowSwing, | ||||
|     ExternalFullSwing, | ||||
| } | ||||
|  | ||||
| #[non_exhaustive] | ||||
| pub struct Config { | ||||
|     pub hfclk_source: HfclkSource, | ||||
|     pub lfclk_source: LfclkSource, | ||||
| } | ||||
|  | ||||
| impl Default for Config { | ||||
|     fn default() -> Self { | ||||
|         Self { | ||||
|             // There are hobby nrf52 boards out there without external XTALs... | ||||
|             // Default everything to internal so it Just Works. User can enable external | ||||
|             // xtals if they know they have them. | ||||
|             hfclk_source: HfclkSource::Internal, | ||||
|             lfclk_source: LfclkSource::InternalRC, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// safety: must only call once. | ||||
| pub unsafe fn configure(config: Config) { | ||||
|     let r = &*pac::CLOCK::ptr(); | ||||
|  | ||||
|     // Start HFCLK. | ||||
|     match config.hfclk_source { | ||||
|         HfclkSource::Internal => {} | ||||
|         HfclkSource::ExternalXtal => { | ||||
|             // Datasheet says this is likely to take 0.36ms | ||||
|             r.events_hfclkstarted.write(|w| unsafe { w.bits(0) }); | ||||
|             r.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); | ||||
|             while r.events_hfclkstarted.read().bits() == 0 {} | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // Configure LFCLK. | ||||
|     match config.lfclk_source { | ||||
|         LfclkSource::InternalRC => r.lfclksrc.write(|w| w.src().rc()), | ||||
|         LfclkSource::Synthesized => r.lfclksrc.write(|w| w.src().synth()), | ||||
|  | ||||
|         LfclkSource::ExternalXtal => r.lfclksrc.write(move |w| w.src().xtal()), | ||||
|  | ||||
|         LfclkSource::ExternalLowSwing => r.lfclksrc.write(move |w| { | ||||
|             w.src().xtal(); | ||||
|             w.external().enabled(); | ||||
|             w.bypass().disabled(); | ||||
|             w | ||||
|         }), | ||||
|         LfclkSource::ExternalFullSwing => r.lfclksrc.write(move |w| { | ||||
|             w.src().xtal(); | ||||
|             w.external().enabled(); | ||||
|             w.bypass().enabled(); | ||||
|             w | ||||
|         }), | ||||
|     } | ||||
|  | ||||
|     // Start LFCLK. | ||||
|     // Datasheet says this could take 100us from synth source | ||||
|     // 600us from rc source, 0.25s from an external source. | ||||
|     r.events_lfclkstarted.write(|w| unsafe { w.bits(0) }); | ||||
|     r.tasks_lfclkstart.write(|w| unsafe { w.bits(1) }); | ||||
|     while r.events_lfclkstarted.read().bits() == 0 {} | ||||
| } | ||||
| @@ -1,8 +1,11 @@ | ||||
| #![macro_use] | ||||
|  | ||||
| use embassy::interrupt::Interrupt; | ||||
| use embassy::util::Unborrow; | ||||
|  | ||||
| use crate::{interrupt, pac, peripherals}; | ||||
| use crate::pac; | ||||
|  | ||||
| mod sealed { | ||||
| pub(crate) mod sealed { | ||||
|     use super::*; | ||||
|  | ||||
|     pub trait Instance { | ||||
| @@ -11,33 +14,25 @@ mod sealed { | ||||
|     pub trait ExtendedInstance {} | ||||
| } | ||||
|  | ||||
| pub trait Instance: sealed::Instance + 'static { | ||||
| pub trait Instance: Unborrow<Target = Self> + sealed::Instance + 'static { | ||||
|     type Interrupt: Interrupt; | ||||
| } | ||||
| pub trait ExtendedInstance: Instance + sealed::ExtendedInstance {} | ||||
|  | ||||
| macro_rules! impl_instance { | ||||
|     ($type:ident, $irq:ident) => { | ||||
|         impl sealed::Instance for peripherals::$type { | ||||
| macro_rules! impl_timer { | ||||
|     ($type:ident, $pac_type:ident, $irq:ident) => { | ||||
|         impl crate::timer::sealed::Instance for peripherals::$type { | ||||
|             fn regs(&self) -> &pac::timer0::RegisterBlock { | ||||
|                 unsafe { &*(pac::$type::ptr() as *const pac::timer0::RegisterBlock) } | ||||
|                 unsafe { &*(pac::$pac_type::ptr() as *const pac::timer0::RegisterBlock) } | ||||
|             } | ||||
|         } | ||||
|         impl Instance for peripherals::$type { | ||||
|             type Interrupt = interrupt::$irq; | ||||
|         impl crate::timer::Instance for peripherals::$type { | ||||
|             type Interrupt = crate::interrupt::$irq; | ||||
|         } | ||||
|     }; | ||||
|     ($type:ident, $irq:ident, extended) => { | ||||
|         impl_instance!($type, $irq); | ||||
|         impl sealed::ExtendedInstance for peripherals::$type {} | ||||
|         impl ExtendedInstance for peripherals::$type {} | ||||
|     ($type:ident, $pac_type:ident, $irq:ident, extended) => { | ||||
|         impl_timer!($type, $pac_type, $irq); | ||||
|         impl crate::timer::sealed::ExtendedInstance for peripherals::$type {} | ||||
|         impl crate::timer::ExtendedInstance for peripherals::$type {} | ||||
|     }; | ||||
| } | ||||
|  | ||||
| impl_instance!(TIMER0, TIMER0); | ||||
| impl_instance!(TIMER1, TIMER1); | ||||
| impl_instance!(TIMER2, TIMER2); | ||||
| #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] | ||||
| impl_instance!(TIMER3, TIMER3, extended); | ||||
| #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] | ||||
| impl_instance!(TIMER4, TIMER4, extended); | ||||
|   | ||||
							
								
								
									
										531
									
								
								embassy-nrf/src/twim.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										531
									
								
								embassy-nrf/src/twim.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,531 @@ | ||||
| #![macro_use] | ||||
|  | ||||
| //! HAL interface to the TWIM peripheral. | ||||
| //! | ||||
| //! See product specification: | ||||
| //! | ||||
| //! - nRF52832: Section 33 | ||||
| //! - nRF52840: Section 6.31 | ||||
| use core::marker::PhantomData; | ||||
| use core::sync::atomic::{compiler_fence, Ordering::SeqCst}; | ||||
| use embassy::interrupt::{Interrupt, InterruptExt}; | ||||
| use embassy::util::{AtomicWaker, Unborrow}; | ||||
| use embassy_extras::unborrow; | ||||
|  | ||||
| use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; | ||||
| use crate::fmt::*; | ||||
| use crate::gpio::Pin as GpioPin; | ||||
| use crate::pac; | ||||
| use crate::util::{slice_in_ram, slice_in_ram_or}; | ||||
|  | ||||
| pub enum Frequency { | ||||
|     #[doc = "26738688: 100 kbps"] | ||||
|     K100 = 26738688, | ||||
|     #[doc = "67108864: 250 kbps"] | ||||
|     K250 = 67108864, | ||||
|     #[doc = "104857600: 400 kbps"] | ||||
|     K400 = 104857600, | ||||
| } | ||||
|  | ||||
| #[non_exhaustive] | ||||
| pub struct Config { | ||||
|     pub frequency: Frequency, | ||||
| } | ||||
|  | ||||
| impl Default for Config { | ||||
|     fn default() -> Self { | ||||
|         Self { | ||||
|             frequency: Frequency::K100, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Interface to a TWIM instance. | ||||
| pub struct Twim<'d, T: Instance> { | ||||
|     peri: T, | ||||
|     irq: T::Interrupt, | ||||
|     phantom: PhantomData<&'d mut T>, | ||||
| } | ||||
|  | ||||
| impl<'d, T: Instance> Twim<'d, T> { | ||||
|     pub fn new( | ||||
|         twim: impl Unborrow<Target = T> + 'd, | ||||
|         irq: impl Unborrow<Target = T::Interrupt> + 'd, | ||||
|         sda: impl Unborrow<Target = impl GpioPin> + 'd, | ||||
|         scl: impl Unborrow<Target = impl GpioPin> + 'd, | ||||
|         config: Config, | ||||
|     ) -> Self { | ||||
|         unborrow!(twim, irq, sda, scl); | ||||
|  | ||||
|         let r = T::regs(); | ||||
|  | ||||
|         // Configure pins | ||||
|         sda.conf().write(|w| { | ||||
|             w.dir().input(); | ||||
|             w.input().connect(); | ||||
|             w.pull().pullup(); | ||||
|             w.drive().s0d1(); | ||||
|             w | ||||
|         }); | ||||
|         scl.conf().write(|w| { | ||||
|             w.dir().input(); | ||||
|             w.input().connect(); | ||||
|             w.pull().pullup(); | ||||
|             w.drive().s0d1(); | ||||
|             w | ||||
|         }); | ||||
|  | ||||
|         // Select pins. | ||||
|         r.psel.sda.write(|w| unsafe { w.bits(sda.psel_bits()) }); | ||||
|         r.psel.scl.write(|w| unsafe { w.bits(scl.psel_bits()) }); | ||||
|  | ||||
|         // Enable TWIM instance. | ||||
|         r.enable.write(|w| w.enable().enabled()); | ||||
|  | ||||
|         // Configure frequency. | ||||
|         r.frequency | ||||
|             .write(|w| unsafe { w.frequency().bits(config.frequency as u32) }); | ||||
|  | ||||
|         // Disable all events interrupts | ||||
|         r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); | ||||
|  | ||||
|         irq.set_handler(Self::on_interrupt); | ||||
|         irq.unpend(); | ||||
|         irq.enable(); | ||||
|  | ||||
|         Self { | ||||
|             peri: twim, | ||||
|             irq, | ||||
|             phantom: PhantomData, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn on_interrupt(_: *mut ()) { | ||||
|         let r = T::regs(); | ||||
|         let s = T::state(); | ||||
|  | ||||
|         if r.events_stopped.read().bits() != 0 { | ||||
|             s.end_waker.wake(); | ||||
|             r.intenclr.write(|w| w.stopped().clear()); | ||||
|         } | ||||
|         if r.events_error.read().bits() != 0 { | ||||
|             s.end_waker.wake(); | ||||
|             r.intenclr.write(|w| w.error().clear()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Set TX buffer, checking that it is in RAM and has suitable length. | ||||
|     unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> { | ||||
|         slice_in_ram_or(buffer, Error::DMABufferNotInDataMemory)?; | ||||
|  | ||||
|         if buffer.len() == 0 { | ||||
|             return Err(Error::TxBufferZeroLength); | ||||
|         } | ||||
|         if buffer.len() > EASY_DMA_SIZE { | ||||
|             return Err(Error::TxBufferTooLong); | ||||
|         } | ||||
|  | ||||
|         let r = T::regs(); | ||||
|  | ||||
|         r.txd.ptr.write(|w| | ||||
|             // We're giving the register a pointer to the stack. Since we're | ||||
|             // waiting for the I2C transaction to end before this stack pointer | ||||
|             // becomes invalid, there's nothing wrong here. | ||||
|             // | ||||
|             // The PTR field is a full 32 bits wide and accepts the full range | ||||
|             // of values. | ||||
|             w.ptr().bits(buffer.as_ptr() as u32)); | ||||
|         r.txd.maxcnt.write(|w| | ||||
|             // We're giving it the length of the buffer, so no danger of | ||||
|             // accessing invalid memory. We have verified that the length of the | ||||
|             // buffer fits in an `u8`, so the cast to `u8` is also fine. | ||||
|             // | ||||
|             // The MAXCNT field is 8 bits wide and accepts the full range of | ||||
|             // values. | ||||
|             w.maxcnt().bits(buffer.len() as _)); | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     /// Set RX buffer, checking that it has suitable length. | ||||
|     unsafe fn set_rx_buffer(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | ||||
|         // NOTE: RAM slice check is not necessary, as a mutable | ||||
|         // slice can only be built from data located in RAM. | ||||
|  | ||||
|         if buffer.len() == 0 { | ||||
|             return Err(Error::RxBufferZeroLength); | ||||
|         } | ||||
|         if buffer.len() > EASY_DMA_SIZE { | ||||
|             return Err(Error::RxBufferTooLong); | ||||
|         } | ||||
|  | ||||
|         let r = T::regs(); | ||||
|  | ||||
|         r.rxd.ptr.write(|w| | ||||
|             // We're giving the register a pointer to the stack. Since we're | ||||
|             // waiting for the I2C transaction to end before this stack pointer | ||||
|             // becomes invalid, there's nothing wrong here. | ||||
|             // | ||||
|             // The PTR field is a full 32 bits wide and accepts the full range | ||||
|             // of values. | ||||
|             w.ptr().bits(buffer.as_mut_ptr() as u32)); | ||||
|         r.rxd.maxcnt.write(|w| | ||||
|             // We're giving it the length of the buffer, so no danger of | ||||
|             // accessing invalid memory. We have verified that the length of the | ||||
|             // buffer fits in an `u8`, so the cast to the type of maxcnt | ||||
|             // is also fine. | ||||
|             // | ||||
|             // Note that that nrf52840 maxcnt is a wider | ||||
|             // type than a u8, so we use a `_` cast rather than a `u8` cast. | ||||
|             // The MAXCNT field is thus at least 8 bits wide and accepts the | ||||
|             // full range of values that fit in a `u8`. | ||||
|             w.maxcnt().bits(buffer.len() as _)); | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     fn clear_errorsrc(&mut self) { | ||||
|         let r = T::regs(); | ||||
|         r.errorsrc | ||||
|             .write(|w| w.anack().bit(true).dnack().bit(true).overrun().bit(true)); | ||||
|     } | ||||
|  | ||||
|     /// Get Error instance, if any occurred. | ||||
|     fn read_errorsrc(&self) -> Result<(), Error> { | ||||
|         let r = T::regs(); | ||||
|  | ||||
|         let err = r.errorsrc.read(); | ||||
|         if err.anack().is_received() { | ||||
|             return Err(Error::AddressNack); | ||||
|         } | ||||
|         if err.dnack().is_received() { | ||||
|             return Err(Error::DataNack); | ||||
|         } | ||||
|         if err.overrun().is_received() { | ||||
|             return Err(Error::DataNack); | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     /// Wait for stop or error | ||||
|     fn wait(&mut self) { | ||||
|         let r = T::regs(); | ||||
|         loop { | ||||
|             if r.events_stopped.read().bits() != 0 { | ||||
|                 r.events_stopped.reset(); | ||||
|                 break; | ||||
|             } | ||||
|             if r.events_error.read().bits() != 0 { | ||||
|                 r.events_error.reset(); | ||||
|                 r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Write to an I2C slave. | ||||
|     /// | ||||
|     /// The buffer must have a length of at most 255 bytes on the nRF52832 | ||||
|     /// and at most 65535 bytes on the nRF52840. | ||||
|     pub fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { | ||||
|         let r = T::regs(); | ||||
|  | ||||
|         // Conservative compiler fence to prevent optimizations that do not | ||||
|         // take in to account actions by DMA. The fence has been placed here, | ||||
|         // before any DMA action has started. | ||||
|         compiler_fence(SeqCst); | ||||
|  | ||||
|         r.address.write(|w| unsafe { w.address().bits(address) }); | ||||
|  | ||||
|         // Set up the DMA write. | ||||
|         unsafe { self.set_tx_buffer(buffer)? }; | ||||
|  | ||||
|         // Clear events | ||||
|         r.events_stopped.reset(); | ||||
|         r.events_error.reset(); | ||||
|         r.events_lasttx.reset(); | ||||
|         self.clear_errorsrc(); | ||||
|  | ||||
|         // Start write operation. | ||||
|         r.shorts.write(|w| w.lasttx_stop().enabled()); | ||||
|         r.tasks_starttx.write(|w| | ||||
|             // `1` is a valid value to write to task registers. | ||||
|             unsafe { w.bits(1) }); | ||||
|  | ||||
|         self.wait(); | ||||
|  | ||||
|         // Conservative compiler fence to prevent optimizations that do not | ||||
|         // take in to account actions by DMA. The fence has been placed here, | ||||
|         // after all possible DMA actions have completed. | ||||
|         compiler_fence(SeqCst); | ||||
|  | ||||
|         self.read_errorsrc()?; | ||||
|  | ||||
|         if r.txd.amount.read().bits() != buffer.len() as u32 { | ||||
|             return Err(Error::Transmit); | ||||
|         } | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     /// Read from an I2C slave. | ||||
|     /// | ||||
|     /// The buffer must have a length of at most 255 bytes on the nRF52832 | ||||
|     /// and at most 65535 bytes on the nRF52840. | ||||
|     pub fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { | ||||
|         let r = T::regs(); | ||||
|  | ||||
|         // Conservative compiler fence to prevent optimizations that do not | ||||
|         // take in to account actions by DMA. The fence has been placed here, | ||||
|         // before any DMA action has started. | ||||
|         compiler_fence(SeqCst); | ||||
|  | ||||
|         r.address.write(|w| unsafe { w.address().bits(address) }); | ||||
|  | ||||
|         // Set up the DMA read. | ||||
|         unsafe { self.set_rx_buffer(buffer)? }; | ||||
|  | ||||
|         // Clear events | ||||
|         r.events_stopped.reset(); | ||||
|         r.events_error.reset(); | ||||
|         self.clear_errorsrc(); | ||||
|  | ||||
|         // Start read operation. | ||||
|         r.shorts.write(|w| w.lastrx_stop().enabled()); | ||||
|         r.tasks_startrx.write(|w| | ||||
|             // `1` is a valid value to write to task registers. | ||||
|             unsafe { w.bits(1) }); | ||||
|  | ||||
|         self.wait(); | ||||
|  | ||||
|         // Conservative compiler fence to prevent optimizations that do not | ||||
|         // take in to account actions by DMA. The fence has been placed here, | ||||
|         // after all possible DMA actions have completed. | ||||
|         compiler_fence(SeqCst); | ||||
|  | ||||
|         self.read_errorsrc()?; | ||||
|  | ||||
|         if r.rxd.amount.read().bits() != buffer.len() as u32 { | ||||
|             return Err(Error::Receive); | ||||
|         } | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     /// Write data to an I2C slave, then read data from the slave without | ||||
|     /// triggering a stop condition between the two. | ||||
|     /// | ||||
|     /// The buffers must have a length of at most 255 bytes on the nRF52832 | ||||
|     /// and at most 65535 bytes on the nRF52840. | ||||
|     pub fn write_then_read( | ||||
|         &mut self, | ||||
|         address: u8, | ||||
|         wr_buffer: &[u8], | ||||
|         rd_buffer: &mut [u8], | ||||
|     ) -> Result<(), Error> { | ||||
|         let r = T::regs(); | ||||
|  | ||||
|         // Conservative compiler fence to prevent optimizations that do not | ||||
|         // take in to account actions by DMA. The fence has been placed here, | ||||
|         // before any DMA action has started. | ||||
|         compiler_fence(SeqCst); | ||||
|  | ||||
|         r.address.write(|w| unsafe { w.address().bits(address) }); | ||||
|  | ||||
|         // Set up DMA buffers. | ||||
|         unsafe { | ||||
|             self.set_tx_buffer(wr_buffer)?; | ||||
|             self.set_rx_buffer(rd_buffer)?; | ||||
|         } | ||||
|  | ||||
|         // Clear events | ||||
|         r.events_stopped.reset(); | ||||
|         r.events_error.reset(); | ||||
|         self.clear_errorsrc(); | ||||
|  | ||||
|         // Start write+read operation. | ||||
|         r.shorts.write(|w| { | ||||
|             w.lasttx_startrx().enabled(); | ||||
|             w.lastrx_stop().enabled(); | ||||
|             w | ||||
|         }); | ||||
|         // `1` is a valid value to write to task registers. | ||||
|         r.tasks_starttx.write(|w| unsafe { w.bits(1) }); | ||||
|  | ||||
|         self.wait(); | ||||
|  | ||||
|         // Conservative compiler fence to prevent optimizations that do not | ||||
|         // take in to account actions by DMA. The fence has been placed here, | ||||
|         // after all possible DMA actions have completed. | ||||
|         compiler_fence(SeqCst); | ||||
|  | ||||
|         self.read_errorsrc()?; | ||||
|  | ||||
|         let bad_write = r.txd.amount.read().bits() != wr_buffer.len() as u32; | ||||
|         let bad_read = r.rxd.amount.read().bits() != rd_buffer.len() as u32; | ||||
|  | ||||
|         if bad_write { | ||||
|             return Err(Error::Transmit); | ||||
|         } | ||||
|  | ||||
|         if bad_read { | ||||
|             return Err(Error::Receive); | ||||
|         } | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     /// Copy data into RAM and write to an I2C slave. | ||||
|     /// | ||||
|     /// The write buffer must have a length of at most 255 bytes on the nRF52832 | ||||
|     /// and at most 1024 bytes on the nRF52840. | ||||
|     pub fn copy_write(&mut self, address: u8, wr_buffer: &[u8]) -> Result<(), Error> { | ||||
|         if wr_buffer.len() > FORCE_COPY_BUFFER_SIZE { | ||||
|             return Err(Error::TxBufferTooLong); | ||||
|         } | ||||
|  | ||||
|         // Copy to RAM | ||||
|         let wr_ram_buffer = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()]; | ||||
|         wr_ram_buffer.copy_from_slice(wr_buffer); | ||||
|  | ||||
|         self.write(address, wr_ram_buffer) | ||||
|     } | ||||
|  | ||||
|     /// Copy data into RAM and write to an I2C slave, then read data from the slave without | ||||
|     /// triggering a stop condition between the two. | ||||
|     /// | ||||
|     /// The write buffer must have a length of at most 255 bytes on the nRF52832 | ||||
|     /// and at most 1024 bytes on the nRF52840. | ||||
|     /// | ||||
|     /// The read buffer must have a length of at most 255 bytes on the nRF52832 | ||||
|     /// and at most 65535 bytes on the nRF52840. | ||||
|     pub fn copy_write_then_read( | ||||
|         &mut self, | ||||
|         address: u8, | ||||
|         wr_buffer: &[u8], | ||||
|         rd_buffer: &mut [u8], | ||||
|     ) -> Result<(), Error> { | ||||
|         if wr_buffer.len() > FORCE_COPY_BUFFER_SIZE { | ||||
|             return Err(Error::TxBufferTooLong); | ||||
|         } | ||||
|  | ||||
|         // Copy to RAM | ||||
|         let wr_ram_buffer = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()]; | ||||
|         wr_ram_buffer.copy_from_slice(wr_buffer); | ||||
|  | ||||
|         self.write_then_read(address, wr_ram_buffer, rd_buffer) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'a, T: Instance> Drop for Twim<'a, T> { | ||||
|     fn drop(&mut self) { | ||||
|         info!("twim drop"); | ||||
|  | ||||
|         // TODO when implementing async here, check for abort | ||||
|  | ||||
|         // disable! | ||||
|         let r = T::regs(); | ||||
|         r.enable.write(|w| w.enable().disabled()); | ||||
|  | ||||
|         info!("uarte drop: done"); | ||||
|  | ||||
|         // TODO: disable pins | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'a, T: Instance> embedded_hal::blocking::i2c::Write for Twim<'a, T> { | ||||
|     type Error = Error; | ||||
|  | ||||
|     fn write<'w>(&mut self, addr: u8, bytes: &'w [u8]) -> Result<(), Error> { | ||||
|         if slice_in_ram(bytes) { | ||||
|             self.write(addr, bytes) | ||||
|         } else { | ||||
|             let buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..]; | ||||
|             for chunk in bytes.chunks(FORCE_COPY_BUFFER_SIZE) { | ||||
|                 buf[..chunk.len()].copy_from_slice(chunk); | ||||
|                 self.write(addr, &buf[..chunk.len()])?; | ||||
|             } | ||||
|             Ok(()) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'a, T: Instance> embedded_hal::blocking::i2c::Read for Twim<'a, T> { | ||||
|     type Error = Error; | ||||
|  | ||||
|     fn read<'w>(&mut self, addr: u8, bytes: &'w mut [u8]) -> Result<(), Error> { | ||||
|         self.read(addr, bytes) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'a, T: Instance> embedded_hal::blocking::i2c::WriteRead for Twim<'a, T> { | ||||
|     type Error = Error; | ||||
|  | ||||
|     fn write_read<'w>( | ||||
|         &mut self, | ||||
|         addr: u8, | ||||
|         bytes: &'w [u8], | ||||
|         buffer: &'w mut [u8], | ||||
|     ) -> Result<(), Error> { | ||||
|         if slice_in_ram(bytes) { | ||||
|             self.write_then_read(addr, bytes, buffer) | ||||
|         } else { | ||||
|             self.copy_write_then_read(addr, bytes, buffer) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||||
| pub enum Error { | ||||
|     TxBufferTooLong, | ||||
|     RxBufferTooLong, | ||||
|     TxBufferZeroLength, | ||||
|     RxBufferZeroLength, | ||||
|     Transmit, | ||||
|     Receive, | ||||
|     DMABufferNotInDataMemory, | ||||
|     AddressNack, | ||||
|     DataNack, | ||||
|     Overrun, | ||||
| } | ||||
|  | ||||
| pub(crate) mod sealed { | ||||
|     use super::*; | ||||
|  | ||||
|     pub struct State { | ||||
|         pub end_waker: AtomicWaker, | ||||
|     } | ||||
|  | ||||
|     impl State { | ||||
|         pub const fn new() -> Self { | ||||
|             Self { | ||||
|                 end_waker: AtomicWaker::new(), | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub trait Instance { | ||||
|         fn regs() -> &'static pac::twim0::RegisterBlock; | ||||
|         fn state() -> &'static State; | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub trait Instance: Unborrow<Target = Self> + sealed::Instance + 'static { | ||||
|     type Interrupt: Interrupt; | ||||
| } | ||||
|  | ||||
| macro_rules! impl_twim { | ||||
|     ($type:ident, $pac_type:ident, $irq:ident) => { | ||||
|         impl crate::twim::sealed::Instance for peripherals::$type { | ||||
|             fn regs() -> &'static pac::twim0::RegisterBlock { | ||||
|                 unsafe { &*pac::$pac_type::ptr() } | ||||
|             } | ||||
|             fn state() -> &'static crate::twim::sealed::State { | ||||
|                 static STATE: crate::twim::sealed::State = crate::twim::sealed::State::new(); | ||||
|                 &STATE | ||||
|             } | ||||
|         } | ||||
|         impl crate::twim::Instance for peripherals::$type { | ||||
|             type Interrupt = crate::interrupt::$irq; | ||||
|         } | ||||
|     }; | ||||
| } | ||||
| @@ -1,3 +1,5 @@ | ||||
| #![macro_use] | ||||
|  | ||||
| //! Async UART | ||||
|  | ||||
| use core::future::Future; | ||||
| @@ -10,6 +12,7 @@ use embassy::util::{AtomicWaker, OnDrop, Unborrow}; | ||||
| use embassy_extras::unborrow; | ||||
| use futures::future::poll_fn; | ||||
|  | ||||
| use crate::chip::EASY_DMA_SIZE; | ||||
| use crate::fmt::{assert, panic, *}; | ||||
| use crate::gpio::sealed::Pin as _; | ||||
| use crate::gpio::{OptionalPin as GpioOptionalPin, Pin as GpioPin}; | ||||
| @@ -18,7 +21,6 @@ use crate::interrupt::Interrupt; | ||||
| use crate::pac; | ||||
| use crate::peripherals; | ||||
| use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; | ||||
| use crate::target_constants::EASY_DMA_SIZE; | ||||
| use crate::timer::Instance as TimerInstance; | ||||
|  | ||||
| // Re-export SVD variants to allow user to directly set values. | ||||
| @@ -445,7 +447,7 @@ impl<'d, U: Instance, T: TimerInstance> Write for UarteWithIdle<'d, U, T> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| mod sealed { | ||||
| pub(crate) mod sealed { | ||||
|     use super::*; | ||||
|  | ||||
|     pub struct State { | ||||
| @@ -467,27 +469,23 @@ mod sealed { | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub trait Instance: sealed::Instance + 'static { | ||||
| pub trait Instance: Unborrow<Target = Self> + sealed::Instance + 'static { | ||||
|     type Interrupt: Interrupt; | ||||
| } | ||||
|  | ||||
| macro_rules! impl_instance { | ||||
|     ($type:ident, $irq:ident) => { | ||||
|         impl sealed::Instance for peripherals::$type { | ||||
| macro_rules! impl_uarte { | ||||
|     ($type:ident, $pac_type:ident, $irq:ident) => { | ||||
|         impl crate::uarte::sealed::Instance for peripherals::$type { | ||||
|             fn regs() -> &'static pac::uarte0::RegisterBlock { | ||||
|                 unsafe { &*pac::$type::ptr() } | ||||
|                 unsafe { &*pac::$pac_type::ptr() } | ||||
|             } | ||||
|             fn state() -> &'static sealed::State { | ||||
|                 static STATE: sealed::State = sealed::State::new(); | ||||
|             fn state() -> &'static crate::uarte::sealed::State { | ||||
|                 static STATE: crate::uarte::sealed::State = crate::uarte::sealed::State::new(); | ||||
|                 &STATE | ||||
|             } | ||||
|         } | ||||
|         impl Instance for peripherals::$type { | ||||
|             type Interrupt = interrupt::$irq; | ||||
|         impl crate::uarte::Instance for peripherals::$type { | ||||
|             type Interrupt = crate::interrupt::$irq; | ||||
|         } | ||||
|     }; | ||||
| } | ||||
|  | ||||
| impl_instance!(UARTE0, UARTE0_UART0); | ||||
| #[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] | ||||
| impl_instance!(UARTE1, UARTE1); | ||||
|   | ||||
							
								
								
									
										18
									
								
								embassy-nrf/src/util.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								embassy-nrf/src/util.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| const SRAM_LOWER: usize = 0x2000_0000; | ||||
| const SRAM_UPPER: usize = 0x3000_0000; | ||||
|  | ||||
| /// Does this slice reside entirely within RAM? | ||||
| pub(crate) fn slice_in_ram(slice: &[u8]) -> bool { | ||||
|     let ptr = slice.as_ptr() as usize; | ||||
|     ptr >= SRAM_LOWER && (ptr + slice.len()) < SRAM_UPPER | ||||
| } | ||||
|  | ||||
| /// Return an error if slice is not in RAM. | ||||
| #[cfg(not(feature = "51"))] | ||||
| pub(crate) fn slice_in_ram_or<T>(slice: &[u8], err: T) -> Result<(), T> { | ||||
|     if slice.len() == 0 || slice_in_ram(slice) { | ||||
|         Ok(()) | ||||
|     } else { | ||||
|         Err(err) | ||||
|     } | ||||
| } | ||||
| @@ -16,9 +16,7 @@ use embedded_hal::digital::v2::OutputPin; | ||||
| use gpio::{Level, Output}; | ||||
|  | ||||
| #[embassy::main] | ||||
| async fn main(_spawner: Spawner) { | ||||
|     let p = unwrap!(Peripherals::take()); | ||||
|  | ||||
| async fn main(_spawner: Spawner, p: Peripherals) { | ||||
|     let mut led = Output::new(p.PIN_25, Level::Low); | ||||
|  | ||||
|     loop { | ||||
|   | ||||
| @@ -16,9 +16,7 @@ use embassy_rp::Peripherals; | ||||
| use embedded_hal::digital::v2::{InputPin, OutputPin}; | ||||
|  | ||||
| #[embassy::main] | ||||
| async fn main(_spawner: Spawner) { | ||||
|     let p = unwrap!(Peripherals::take()); | ||||
|  | ||||
| async fn main(_spawner: Spawner, p: Peripherals) { | ||||
|     let button = Input::new(p.PIN_28, Pull::Up); | ||||
|     let mut led = Output::new(p.PIN_25, Level::Low); | ||||
|  | ||||
|   | ||||
| @@ -14,9 +14,7 @@ use embassy::executor::Spawner; | ||||
| use embassy_rp::{uart, Peripherals}; | ||||
|  | ||||
| #[embassy::main] | ||||
| async fn main(_spanwer: Spawner) { | ||||
|     let p = unwrap!(Peripherals::take()); | ||||
|  | ||||
| async fn main(_spawner: Spawner, p: Peripherals) { | ||||
|     let config = uart::Config::default(); | ||||
|     let mut uart = uart::Uart::new(p.UART0, p.PIN_0, p.PIN_1, p.PIN_2, p.PIN_3, config); | ||||
|     uart.send("Hello World!\r\n".as_bytes()); | ||||
|   | ||||
| @@ -15,7 +15,6 @@ pub mod dma; | ||||
| pub mod gpio; | ||||
| pub mod pll; | ||||
| pub mod resets; | ||||
| pub mod system; | ||||
| pub mod uart; | ||||
|  | ||||
| embassy_extras::peripherals! { | ||||
| @@ -72,3 +71,105 @@ embassy_extras::peripherals! { | ||||
|     DMA_CH10, | ||||
|     DMA_CH11, | ||||
| } | ||||
|  | ||||
| #[link_section = ".boot2"] | ||||
| #[used] | ||||
| static BOOT2: [u8; 256] = *include_bytes!("boot2.bin"); | ||||
|  | ||||
| pub mod config { | ||||
|     #[non_exhaustive] | ||||
|     pub struct Config {} | ||||
|  | ||||
|     impl Default for Config { | ||||
|         fn default() -> Self { | ||||
|             Self {} | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub fn init(config: config::Config) -> Peripherals { | ||||
|     // Do this first, so that it panics if user is calling `init` a second time | ||||
|     // before doing anything important. | ||||
|     let peripherals = Peripherals::take(); | ||||
|  | ||||
|     // Now reset all the peripherals, except QSPI and XIP (we're using those | ||||
|     // to execute from external flash!) | ||||
|  | ||||
|     let resets = resets::Resets::new(); | ||||
|  | ||||
|     // Reset everything except: | ||||
|     // - QSPI (we're using it to run this code!) | ||||
|     // - PLLs (it may be suicide if that's what's clocking us) | ||||
|     let mut peris = resets::ALL_PERIPHERALS; | ||||
|     peris.set_io_qspi(false); | ||||
|     peris.set_pads_qspi(false); | ||||
|     peris.set_pll_sys(false); | ||||
|     peris.set_pll_usb(false); | ||||
|     resets.reset(peris); | ||||
|  | ||||
|     let mut peris = resets::ALL_PERIPHERALS; | ||||
|     peris.set_adc(false); | ||||
|     peris.set_rtc(false); | ||||
|     peris.set_spi0(false); | ||||
|     peris.set_spi1(false); | ||||
|     peris.set_uart0(false); | ||||
|     peris.set_uart1(false); | ||||
|     peris.set_usbctrl(false); | ||||
|     resets.unreset_wait(peris); | ||||
|  | ||||
|     unsafe { | ||||
|         // xosc 12 mhz | ||||
|         pac::WATCHDOG.tick().write(|w| { | ||||
|             w.set_cycles(XOSC_MHZ as u16); | ||||
|             w.set_enable(true); | ||||
|         }); | ||||
|  | ||||
|         pac::CLOCKS | ||||
|             .clk_sys_resus_ctrl() | ||||
|             .write_value(pac::clocks::regs::ClkSysResusCtrl(0)); | ||||
|  | ||||
|         // Enable XOSC | ||||
|         // TODO extract to HAL module | ||||
|         const XOSC_MHZ: u32 = 12; | ||||
|         pac::XOSC | ||||
|             .ctrl() | ||||
|             .write(|w| w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ)); | ||||
|  | ||||
|         let startup_delay = (((XOSC_MHZ * 1_000_000) / 1000) + 128) / 256; | ||||
|         pac::XOSC | ||||
|             .startup() | ||||
|             .write(|w| w.set_delay(startup_delay as u16)); | ||||
|         pac::XOSC.ctrl().write(|w| { | ||||
|             w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ); | ||||
|             w.set_enable(pac::xosc::vals::CtrlEnable::ENABLE); | ||||
|         }); | ||||
|         while !pac::XOSC.status().read().stable() {} | ||||
|  | ||||
|         // Before we touch PLLs, switch sys and ref cleanly away from their aux sources. | ||||
|         pac::CLOCKS | ||||
|             .clk_sys_ctrl() | ||||
|             .modify(|w| w.set_src(pac::clocks::vals::ClkSysCtrlSrc::CLK_REF)); | ||||
|         while pac::CLOCKS.clk_sys_selected().read() != 1 {} | ||||
|         pac::CLOCKS | ||||
|             .clk_ref_ctrl() | ||||
|             .modify(|w| w.set_src(pac::clocks::vals::ClkRefCtrlSrc::ROSC_CLKSRC_PH)); | ||||
|         while pac::CLOCKS.clk_ref_selected().read() != 1 {} | ||||
|  | ||||
|         let mut peris = resets::Peripherals(0); | ||||
|         peris.set_pll_sys(true); | ||||
|         peris.set_pll_usb(true); | ||||
|         resets.reset(peris); | ||||
|         resets.unreset_wait(peris); | ||||
|  | ||||
|         pll::PLL::new(pll::PllSys).configure(1, 1500_000_000, 6, 2); | ||||
|         pll::PLL::new(pll::PllUsb).configure(1, 480_000_000, 5, 2); | ||||
|  | ||||
|         // Activate peripheral clock and take external oscillator as input | ||||
|         pac::CLOCKS.clk_peri_ctrl().write(|w| { | ||||
|             w.set_enable(true); | ||||
|             w.set_auxsrc(pac::clocks::vals::ClkPeriCtrlAuxsrc::XOSC_CLKSRC); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     peripherals | ||||
| } | ||||
|   | ||||
| @@ -1,94 +0,0 @@ | ||||
| use crate::{pac, pll, resets}; | ||||
|  | ||||
| #[link_section = ".boot2"] | ||||
| #[used] | ||||
| pub static BOOT2: [u8; 256] = *include_bytes!("boot2.bin"); | ||||
|  | ||||
| #[non_exhaustive] | ||||
| pub struct Config {} | ||||
|  | ||||
| impl Default for Config { | ||||
|     fn default() -> Self { | ||||
|         Self {} | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// safety: must only call once. | ||||
| pub unsafe fn configure(_config: Config) { | ||||
|     // Now reset all the peripherals, except QSPI and XIP (we're using those | ||||
|     // to execute from external flash!) | ||||
|  | ||||
|     let resets = resets::Resets::new(); | ||||
|  | ||||
|     // Reset everything except: | ||||
|     // - QSPI (we're using it to run this code!) | ||||
|     // - PLLs (it may be suicide if that's what's clocking us) | ||||
|     let mut peris = resets::ALL_PERIPHERALS; | ||||
|     peris.set_io_qspi(false); | ||||
|     peris.set_pads_qspi(false); | ||||
|     peris.set_pll_sys(false); | ||||
|     peris.set_pll_usb(false); | ||||
|     resets.reset(peris); | ||||
|  | ||||
|     let mut peris = resets::ALL_PERIPHERALS; | ||||
|     peris.set_adc(false); | ||||
|     peris.set_rtc(false); | ||||
|     peris.set_spi0(false); | ||||
|     peris.set_spi1(false); | ||||
|     peris.set_uart0(false); | ||||
|     peris.set_uart1(false); | ||||
|     peris.set_usbctrl(false); | ||||
|     resets.unreset_wait(peris); | ||||
|  | ||||
|     // xosc 12 mhz | ||||
|     pac::WATCHDOG.tick().write(|w| { | ||||
|         w.set_cycles(XOSC_MHZ as u16); | ||||
|         w.set_enable(true); | ||||
|     }); | ||||
|  | ||||
|     pac::CLOCKS | ||||
|         .clk_sys_resus_ctrl() | ||||
|         .write_value(pac::clocks::regs::ClkSysResusCtrl(0)); | ||||
|  | ||||
|     // Enable XOSC | ||||
|     // TODO extract to HAL module | ||||
|     const XOSC_MHZ: u32 = 12; | ||||
|     pac::XOSC | ||||
|         .ctrl() | ||||
|         .write(|w| w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ)); | ||||
|  | ||||
|     let startup_delay = (((XOSC_MHZ * 1_000_000) / 1000) + 128) / 256; | ||||
|     pac::XOSC | ||||
|         .startup() | ||||
|         .write(|w| w.set_delay(startup_delay as u16)); | ||||
|     pac::XOSC.ctrl().write(|w| { | ||||
|         w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ); | ||||
|         w.set_enable(pac::xosc::vals::CtrlEnable::ENABLE); | ||||
|     }); | ||||
|     while !pac::XOSC.status().read().stable() {} | ||||
|  | ||||
|     // Before we touch PLLs, switch sys and ref cleanly away from their aux sources. | ||||
|     pac::CLOCKS | ||||
|         .clk_sys_ctrl() | ||||
|         .modify(|w| w.set_src(pac::clocks::vals::ClkSysCtrlSrc::CLK_REF)); | ||||
|     while pac::CLOCKS.clk_sys_selected().read() != 1 {} | ||||
|     pac::CLOCKS | ||||
|         .clk_ref_ctrl() | ||||
|         .modify(|w| w.set_src(pac::clocks::vals::ClkRefCtrlSrc::ROSC_CLKSRC_PH)); | ||||
|     while pac::CLOCKS.clk_ref_selected().read() != 1 {} | ||||
|  | ||||
|     let mut peris = resets::Peripherals(0); | ||||
|     peris.set_pll_sys(true); | ||||
|     peris.set_pll_usb(true); | ||||
|     resets.reset(peris); | ||||
|     resets.unreset_wait(peris); | ||||
|  | ||||
|     pll::PLL::new(pll::PllSys).configure(1, 1500_000_000, 6, 2); | ||||
|     pll::PLL::new(pll::PllUsb).configure(1, 480_000_000, 5, 2); | ||||
|  | ||||
|     // Activate peripheral clock and take external oscillator as input | ||||
|     pac::CLOCKS.clk_peri_ctrl().write(|w| { | ||||
|         w.set_enable(true); | ||||
|         w.set_auxsrc(pac::clocks::vals::ClkPeriCtrlAuxsrc::XOSC_CLKSRC); | ||||
|     }); | ||||
| } | ||||
| @@ -1,28 +0,0 @@ | ||||
| [target.'cfg(all(target_arch = "arm", target_os = "none"))'] | ||||
| runner = "probe-run --chip STM32F401CCUx" | ||||
|  | ||||
| rustflags = [ | ||||
|   # LLD (shipped with the Rust toolchain) is used as the default linker | ||||
|   "-C", "link-arg=--nmagic", | ||||
|   "-C", "link-arg=-Tlink.x", | ||||
|   "-C", "link-arg=-Tdefmt.x", | ||||
|  | ||||
|   # if you run into problems with LLD switch to the GNU linker by commenting out | ||||
|   # this line | ||||
|   # "-C", "linker=arm-none-eabi-ld", | ||||
|  | ||||
|   # if you need to link to pre-compiled C libraries provided by a C toolchain | ||||
|   # use GCC as the linker by commenting out both lines above and then | ||||
|   # uncommenting the three lines below | ||||
|   # "-C", "linker=arm-none-eabi-gcc", | ||||
|   # "-C", "link-arg=-Wl,-Tlink.x", | ||||
|   # "-C", "link-arg=-nostartfiles", | ||||
|  | ||||
|   # Code-size optimizations. | ||||
|   "-Z", "trap-unreachable=no", | ||||
|   "-C", "inline-threshold=5", | ||||
|   "-C", "no-vectorize-loops", | ||||
| ] | ||||
|  | ||||
| [build] | ||||
| target = "thumbv7em-none-eabi" | ||||
| @@ -1,53 +0,0 @@ | ||||
| [package] | ||||
| authors = ["Dario Nieuwenhuis <dirbaio@dirbaio.net>"] | ||||
| edition = "2018" | ||||
| name = "embassy-stm32f4-examples" | ||||
| version = "0.1.0" | ||||
|  | ||||
| [features] | ||||
| default = [ | ||||
|     "defmt-default", | ||||
| ] | ||||
| defmt-default = [] | ||||
| defmt-trace = [] | ||||
| defmt-debug = [] | ||||
| defmt-info = [] | ||||
| defmt-warn = [] | ||||
| defmt-error = [] | ||||
|  | ||||
| stm32f401 = ["embassy-stm32/stm32f401"] | ||||
| stm32f405 = ["embassy-stm32/stm32f405"] | ||||
| stm32f407 = ["embassy-stm32/stm32f407"] | ||||
| stm32f410 = ["embassy-stm32/stm32f410"] | ||||
| stm32f411 = ["embassy-stm32/stm32f411"] | ||||
| stm32f412 = ["embassy-stm32/stm32f412"] | ||||
| stm32f413 = ["embassy-stm32/stm32f413"] | ||||
| stm32f415 = ["embassy-stm32/stm32f405"] | ||||
| stm32f417 = ["embassy-stm32/stm32f407"] | ||||
| stm32f423 = ["embassy-stm32/stm32f413"] | ||||
| stm32f427 = ["embassy-stm32/stm32f427"] | ||||
| stm32f429 = ["embassy-stm32/stm32f429"] | ||||
| stm32f437 = ["embassy-stm32/stm32f427"] | ||||
| stm32f439 = ["embassy-stm32/stm32f429"] | ||||
| stm32f446 = ["embassy-stm32/stm32f446"] | ||||
| stm32f469 = ["embassy-stm32/stm32f469"] | ||||
| stm32f479 = ["embassy-stm32/stm32f469"] | ||||
|  | ||||
|  | ||||
| [dependencies] | ||||
| embassy = { version = "0.1.0", path = "../embassy", features = ["defmt", "defmt-trace"] } | ||||
| embassy-traits = { version = "0.1.0", path = "../embassy-traits", features = ["defmt"] } | ||||
| embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" } | ||||
| embassy-extras = {version = "0.1.0", path = "../embassy-extras" } | ||||
|  | ||||
| defmt = "0.2.0" | ||||
| defmt-rtt = "0.2.0" | ||||
|  | ||||
| cortex-m = "0.7.1" | ||||
| cortex-m-rt = "0.6.13" | ||||
| embedded-hal    = { version = "0.2.4" } | ||||
| panic-probe = { version = "0.2.0", features = ["print-defmt"] } | ||||
| futures = { version = "0.3.8", default-features = false, features = ["async-await"] } | ||||
| rtt-target = { version = "0.3", features = ["cortex-m"] } | ||||
| bxcan = "0.5.0" | ||||
| usb-device = "0.2.7" | ||||
| @@ -1,31 +0,0 @@ | ||||
| //! This build script copies the `memory.x` file from the crate root into | ||||
| //! a directory where the linker can always find it at build time. | ||||
| //! For many projects this is optional, as the linker always searches the | ||||
| //! project root directory -- wherever `Cargo.toml` is. However, if you | ||||
| //! are using a workspace or have a more complicated build setup, this | ||||
| //! build script becomes required. Additionally, by requesting that | ||||
| //! Cargo re-run the build script whenever `memory.x` is changed, | ||||
| //! updating `memory.x` ensures a rebuild of the application with the | ||||
| //! new memory settings. | ||||
|  | ||||
| use std::env; | ||||
| use std::fs::File; | ||||
| use std::io::Write; | ||||
| use std::path::PathBuf; | ||||
|  | ||||
| fn main() { | ||||
|     // Put `memory.x` in our output directory and ensure it's | ||||
|     // on the linker search path. | ||||
|     let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); | ||||
|     File::create(out.join("memory.x")) | ||||
|         .unwrap() | ||||
|         .write_all(include_bytes!("memory.x")) | ||||
|         .unwrap(); | ||||
|     println!("cargo:rustc-link-search={}", out.display()); | ||||
|  | ||||
|     // By default, Cargo will re-run a build script whenever | ||||
|     // any file in the project changes. By specifying `memory.x` | ||||
|     // here, we ensure the build script is only re-run when | ||||
|     // `memory.x` is changed. | ||||
|     println!("cargo:rerun-if-changed=memory.x"); | ||||
| } | ||||
| @@ -1,5 +0,0 @@ | ||||
| MEMORY | ||||
| { | ||||
|   FLASH : ORIGIN = 0x08000000, LENGTH = 64K | ||||
|   RAM : ORIGIN = 0x20000000, LENGTH = 32K | ||||
| } | ||||
| @@ -1,57 +0,0 @@ | ||||
| #![no_std] | ||||
| #![no_main] | ||||
| #![feature(trait_alias)] | ||||
| #![feature(type_alias_impl_trait)] | ||||
| #![feature(min_type_alias_impl_trait)] | ||||
| #![feature(impl_trait_in_bindings)] | ||||
|  | ||||
| #[path = "../example_common.rs"] | ||||
| mod example_common; | ||||
| use example_common::{panic, *}; | ||||
|  | ||||
| use bxcan::filter::Mask32; | ||||
| use cortex_m_rt::entry; | ||||
| use embassy::executor::Executor; | ||||
| use embassy::util::Forever; | ||||
| use embassy_stm32::hal::prelude::*; | ||||
| use embassy_stm32::hal::{can::Can, stm32}; | ||||
| use embassy_stm32::{can, interrupt}; | ||||
|  | ||||
| #[embassy::task] | ||||
| async fn run(dp: stm32::Peripherals, _cp: cortex_m::Peripherals) { | ||||
|     let gpioa = dp.GPIOA.split(); | ||||
|  | ||||
|     let rx = gpioa.pa11.into_alternate_af9(); | ||||
|     let tx = gpioa.pa12.into_alternate_af9(); | ||||
|     let mut can = bxcan::Can::new(Can::new(dp.CAN1, (tx, rx))); | ||||
|  | ||||
|     // APB1 (PCLK1): 24MHz, Bit rate: 20kBit/s, Sample Point 87.5% | ||||
|     // Value was calculated with http://www.bittiming.can-wiki.info/ | ||||
|     can.modify_config().set_bit_timing(0x001c_004a); | ||||
|     // Configure filters so that can frames can be received. | ||||
|     can.modify_filters().enable_bank(0, Mask32::accept_all()); | ||||
|  | ||||
|     let mut can = can::Can::new(can, interrupt::take!(CAN1_TX), interrupt::take!(CAN1_RX0)); | ||||
|  | ||||
|     let _frame = can.receive().await; | ||||
| } | ||||
|  | ||||
| static EXECUTOR: Forever<Executor> = Forever::new(); | ||||
|  | ||||
| #[entry] | ||||
| fn main() -> ! { | ||||
|     let dp = stm32::Peripherals::take().unwrap(); | ||||
|     let cp = cortex_m::peripheral::Peripherals::take().unwrap(); | ||||
|  | ||||
|     dp.DBGMCU.cr.modify(|_, w| { | ||||
|         w.dbg_sleep().set_bit(); | ||||
|         w.dbg_standby().set_bit(); | ||||
|         w.dbg_stop().set_bit() | ||||
|     }); | ||||
|     dp.RCC.ahb1enr.modify(|_, w| w.dma1en().enabled()); | ||||
|  | ||||
|     let executor = EXECUTOR.put(Executor::new()); | ||||
|     executor.run(|spawner| { | ||||
|         unwrap!(spawner.spawn(run(dp, cp))); | ||||
|     }); | ||||
| } | ||||
| @@ -1,57 +0,0 @@ | ||||
| #![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 example_common::{panic, *}; | ||||
|  | ||||
| use cortex_m_rt::entry; | ||||
| use embassy::executor::Executor; | ||||
| use embassy::traits::gpio::*; | ||||
| use embassy::util::Forever; | ||||
| use embassy_stm32::exti::ExtiPin; | ||||
| use embassy_stm32::hal::prelude::*; | ||||
| use embassy_stm32::interrupt; | ||||
| use embassy_stm32::pac as stm32; | ||||
| use futures::pin_mut; | ||||
|  | ||||
| #[embassy::task] | ||||
| async fn run(dp: stm32::Peripherals, _cp: cortex_m::Peripherals) { | ||||
|     let gpioa = dp.GPIOA.split(); | ||||
|  | ||||
|     let button = gpioa.pa0.into_pull_up_input(); | ||||
|     let mut syscfg = dp.SYSCFG.constrain(); | ||||
|  | ||||
|     let mut pin = ExtiPin::new(button, interrupt::take!(EXTI0), &mut syscfg); | ||||
|  | ||||
|     info!("Starting loop"); | ||||
|  | ||||
|     loop { | ||||
|         pin.wait_for_rising_edge().await; | ||||
|         info!("edge detected!"); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static EXECUTOR: Forever<Executor> = Forever::new(); | ||||
|  | ||||
| #[entry] | ||||
| fn main() -> ! { | ||||
|     let dp = stm32::Peripherals::take().unwrap(); | ||||
|     let cp = cortex_m::peripheral::Peripherals::take().unwrap(); | ||||
|  | ||||
|     dp.DBGMCU.cr.modify(|_, w| { | ||||
|         w.dbg_sleep().set_bit(); | ||||
|         w.dbg_standby().set_bit(); | ||||
|         w.dbg_stop().set_bit() | ||||
|     }); | ||||
|     dp.RCC.ahb1enr.modify(|_, w| w.dma1en().enabled()); | ||||
|  | ||||
|     let executor = EXECUTOR.put(Executor::new()); | ||||
|     executor.run(|spawner| { | ||||
|         unwrap!(spawner.spawn(run(dp, cp))); | ||||
|     }); | ||||
| } | ||||
| @@ -1,42 +0,0 @@ | ||||
| #![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 example_common::*; | ||||
|  | ||||
| use cortex_m_rt::entry; | ||||
| use embassy_stm32::hal::prelude::*; | ||||
|  | ||||
| #[entry] | ||||
| fn main() -> ! { | ||||
|     info!("Hello World!"); | ||||
|  | ||||
|     let p = embassy_stm32::pac::Peripherals::take().unwrap(); | ||||
|  | ||||
|     p.DBGMCU.cr.modify(|_, w| { | ||||
|         w.dbg_sleep().set_bit(); | ||||
|         w.dbg_standby().set_bit(); | ||||
|         w.dbg_stop().set_bit() | ||||
|     }); | ||||
|     p.RCC.ahb1enr.modify(|_, w| w.dma1en().enabled()); | ||||
|  | ||||
|     let gpioa = p.GPIOA.split(); | ||||
|     let gpioc = p.GPIOC.split(); | ||||
|  | ||||
|     let mut led = gpioc.pc13.into_push_pull_output(); | ||||
|     let button = gpioa.pa0.into_pull_up_input(); | ||||
|     led.set_low().unwrap(); | ||||
|  | ||||
|     loop { | ||||
|         if button.is_high().unwrap() { | ||||
|             led.set_low().unwrap(); | ||||
|         } else { | ||||
|             led.set_high().unwrap(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,40 +0,0 @@ | ||||
| #![no_std] | ||||
| #![no_main] | ||||
| #![feature(min_type_alias_impl_trait)] | ||||
| #![feature(impl_trait_in_bindings)] | ||||
| #![feature(type_alias_impl_trait)] | ||||
|  | ||||
| #[path = "../example_common.rs"] | ||||
| mod example_common; | ||||
| use example_common::*; | ||||
|  | ||||
| use defmt::panic; | ||||
| use embassy; | ||||
|  | ||||
| use embassy::executor::Spawner; | ||||
| use embassy::time::{Duration, Timer}; | ||||
| use embassy_stm32; | ||||
| use embassy_stm32::hal; | ||||
|  | ||||
| #[embassy::task] | ||||
| async fn run1() { | ||||
|     loop { | ||||
|         info!("BIG INFREQUENT TICK"); | ||||
|         Timer::after(Duration::from_ticks(32768 * 2 as u64)).await; | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[embassy::task] | ||||
| async fn run2() { | ||||
|     loop { | ||||
|         info!("tick"); | ||||
|         Timer::after(Duration::from_ticks(13000 as u64)).await; | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[embassy::main(config = "embassy_stm32::system::Config::new().use_hse(16)")] | ||||
| async fn main(spawner: Spawner) { | ||||
|     let (dp, clocks) = embassy_stm32::Peripherals::take().unwrap(); | ||||
|  | ||||
|     spawner.spawn(run1()).unwrap(); | ||||
| } | ||||
| @@ -1,80 +0,0 @@ | ||||
| #![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 example_common::{panic, *}; | ||||
|  | ||||
| use cortex_m::singleton; | ||||
| use cortex_m_rt::entry; | ||||
| use embassy::executor::{Executor, Spawner}; | ||||
| use embassy::traits::uart::{Read, ReadUntilIdle, Write}; | ||||
| use embassy::util::Forever; | ||||
| use embassy_stm32::hal::dma::StreamsTuple; | ||||
| use embassy_stm32::hal::prelude::*; | ||||
| use embassy_stm32::hal::serial::config::Config; | ||||
| use embassy_stm32::interrupt; | ||||
| use embassy_stm32::pac as stm32; | ||||
| use embassy_stm32::serial; | ||||
| use futures::pin_mut; | ||||
|  | ||||
| #[embassy::main(config = "embassy_stm32::system::Config::new().use_hse(16).sysclk(48).pclk1(24)")] | ||||
| async fn main(spawner: Spawner) { | ||||
|     let (dp, clocks) = embassy_stm32::Peripherals::take().unwrap(); | ||||
|     let cp = cortex_m::peripheral::Peripherals::take().unwrap(); | ||||
|  | ||||
|     dp.DBGMCU.cr.modify(|_, w| { | ||||
|         w.dbg_sleep().set_bit(); | ||||
|         w.dbg_standby().set_bit(); | ||||
|         w.dbg_stop().set_bit() | ||||
|     }); | ||||
|  | ||||
|     // https://gist.github.com/thalesfragoso/a07340c5df6eee3b04c42fdc69ecdcb1 | ||||
|     let gpioa = dp.GPIOA.split(); | ||||
|     let streams = StreamsTuple::new(dp.DMA2); | ||||
|  | ||||
|     let _serial = unsafe { | ||||
|         serial::Serial::new( | ||||
|             dp.USART1, | ||||
|             (streams.7, streams.2), | ||||
|             ( | ||||
|                 gpioa.pa9.into_alternate_af7(), | ||||
|                 gpioa.pa10.into_alternate_af7(), | ||||
|             ), | ||||
|             interrupt::take!(DMA2_STREAM7), | ||||
|             interrupt::take!(DMA2_STREAM2), | ||||
|             interrupt::take!(USART1), | ||||
|             Config::default().baudrate(9600.bps()), | ||||
|             clocks, | ||||
|         ) | ||||
|     }; | ||||
|  | ||||
|     let streams = StreamsTuple::new(dp.DMA1); | ||||
|  | ||||
|     let mut serial = unsafe { | ||||
|         serial::Serial::new( | ||||
|             dp.USART2, | ||||
|             (streams.6, streams.5), | ||||
|             ( | ||||
|                 gpioa.pa2.into_alternate_af7(), | ||||
|                 gpioa.pa3.into_alternate_af7(), | ||||
|             ), | ||||
|             interrupt::take!(DMA1_STREAM6), | ||||
|             interrupt::take!(DMA1_STREAM5), | ||||
|             interrupt::take!(USART2), | ||||
|             Config::default().baudrate(9600.bps()), | ||||
|             clocks, | ||||
|         ) | ||||
|     }; | ||||
|     pin_mut!(serial); | ||||
|  | ||||
|     let buf = singleton!(: [u8; 30] = [0; 30]).unwrap(); | ||||
|  | ||||
|     buf[5] = 0x01; | ||||
|     serial.as_mut().write(buf).await.unwrap(); | ||||
|     serial.as_mut().read_until_idle(buf).await.unwrap(); | ||||
| } | ||||
| @@ -1,119 +0,0 @@ | ||||
| #![no_std] | ||||
| #![no_main] | ||||
| #![feature(type_alias_impl_trait)] | ||||
| #![feature(min_type_alias_impl_trait)] | ||||
| #![feature(impl_trait_in_bindings)] | ||||
|  | ||||
| #[path = "../example_common.rs"] | ||||
| mod example_common; | ||||
| use example_common::*; | ||||
|  | ||||
| use cortex_m_rt::entry; | ||||
| use defmt::panic; | ||||
| use embassy::executor::{Executor, Spawner}; | ||||
| use embassy::interrupt::InterruptExt; | ||||
| use embassy::io::{AsyncBufReadExt, AsyncWriteExt}; | ||||
| use embassy::time::{Duration, Timer}; | ||||
| use embassy::util::Forever; | ||||
| use embassy_extras::usb::usb_serial::UsbSerial; | ||||
| use embassy_extras::usb::Usb; | ||||
| use embassy_stm32::hal::otg_fs::{UsbBus, USB}; | ||||
| use embassy_stm32::hal::prelude::*; | ||||
| use embassy_stm32::{interrupt, pac, rtc}; | ||||
| use futures::future::{select, Either}; | ||||
| use futures::pin_mut; | ||||
| use usb_device::bus::UsbBusAllocator; | ||||
| use usb_device::prelude::*; | ||||
|  | ||||
| #[embassy::task] | ||||
| async fn run1(bus: &'static mut UsbBusAllocator<UsbBus<USB>>) { | ||||
|     info!("Async task"); | ||||
|  | ||||
|     let mut read_buf = [0u8; 128]; | ||||
|     let mut write_buf = [0u8; 128]; | ||||
|     let serial = UsbSerial::new(bus, &mut read_buf, &mut write_buf); | ||||
|  | ||||
|     let device = UsbDeviceBuilder::new(bus, UsbVidPid(0x16c0, 0x27dd)) | ||||
|         .manufacturer("Fake company") | ||||
|         .product("Serial port") | ||||
|         .serial_number("TEST") | ||||
|         .device_class(0x02) | ||||
|         .build(); | ||||
|  | ||||
|     let irq = interrupt::take!(OTG_FS); | ||||
|     irq.set_priority(interrupt::Priority::P3); | ||||
|  | ||||
|     let usb = Usb::new(device, serial, irq); | ||||
|     pin_mut!(usb); | ||||
|     usb.as_mut().start(); | ||||
|  | ||||
|     let (mut read_interface, mut write_interface) = usb.as_ref().take_serial_0(); | ||||
|  | ||||
|     let mut buf = [0u8; 64]; | ||||
|     loop { | ||||
|         let mut n = 0; | ||||
|         let left = { | ||||
|             let recv_fut = async { | ||||
|                 loop { | ||||
|                     let byte = unwrap!(read_interface.read_byte().await); | ||||
|                     unwrap!(write_interface.write_byte(byte).await); | ||||
|                     buf[n] = byte; | ||||
|  | ||||
|                     n += 1; | ||||
|                     if byte == b'\n' || byte == b'\r' || n == buf.len() { | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
|             }; | ||||
|             pin_mut!(recv_fut); | ||||
|  | ||||
|             let timeout = Timer::after(Duration::from_ticks(32768 * 10)); | ||||
|  | ||||
|             match select(recv_fut, timeout).await { | ||||
|                 Either::Left(_) => true, | ||||
|                 Either::Right(_) => false, | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         if left { | ||||
|             for c in buf[..n].iter_mut() { | ||||
|                 if 0x61 <= *c && *c <= 0x7a { | ||||
|                     *c &= !0x20; | ||||
|                 } | ||||
|             } | ||||
|             unwrap!(write_interface.write_byte(b'\n').await); | ||||
|             unwrap!(write_interface.write_all(&buf[..n]).await); | ||||
|             unwrap!(write_interface.write_byte(b'\n').await); | ||||
|         } else { | ||||
|             unwrap!(write_interface.write_all(b"\r\nSend something\r\n").await); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| static USB_BUS: Forever<UsbBusAllocator<UsbBus<USB>>> = Forever::new(); | ||||
|  | ||||
| #[embassy::main( | ||||
|     config = "embassy_stm32::system::Config::new().use_hse(25).sysclk(48).require_pll48clk()" | ||||
| )] | ||||
| async fn main(spawner: Spawner) -> ! { | ||||
|     static mut EP_MEMORY: [u32; 1024] = [0; 1024]; | ||||
|  | ||||
|     info!("Hello World!"); | ||||
|  | ||||
|     let (p, clocks) = embassy_stm32::Peripherals::take().unwrap(); | ||||
|  | ||||
|     let gpioa = p.GPIOA.split(); | ||||
|     let usb = USB { | ||||
|         usb_global: p.OTG_FS_GLOBAL, | ||||
|         usb_device: p.OTG_FS_DEVICE, | ||||
|         usb_pwrclk: p.OTG_FS_PWRCLK, | ||||
|         pin_dm: gpioa.pa11.into_alternate_af10(), | ||||
|         pin_dp: gpioa.pa12.into_alternate_af10(), | ||||
|         hclk: clocks.hclk(), | ||||
|     }; | ||||
|     // Rust analyzer isn't recognizing the static ref magic `cortex-m` does | ||||
|     #[allow(unused_unsafe)] | ||||
|     let usb_bus = USB_BUS.put(UsbBus::new(usb, unsafe { &mut EP_MEMORY })); | ||||
|  | ||||
|     spawner.spawn(run1(usb_bus)).unwrap(); | ||||
| } | ||||
| @@ -1,17 +0,0 @@ | ||||
| #![macro_use] | ||||
|  | ||||
| use defmt_rtt as _; // global logger | ||||
| use panic_probe as _; | ||||
|  | ||||
| pub use defmt::*; | ||||
|  | ||||
| use core::sync::atomic::{AtomicUsize, Ordering}; | ||||
|  | ||||
| defmt::timestamp! {"{=u64}", { | ||||
|         static COUNT: AtomicUsize = AtomicUsize::new(0); | ||||
|         // NOTE(no-CAS) `timestamps` runs with interrupts disabled | ||||
|         let n = COUNT.load(Ordering::Relaxed); | ||||
|         COUNT.store(n + 1, Ordering::Relaxed); | ||||
|         n as u64 | ||||
|     } | ||||
| } | ||||
| @@ -1,53 +0,0 @@ | ||||
| [package] | ||||
| name = "embassy-stm32" | ||||
| version = "0.1.0" | ||||
| authors = ["Dario Nieuwenhuis <dirbaio@dirbaio.net>"] | ||||
| edition = "2018" | ||||
|  | ||||
| [features] | ||||
| defmt-trace = [ ] | ||||
| defmt-debug = [ ] | ||||
| defmt-info = [ ] | ||||
| defmt-warn = [ ] | ||||
| defmt-error = [ ] | ||||
|  | ||||
| stm32f401 = ["stm32f4xx-hal/stm32f401"] | ||||
| stm32f405 = ["stm32f4xx-hal/stm32f405"] | ||||
| stm32f407 = ["stm32f4xx-hal/stm32f407"] | ||||
| stm32f410 = ["stm32f4xx-hal/stm32f410"] | ||||
| stm32f411 = ["stm32f4xx-hal/stm32f411"] | ||||
| stm32f412 = ["stm32f4xx-hal/stm32f412"] | ||||
| stm32f413 = ["stm32f4xx-hal/stm32f413"] | ||||
| stm32f415 = ["stm32f4xx-hal/stm32f405"] | ||||
| stm32f417 = ["stm32f4xx-hal/stm32f407"] | ||||
| stm32f423 = ["stm32f4xx-hal/stm32f413"] | ||||
| stm32f427 = ["stm32f4xx-hal/stm32f427"] | ||||
| stm32f429 = ["stm32f4xx-hal/stm32f429"] | ||||
| stm32f437 = ["stm32f4xx-hal/stm32f427"] | ||||
| stm32f439 = ["stm32f4xx-hal/stm32f429"] | ||||
| stm32f446 = ["stm32f4xx-hal/stm32f446"] | ||||
| stm32f469 = ["stm32f4xx-hal/stm32f469"] | ||||
| stm32f479 = ["stm32f4xx-hal/stm32f469"] | ||||
|  | ||||
| stm32l0x1 = ["stm32l0xx-hal/stm32l0x1"] | ||||
| stm32l0x2 = ["stm32l0xx-hal/stm32l0x2"] | ||||
| stm32l0x3 = ["stm32l0xx-hal/stm32l0x3"] | ||||
|  | ||||
| [dependencies] | ||||
| embassy = { version = "0.1.0", path = "../embassy" } | ||||
| embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["stm32"]} | ||||
| embassy-extras = {version = "0.1.0", path = "../embassy-extras" } | ||||
|  | ||||
| atomic-polyfill = "0.1.1" | ||||
| critical-section = "0.2.1" | ||||
| 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" } | ||||
| bxcan = "0.5.0" | ||||
| nb = "*" | ||||
| stm32f4xx-hal = { version = "0.9.0", features = ["rt", "can", "usb_fs"], optional = true } | ||||
| stm32l0xx-hal = { version = "0.7.0", features = ["rt"], optional = true } | ||||
| futures = { version = "0.3.5", default-features = false, features = ["async-await"] } | ||||
| @@ -1,120 +0,0 @@ | ||||
| //! Async low power Serial. | ||||
| //! | ||||
| //! The peripheral is autmatically enabled and disabled as required to save power. | ||||
| //! Lowest power consumption can only be guaranteed if the send receive futures | ||||
| //! are dropped correctly (e.g. not using `mem::forget()`). | ||||
|  | ||||
| use bxcan; | ||||
| use bxcan::Interrupts; | ||||
| use core::future::Future; | ||||
| use embassy::interrupt::Interrupt; | ||||
| use embassy::util::InterruptFuture; | ||||
| use nb; | ||||
| use nb::block; | ||||
|  | ||||
| use crate::interrupt; | ||||
|  | ||||
| /// Interface to the Serial peripheral | ||||
| pub struct Can<T: Instance> { | ||||
|     can: bxcan::Can<T>, | ||||
|     tx_int: T::TInterrupt, | ||||
|     rx_int: T::RInterrupt, | ||||
| } | ||||
|  | ||||
| impl<T: Instance> Can<T> { | ||||
|     pub fn new(mut can: bxcan::Can<T>, tx_int: T::TInterrupt, rx_int: T::RInterrupt) -> Self { | ||||
|         // Sync to the bus and start normal operation. | ||||
|         can.enable_interrupts( | ||||
|             Interrupts::TRANSMIT_MAILBOX_EMPTY | Interrupts::FIFO0_MESSAGE_PENDING, | ||||
|         ); | ||||
|         block!(can.enable()).unwrap(); | ||||
|  | ||||
|         Can { | ||||
|             can: can, | ||||
|             tx_int: tx_int, | ||||
|             rx_int: rx_int, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Sends can frame. | ||||
|     /// | ||||
|     /// This method async-blocks until the frame is transmitted. | ||||
|     pub fn transmit<'a>(&'a mut self, frame: &'a bxcan::Frame) -> impl Future<Output = ()> + 'a { | ||||
|         async move { | ||||
|             let fut = InterruptFuture::new(&mut self.tx_int); | ||||
|             // Infallible | ||||
|             self.can.transmit(frame).unwrap(); | ||||
|  | ||||
|             fut.await; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Receive can frame. | ||||
|     /// | ||||
|     /// This method async-blocks until the frame is received. | ||||
|     pub fn receive<'a>(&'a mut self) -> impl Future<Output = bxcan::Frame> + 'a { | ||||
|         async move { | ||||
|             let mut frame: Option<bxcan::Frame>; | ||||
|  | ||||
|             loop { | ||||
|                 let fut = InterruptFuture::new(&mut self.rx_int); | ||||
|                 frame = match self.can.receive() { | ||||
|                     Ok(frame) => Some(frame), | ||||
|                     Err(nb::Error::WouldBlock) => None, | ||||
|                     Err(nb::Error::Other(_)) => None, // Ignore overrun errors. | ||||
|                 }; | ||||
|                 if frame.is_some() { | ||||
|                     break; | ||||
|                 } | ||||
|                 fut.await; | ||||
|             } | ||||
|  | ||||
|             frame.unwrap() | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| mod private { | ||||
|     pub trait Sealed {} | ||||
| } | ||||
|  | ||||
| pub trait Instance: bxcan::Instance + private::Sealed { | ||||
|     type TInterrupt: Interrupt; | ||||
|     type RInterrupt: Interrupt; | ||||
| } | ||||
|  | ||||
| macro_rules! can { | ||||
|     ($($can:ident => ($tint:ident, $rint:ident),)+) => { | ||||
|         $( | ||||
|             impl private::Sealed for crate::hal::can::Can<crate::pac::$can> {} | ||||
|             impl Instance for crate::hal::can::Can<crate::pac::$can> { | ||||
|                 type TInterrupt = interrupt::$tint; | ||||
|                 type RInterrupt = interrupt::$rint; | ||||
|             } | ||||
|         )+ | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(any( | ||||
|     feature = "stm32f401", | ||||
|     feature = "stm32f405", | ||||
|     feature = "stm32f407", | ||||
|     feature = "stm32f410", | ||||
|     feature = "stm32f411", | ||||
|     feature = "stm32f412", | ||||
|     feature = "stm32f413", | ||||
|     feature = "stm32f415", | ||||
|     feature = "stm32f417", | ||||
|     feature = "stm32f423", | ||||
|     feature = "stm32f427", | ||||
|     feature = "stm32f429", | ||||
|     feature = "stm32f437", | ||||
|     feature = "stm32f439", | ||||
|     feature = "stm32f446", | ||||
|     feature = "stm32f469", | ||||
|     feature = "stm32f479", | ||||
| ))] | ||||
| can! { | ||||
|     CAN1 => (CAN1_TX, CAN1_RX0), | ||||
|     CAN2 => (CAN2_TX, CAN2_RX0), | ||||
| } | ||||
| @@ -1,790 +0,0 @@ | ||||
| use core::future::Future; | ||||
| use core::mem; | ||||
| use cortex_m; | ||||
|  | ||||
| use crate::hal::gpio; | ||||
|  | ||||
| #[cfg(any( | ||||
|     feature = "stm32f401", | ||||
|     feature = "stm32f405", | ||||
|     feature = "stm32f407", | ||||
|     feature = "stm32f410", | ||||
|     feature = "stm32f411", | ||||
|     feature = "stm32f412", | ||||
|     feature = "stm32f413", | ||||
|     feature = "stm32f415", | ||||
|     feature = "stm32f417", | ||||
|     feature = "stm32f423", | ||||
|     feature = "stm32f427", | ||||
|     feature = "stm32f429", | ||||
|     feature = "stm32f437", | ||||
|     feature = "stm32f439", | ||||
|     feature = "stm32f446", | ||||
|     feature = "stm32f469", | ||||
|     feature = "stm32f479", | ||||
| ))] | ||||
| use crate::hal::syscfg::SysCfg; | ||||
|  | ||||
| #[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))] | ||||
| use crate::hal::syscfg::SYSCFG as SysCfg; | ||||
|  | ||||
| use embassy::traits::gpio::{ | ||||
|     WaitForAnyEdge, WaitForFallingEdge, WaitForHigh, WaitForLow, WaitForRisingEdge, | ||||
| }; | ||||
| use embassy::util::InterruptFuture; | ||||
|  | ||||
| use embedded_hal::digital::v2 as digital; | ||||
|  | ||||
| use crate::interrupt; | ||||
|  | ||||
| pub struct ExtiPin<T: Instance> { | ||||
|     pin: T, | ||||
|     interrupt: T::Interrupt, | ||||
| } | ||||
|  | ||||
| impl<T: Instance> ExtiPin<T> { | ||||
|     pub fn new(mut pin: T, interrupt: T::Interrupt, syscfg: &mut SysCfg) -> Self { | ||||
|         critical_section::with(|_| { | ||||
|             pin.make_source(syscfg); | ||||
|         }); | ||||
|  | ||||
|         Self { pin, interrupt } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: Instance + digital::OutputPin> digital::OutputPin for ExtiPin<T> { | ||||
|     type Error = T::Error; | ||||
|  | ||||
|     fn set_low(&mut self) -> Result<(), Self::Error> { | ||||
|         self.pin.set_low() | ||||
|     } | ||||
|  | ||||
|     fn set_high(&mut self) -> Result<(), Self::Error> { | ||||
|         self.pin.set_high() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: Instance + digital::StatefulOutputPin> digital::StatefulOutputPin for ExtiPin<T> { | ||||
|     fn is_set_low(&self) -> Result<bool, Self::Error> { | ||||
|         self.pin.is_set_low() | ||||
|     } | ||||
|  | ||||
|     fn is_set_high(&self) -> Result<bool, Self::Error> { | ||||
|         self.pin.is_set_high() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: Instance + digital::ToggleableOutputPin> digital::ToggleableOutputPin for ExtiPin<T> { | ||||
|     type Error = T::Error; | ||||
|  | ||||
|     fn toggle(&mut self) -> Result<(), Self::Error> { | ||||
|         self.pin.toggle() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: Instance + digital::InputPin> digital::InputPin for ExtiPin<T> { | ||||
|     type Error = T::Error; | ||||
|  | ||||
|     fn is_high(&self) -> Result<bool, Self::Error> { | ||||
|         self.pin.is_high() | ||||
|     } | ||||
|  | ||||
|     fn is_low(&self) -> Result<bool, Self::Error> { | ||||
|         self.pin.is_low() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: Instance + digital::InputPin + 'static> ExtiPin<T> { | ||||
|     fn wait_for_state<'a>(&'a mut self, state: bool) -> impl Future<Output = ()> + 'a { | ||||
|         async move { | ||||
|             let fut = InterruptFuture::new(&mut self.interrupt); | ||||
|             let pin = &mut self.pin; | ||||
|             critical_section::with(|_| { | ||||
|                 pin.trigger_edge(if state { | ||||
|                     EdgeOption::Rising | ||||
|                 } else { | ||||
|                     EdgeOption::Falling | ||||
|                 }); | ||||
|             }); | ||||
|  | ||||
|             if (state && self.pin.is_high().unwrap_or(false)) | ||||
|                 || (!state && self.pin.is_low().unwrap_or(false)) | ||||
|             { | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             fut.await; | ||||
|  | ||||
|             self.pin.clear_pending_bit(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: Instance + 'static> ExtiPin<T> { | ||||
|     fn wait_for_edge<'a>(&'a mut self, state: EdgeOption) -> impl Future<Output = ()> + 'a { | ||||
|         self.pin.clear_pending_bit(); | ||||
|         async move { | ||||
|             let fut = InterruptFuture::new(&mut self.interrupt); | ||||
|             let pin = &mut self.pin; | ||||
|             critical_section::with(|_| { | ||||
|                 pin.trigger_edge(state); | ||||
|             }); | ||||
|  | ||||
|             fut.await; | ||||
|  | ||||
|             self.pin.clear_pending_bit(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: Instance + digital::InputPin + 'static> WaitForHigh for ExtiPin<T> { | ||||
|     type Future<'a> = impl Future<Output = ()> + 'a; | ||||
|  | ||||
|     fn wait_for_high<'a>(&'a mut self) -> Self::Future<'a> { | ||||
|         self.wait_for_state(true) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: Instance + digital::InputPin + 'static> WaitForLow for ExtiPin<T> { | ||||
|     type Future<'a> = impl Future<Output = ()> + 'a; | ||||
|  | ||||
|     fn wait_for_low<'a>(&'a mut self) -> Self::Future<'a> { | ||||
|         self.wait_for_state(false) | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* | ||||
|     Irq	Handler	Description | ||||
|     EXTI0_IRQn	EXTI0_IRQHandler	Handler for pins connected to line 0 | ||||
|     EXTI1_IRQn	EXTI1_IRQHandler	Handler for pins connected to line 1 | ||||
|     EXTI2_IRQn	EXTI2_IRQHandler	Handler for pins connected to line 2 | ||||
|     EXTI3_IRQn	EXTI3_IRQHandler	Handler for pins connected to line 3 | ||||
|     EXTI4_IRQn	EXTI4_IRQHandler	Handler for pins connected to line 4 | ||||
|     EXTI9_5_IRQn	EXTI9_5_IRQHandler	Handler for pins connected to line 5 to 9 | ||||
|     EXTI15_10_IRQn	EXTI15_10_IRQHandler	Handler for pins connected to line 10 to 15 | ||||
| */ | ||||
|  | ||||
| impl<T: Instance + 'static> WaitForRisingEdge for ExtiPin<T> { | ||||
|     type Future<'a> = impl Future<Output = ()> + 'a; | ||||
|  | ||||
|     fn wait_for_rising_edge<'a>(&'a mut self) -> Self::Future<'a> { | ||||
|         self.wait_for_edge(EdgeOption::Rising) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: Instance + 'static> WaitForFallingEdge for ExtiPin<T> { | ||||
|     type Future<'a> = impl Future<Output = ()> + 'a; | ||||
|  | ||||
|     fn wait_for_falling_edge<'a>(&'a mut self) -> Self::Future<'a> { | ||||
|         self.wait_for_edge(EdgeOption::Falling) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: Instance + 'static> WaitForAnyEdge for ExtiPin<T> { | ||||
|     type Future<'a> = impl Future<Output = ()> + 'a; | ||||
|  | ||||
|     fn wait_for_any_edge<'a>(&'a mut self) -> Self::Future<'a> { | ||||
|         self.wait_for_edge(EdgeOption::RisingFalling) | ||||
|     } | ||||
| } | ||||
|  | ||||
| mod private { | ||||
|     pub trait Sealed {} | ||||
| } | ||||
|  | ||||
| #[derive(Copy, Clone)] | ||||
| pub enum EdgeOption { | ||||
|     Rising, | ||||
|     Falling, | ||||
|     RisingFalling, | ||||
| } | ||||
|  | ||||
| pub trait WithInterrupt: private::Sealed { | ||||
|     type Interrupt: interrupt::Interrupt; | ||||
| } | ||||
|  | ||||
| pub trait Instance: WithInterrupt { | ||||
|     fn make_source(&mut self, syscfg: &mut SysCfg); | ||||
|     fn clear_pending_bit(&mut self); | ||||
|     fn trigger_edge(&mut self, edge: EdgeOption); | ||||
| } | ||||
|  | ||||
| macro_rules! exti { | ||||
|     ($set:ident, [ | ||||
|         $($INT:ident => $pin:ident,)+ | ||||
|     ]) => { | ||||
|         $( | ||||
|             impl<T> private::Sealed for gpio::$set::$pin<T> {} | ||||
|             impl<T> WithInterrupt for gpio::$set::$pin<T> { | ||||
|                 type Interrupt = interrupt::$INT; | ||||
|             } | ||||
|  | ||||
|             #[cfg(any( | ||||
|                 feature = "stm32f401", | ||||
|                 feature = "stm32f405", | ||||
|                 feature = "stm32f407", | ||||
|                 feature = "stm32f410", | ||||
|                 feature = "stm32f411", | ||||
|                 feature = "stm32f412", | ||||
|                 feature = "stm32f413", | ||||
|                 feature = "stm32f415", | ||||
|                 feature = "stm32f417", | ||||
|                 feature = "stm32f423", | ||||
|                 feature = "stm32f427", | ||||
|                 feature = "stm32f429", | ||||
|                 feature = "stm32f437", | ||||
|                 feature = "stm32f439", | ||||
|                 feature = "stm32f446", | ||||
|                 feature = "stm32f469", | ||||
|                 feature = "stm32f479", | ||||
|             ))] | ||||
|             impl<T> Instance for gpio::$set::$pin<gpio::Input<T>> { | ||||
|                 fn make_source(&mut self, syscfg: &mut SysCfg) { | ||||
|                     use crate::hal::gpio::ExtiPin; | ||||
|                     self.make_interrupt_source(syscfg); | ||||
|                 } | ||||
|  | ||||
|                 fn clear_pending_bit(&mut self) { | ||||
|                     use crate::hal::{gpio::Edge, gpio::ExtiPin, syscfg::SysCfg}; | ||||
|  | ||||
|                     self.clear_interrupt_pending_bit(); | ||||
|                 } | ||||
|  | ||||
|                 fn trigger_edge(&mut self, edge: EdgeOption) { | ||||
|                     use crate::hal::{gpio::Edge, gpio::ExtiPin, syscfg::SysCfg}; | ||||
|                     use crate::pac::EXTI; | ||||
|                     let mut exti: EXTI = unsafe { mem::transmute(()) }; | ||||
|                     let edge = match edge { | ||||
|                         EdgeOption::Falling => Edge::FALLING, | ||||
|                         EdgeOption::Rising => Edge::RISING, | ||||
|                         EdgeOption::RisingFalling => Edge::RISING_FALLING, | ||||
|                     }; | ||||
|                     self.trigger_on_edge(&mut exti, edge); | ||||
|                     self.enable_interrupt(&mut exti); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             #[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))] | ||||
|             impl<T> Instance for gpio::$set::$pin<T> { | ||||
|                 fn make_source(&mut self, syscfg: &mut SysCfg) {} | ||||
|  | ||||
|                 fn clear_pending_bit(&mut self) { | ||||
|                     use crate::hal::{ | ||||
|                         exti::{Exti, ExtiLine, GpioLine, TriggerEdge}, | ||||
|                         syscfg::SYSCFG, | ||||
|                     }; | ||||
|  | ||||
|                     Exti::unpend(GpioLine::from_raw_line(self.pin_number()).unwrap()); | ||||
|                 } | ||||
|  | ||||
|                 fn trigger_edge(&mut self, edge: EdgeOption) { | ||||
|                     use crate::hal::{ | ||||
|                         exti::{Exti, ExtiLine, GpioLine, TriggerEdge}, | ||||
|                         syscfg::SYSCFG, | ||||
|                     }; | ||||
|  | ||||
|                     use crate::pac::EXTI; | ||||
|  | ||||
|                     let edge = match edge { | ||||
|                         EdgeOption::Falling => TriggerEdge::Falling, | ||||
|                         EdgeOption::Rising => TriggerEdge::Rising, | ||||
|                         EdgeOption::RisingFalling => TriggerEdge::Both, | ||||
|                     }; | ||||
|  | ||||
|                     let exti: EXTI = unsafe { mem::transmute(()) }; | ||||
|                     let mut exti = Exti::new(exti); | ||||
|                     let port = self.port(); | ||||
|                     let mut syscfg: SYSCFG = unsafe { mem::transmute(()) }; | ||||
|                     let line = GpioLine::from_raw_line(self.pin_number()).unwrap(); | ||||
|                     exti.listen_gpio(&mut syscfg, port, line, edge); | ||||
|                 } | ||||
|             } | ||||
|         )+ | ||||
|     }; | ||||
| } | ||||
|  | ||||
| #[cfg(any( | ||||
|     feature = "stm32f401", | ||||
|     feature = "stm32f405", | ||||
|     feature = "stm32f407", | ||||
|     feature = "stm32f410", | ||||
|     feature = "stm32f411", | ||||
|     feature = "stm32f412", | ||||
|     feature = "stm32f413", | ||||
|     feature = "stm32f415", | ||||
|     feature = "stm32f417", | ||||
|     feature = "stm32f423", | ||||
|     feature = "stm32f427", | ||||
|     feature = "stm32f429", | ||||
|     feature = "stm32f437", | ||||
|     feature = "stm32f439", | ||||
|     feature = "stm32f446", | ||||
|     feature = "stm32f469", | ||||
|     feature = "stm32f479" | ||||
| ))] | ||||
| exti!(gpioa, [ | ||||
|     EXTI0 => PA0, | ||||
|     EXTI1 => PA1, | ||||
|     EXTI2 => PA2, | ||||
|     EXTI3 => PA3, | ||||
|     EXTI4 => PA4, | ||||
|     EXTI9_5 => PA5, | ||||
|     EXTI9_5 => PA6, | ||||
|     EXTI9_5 => PA7, | ||||
|     EXTI9_5 => PA8, | ||||
|     EXTI9_5 => PA9, | ||||
|     EXTI15_10 => PA10, | ||||
|     EXTI15_10 => PA11, | ||||
|     EXTI15_10 => PA12, | ||||
|     EXTI15_10 => PA13, | ||||
|     EXTI15_10 => PA14, | ||||
|     EXTI15_10 => PA15, | ||||
| ]); | ||||
|  | ||||
| #[cfg(any( | ||||
|     feature = "stm32f401", | ||||
|     feature = "stm32f405", | ||||
|     feature = "stm32f407", | ||||
|     feature = "stm32f410", | ||||
|     feature = "stm32f411", | ||||
|     feature = "stm32f412", | ||||
|     feature = "stm32f413", | ||||
|     feature = "stm32f415", | ||||
|     feature = "stm32f417", | ||||
|     feature = "stm32f423", | ||||
|     feature = "stm32f427", | ||||
|     feature = "stm32f429", | ||||
|     feature = "stm32f437", | ||||
|     feature = "stm32f439", | ||||
|     feature = "stm32f446", | ||||
|     feature = "stm32f469", | ||||
|     feature = "stm32f479" | ||||
| ))] | ||||
| exti!(gpiob, [ | ||||
|     EXTI0 => PB0, | ||||
|     EXTI1 => PB1, | ||||
|     EXTI2 => PB2, | ||||
|     EXTI3 => PB3, | ||||
|     EXTI4 => PB4, | ||||
|     EXTI9_5 => PB5, | ||||
|     EXTI9_5 => PB6, | ||||
|     EXTI9_5 => PB7, | ||||
|     EXTI9_5 => PB8, | ||||
|     EXTI9_5 => PB9, | ||||
|     EXTI15_10 => PB10, | ||||
|     EXTI15_10 => PB11, | ||||
|     EXTI15_10 => PB12, | ||||
|     EXTI15_10 => PB13, | ||||
|     EXTI15_10 => PB14, | ||||
|     EXTI15_10 => PB15, | ||||
| ]); | ||||
|  | ||||
| #[cfg(any( | ||||
|     feature = "stm32f401", | ||||
|     feature = "stm32f405", | ||||
|     feature = "stm32f407", | ||||
|     feature = "stm32f410", | ||||
|     feature = "stm32f411", | ||||
|     feature = "stm32f412", | ||||
|     feature = "stm32f413", | ||||
|     feature = "stm32f415", | ||||
|     feature = "stm32f417", | ||||
|     feature = "stm32f423", | ||||
|     feature = "stm32f427", | ||||
|     feature = "stm32f429", | ||||
|     feature = "stm32f437", | ||||
|     feature = "stm32f439", | ||||
|     feature = "stm32f446", | ||||
|     feature = "stm32f469", | ||||
|     feature = "stm32f479" | ||||
| ))] | ||||
| exti!(gpioc, [ | ||||
|     EXTI0 => PC0, | ||||
|     EXTI1 => PC1, | ||||
|     EXTI2 => PC2, | ||||
|     EXTI3 => PC3, | ||||
|     EXTI4 => PC4, | ||||
|     EXTI9_5 => PC5, | ||||
|     EXTI9_5 => PC6, | ||||
|     EXTI9_5 => PC7, | ||||
|     EXTI9_5 => PC8, | ||||
|     EXTI9_5 => PC9, | ||||
|     EXTI15_10 => PC10, | ||||
|     EXTI15_10 => PC11, | ||||
|     EXTI15_10 => PC12, | ||||
|     EXTI15_10 => PC13, | ||||
|     EXTI15_10 => PC14, | ||||
|     EXTI15_10 => PC15, | ||||
| ]); | ||||
|  | ||||
| #[cfg(any( | ||||
|     feature = "stm32f401", | ||||
|     feature = "stm32f405", | ||||
|     feature = "stm32f407", | ||||
|     feature = "stm32f411", | ||||
|     feature = "stm32f412", | ||||
|     feature = "stm32f413", | ||||
|     feature = "stm32f415", | ||||
|     feature = "stm32f417", | ||||
|     feature = "stm32f423", | ||||
|     feature = "stm32f427", | ||||
|     feature = "stm32f429", | ||||
|     feature = "stm32f437", | ||||
|     feature = "stm32f439", | ||||
|     feature = "stm32f446", | ||||
|     feature = "stm32f469", | ||||
|     feature = "stm32f479" | ||||
| ))] | ||||
| exti!(gpiod, [ | ||||
|     EXTI0 => PD0, | ||||
|     EXTI1 => PD1, | ||||
|     EXTI2 => PD2, | ||||
|     EXTI3 => PD3, | ||||
|     EXTI4 => PD4, | ||||
|     EXTI9_5 => PD5, | ||||
|     EXTI9_5 => PD6, | ||||
|     EXTI9_5 => PD7, | ||||
|     EXTI9_5 => PD8, | ||||
|     EXTI9_5 => PD9, | ||||
|     EXTI15_10 => PD10, | ||||
|     EXTI15_10 => PD11, | ||||
|     EXTI15_10 => PD12, | ||||
|     EXTI15_10 => PD13, | ||||
|     EXTI15_10 => PD14, | ||||
|     EXTI15_10 => PD15, | ||||
| ]); | ||||
|  | ||||
| #[cfg(any( | ||||
|     feature = "stm32f401", | ||||
|     feature = "stm32f405", | ||||
|     feature = "stm32f407", | ||||
|     feature = "stm32f411", | ||||
|     feature = "stm32f412", | ||||
|     feature = "stm32f413", | ||||
|     feature = "stm32f415", | ||||
|     feature = "stm32f417", | ||||
|     feature = "stm32f423", | ||||
|     feature = "stm32f427", | ||||
|     feature = "stm32f429", | ||||
|     feature = "stm32f437", | ||||
|     feature = "stm32f439", | ||||
|     feature = "stm32f446", | ||||
|     feature = "stm32f469", | ||||
|     feature = "stm32f479" | ||||
| ))] | ||||
| exti!(gpioe, [ | ||||
|     EXTI0 => PE0, | ||||
|     EXTI1 => PE1, | ||||
|     EXTI2 => PE2, | ||||
|     EXTI3 => PE3, | ||||
|     EXTI4 => PE4, | ||||
|     EXTI9_5 => PE5, | ||||
|     EXTI9_5 => PE6, | ||||
|     EXTI9_5 => PE7, | ||||
|     EXTI9_5 => PE8, | ||||
|     EXTI9_5 => PE9, | ||||
|     EXTI15_10 => PE10, | ||||
|     EXTI15_10 => PE11, | ||||
|     EXTI15_10 => PE12, | ||||
|     EXTI15_10 => PE13, | ||||
|     EXTI15_10 => PE14, | ||||
|     EXTI15_10 => PE15, | ||||
| ]); | ||||
|  | ||||
| #[cfg(any( | ||||
|     feature = "stm32f405", | ||||
|     feature = "stm32f407", | ||||
|     feature = "stm32f412", | ||||
|     feature = "stm32f413", | ||||
|     feature = "stm32f415", | ||||
|     feature = "stm32f417", | ||||
|     feature = "stm32f423", | ||||
|     feature = "stm32f427", | ||||
|     feature = "stm32f429", | ||||
|     feature = "stm32f437", | ||||
|     feature = "stm32f439", | ||||
|     feature = "stm32f446", | ||||
|     feature = "stm32f469", | ||||
|     feature = "stm32f479" | ||||
| ))] | ||||
| exti!(gpiof, [ | ||||
|     EXTI0 => PF0, | ||||
|     EXTI1 => PF1, | ||||
|     EXTI2 => PF2, | ||||
|     EXTI3 => PF3, | ||||
|     EXTI4 => PF4, | ||||
|     EXTI9_5 => PF5, | ||||
|     EXTI9_5 => PF6, | ||||
|     EXTI9_5 => PF7, | ||||
|     EXTI9_5 => PF8, | ||||
|     EXTI9_5 => PF9, | ||||
|     EXTI15_10 => PF10, | ||||
|     EXTI15_10 => PF11, | ||||
|     EXTI15_10 => PF12, | ||||
|     EXTI15_10 => PF13, | ||||
|     EXTI15_10 => PF14, | ||||
|     EXTI15_10 => PF15, | ||||
| ]); | ||||
|  | ||||
| #[cfg(any( | ||||
|     feature = "stm32f405", | ||||
|     feature = "stm32f407", | ||||
|     feature = "stm32f412", | ||||
|     feature = "stm32f413", | ||||
|     feature = "stm32f415", | ||||
|     feature = "stm32f417", | ||||
|     feature = "stm32f423", | ||||
|     feature = "stm32f427", | ||||
|     feature = "stm32f429", | ||||
|     feature = "stm32f437", | ||||
|     feature = "stm32f439", | ||||
|     feature = "stm32f446", | ||||
|     feature = "stm32f469", | ||||
|     feature = "stm32f479" | ||||
| ))] | ||||
| exti!(gpiog, [ | ||||
|     EXTI0 => PG0, | ||||
|     EXTI1 => PG1, | ||||
|     EXTI2 => PG2, | ||||
|     EXTI3 => PG3, | ||||
|     EXTI4 => PG4, | ||||
|     EXTI9_5 => PG5, | ||||
|     EXTI9_5 => PG6, | ||||
|     EXTI9_5 => PG7, | ||||
|     EXTI9_5 => PG8, | ||||
|     EXTI9_5 => PG9, | ||||
|     EXTI15_10 => PG10, | ||||
|     EXTI15_10 => PG11, | ||||
|     EXTI15_10 => PG12, | ||||
|     EXTI15_10 => PG13, | ||||
|     EXTI15_10 => PG14, | ||||
|     EXTI15_10 => PG15, | ||||
| ]); | ||||
|  | ||||
| #[cfg(any( | ||||
|     feature = "stm32f405", | ||||
|     feature = "stm32f407", | ||||
|     feature = "stm32f410", | ||||
|     feature = "stm32f411", | ||||
|     feature = "stm32f412", | ||||
|     feature = "stm32f413", | ||||
|     feature = "stm32f415", | ||||
|     feature = "stm32f417", | ||||
|     feature = "stm32f423", | ||||
|     feature = "stm32f427", | ||||
|     feature = "stm32f429", | ||||
|     feature = "stm32f437", | ||||
|     feature = "stm32f439", | ||||
|     feature = "stm32f446", | ||||
|     feature = "stm32f469", | ||||
|     feature = "stm32f479" | ||||
| ))] | ||||
| exti!(gpioh, [ | ||||
|     EXTI0 => PH0, | ||||
|     EXTI1 => PH1, | ||||
|     EXTI2 => PH2, | ||||
|     EXTI3 => PH3, | ||||
|     EXTI4 => PH4, | ||||
|     EXTI9_5 => PH5, | ||||
|     EXTI9_5 => PH6, | ||||
|     EXTI9_5 => PH7, | ||||
|     EXTI9_5 => PH8, | ||||
|     EXTI9_5 => PH9, | ||||
|     EXTI15_10 => PH10, | ||||
|     EXTI15_10 => PH11, | ||||
|     EXTI15_10 => PH12, | ||||
|     EXTI15_10 => PH13, | ||||
|     EXTI15_10 => PH14, | ||||
|     EXTI15_10 => PH15, | ||||
| ]); | ||||
|  | ||||
| #[cfg(any(feature = "stm32f401"))] | ||||
| exti!(gpioh, [ | ||||
|     EXTI0 => PH0, | ||||
|     EXTI1 => PH1, | ||||
| ]); | ||||
|  | ||||
| #[cfg(any( | ||||
|     feature = "stm32f405", | ||||
|     feature = "stm32f407", | ||||
|     feature = "stm32f415", | ||||
|     feature = "stm32f417", | ||||
|     feature = "stm32f427", | ||||
|     feature = "stm32f429", | ||||
|     feature = "stm32f437", | ||||
|     feature = "stm32f439", | ||||
|     feature = "stm32f469", | ||||
|     feature = "stm32f479" | ||||
| ))] | ||||
| exti!(gpioi, [ | ||||
|     EXTI0 => PI0, | ||||
|     EXTI1 => PI1, | ||||
|     EXTI2 => PI2, | ||||
|     EXTI3 => PI3, | ||||
|     EXTI4 => PI4, | ||||
|     EXTI9_5 => PI5, | ||||
|     EXTI9_5 => PI6, | ||||
|     EXTI9_5 => PI7, | ||||
|     EXTI9_5 => PI8, | ||||
|     EXTI9_5 => PI9, | ||||
|     EXTI15_10 => PI10, | ||||
|     EXTI15_10 => PI11, | ||||
|     EXTI15_10 => PI12, | ||||
|     EXTI15_10 => PI13, | ||||
|     EXTI15_10 => PI14, | ||||
|     EXTI15_10 => PI15, | ||||
| ]); | ||||
|  | ||||
| #[cfg(any( | ||||
|     feature = "stm32f427", | ||||
|     feature = "stm32f429", | ||||
|     feature = "stm32f437", | ||||
|     feature = "stm32f439", | ||||
|     feature = "stm32f469", | ||||
|     feature = "stm32f479" | ||||
| ))] | ||||
| exti!(gpioj, [ | ||||
|     EXTI0 => PJ0, | ||||
|     EXTI1 => PJ1, | ||||
|     EXTI2 => PJ2, | ||||
|     EXTI3 => PJ3, | ||||
|     EXTI4 => PJ4, | ||||
|     EXTI9_5 => PJ5, | ||||
|     EXTI9_5 => PJ6, | ||||
|     EXTI9_5 => PJ7, | ||||
|     EXTI9_5 => PJ8, | ||||
|     EXTI9_5 => PJ9, | ||||
|     EXTI15_10 => PJ10, | ||||
|     EXTI15_10 => PJ11, | ||||
|     EXTI15_10 => PJ12, | ||||
|     EXTI15_10 => PJ13, | ||||
|     EXTI15_10 => PJ14, | ||||
|     EXTI15_10 => PJ15, | ||||
| ]); | ||||
|  | ||||
| #[cfg(any( | ||||
|     feature = "stm32f427", | ||||
|     feature = "stm32f429", | ||||
|     feature = "stm32f437", | ||||
|     feature = "stm32f439", | ||||
|     feature = "stm32f469", | ||||
|     feature = "stm32f479" | ||||
| ))] | ||||
| exti!(gpiok, [ | ||||
|     EXTI0 => PK0, | ||||
|     EXTI1 => PK1, | ||||
|     EXTI2 => PK2, | ||||
|     EXTI3 => PK3, | ||||
|     EXTI4 => PK4, | ||||
|     EXTI9_5 => PK5, | ||||
|     EXTI9_5 => PK6, | ||||
|     EXTI9_5 => PK7, | ||||
| ]); | ||||
|  | ||||
| #[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))] | ||||
| exti!(gpioa, [ | ||||
|     EXTI0_1 => PA0, | ||||
|     EXTI0_1 => PA1, | ||||
|     EXTI2_3 => PA2, | ||||
|     EXTI2_3 => PA3, | ||||
|     EXTI4_15 => PA4, | ||||
|     EXTI4_15 => PA5, | ||||
|     EXTI4_15 => PA6, | ||||
|     EXTI4_15 => PA7, | ||||
|     EXTI4_15 => PA8, | ||||
|     EXTI4_15 => PA9, | ||||
|     EXTI4_15 => PA10, | ||||
|     EXTI4_15 => PA11, | ||||
|     EXTI4_15 => PA12, | ||||
|     EXTI4_15 => PA13, | ||||
|     EXTI4_15 => PA14, | ||||
|     EXTI4_15 => PA15, | ||||
| ]); | ||||
|  | ||||
| #[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))] | ||||
| exti!(gpiob, [ | ||||
|     EXTI0_1 => PB0, | ||||
|     EXTI0_1 => PB1, | ||||
|     EXTI2_3 => PB2, | ||||
|     EXTI2_3 => PB3, | ||||
|     EXTI4_15 => PB4, | ||||
|     EXTI4_15 => PB5, | ||||
|     EXTI4_15 => PB6, | ||||
|     EXTI4_15 => PB7, | ||||
|     EXTI4_15 => PB8, | ||||
|     EXTI4_15 => PB9, | ||||
|     EXTI4_15 => PB10, | ||||
|     EXTI4_15 => PB11, | ||||
|     EXTI4_15 => PB12, | ||||
|     EXTI4_15 => PB13, | ||||
|     EXTI4_15 => PB14, | ||||
|     EXTI4_15 => PB15, | ||||
| ]); | ||||
|  | ||||
| #[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))] | ||||
| exti!(gpioc, [ | ||||
|     EXTI0_1 => PC0, | ||||
|     EXTI0_1 => PC1, | ||||
|     EXTI2_3 => PC2, | ||||
|     EXTI2_3 => PC3, | ||||
|     EXTI4_15 => PC4, | ||||
|     EXTI4_15 => PC5, | ||||
|     EXTI4_15 => PC6, | ||||
|     EXTI4_15 => PC7, | ||||
|     EXTI4_15 => PC8, | ||||
|     EXTI4_15 => PC9, | ||||
|     EXTI4_15 => PC10, | ||||
|     EXTI4_15 => PC11, | ||||
|     EXTI4_15 => PC12, | ||||
|     EXTI4_15 => PC13, | ||||
|     EXTI4_15 => PC14, | ||||
|     EXTI4_15 => PC15, | ||||
| ]); | ||||
|  | ||||
| #[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))] | ||||
| exti!(gpiod, [ | ||||
|     EXTI0_1 => PD0, | ||||
|     EXTI0_1 => PD1, | ||||
|     EXTI2_3 => PD2, | ||||
|     EXTI2_3 => PD3, | ||||
|     EXTI4_15 => PD4, | ||||
|     EXTI4_15 => PD5, | ||||
|     EXTI4_15 => PD6, | ||||
|     EXTI4_15 => PD7, | ||||
|     EXTI4_15 => PD8, | ||||
|     EXTI4_15 => PD9, | ||||
|     EXTI4_15 => PD10, | ||||
|     EXTI4_15 => PD11, | ||||
|     EXTI4_15 => PD12, | ||||
|     EXTI4_15 => PD13, | ||||
|     EXTI4_15 => PD14, | ||||
|     EXTI4_15 => PD15, | ||||
| ]); | ||||
|  | ||||
| #[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))] | ||||
| exti!(gpioe, [ | ||||
|     EXTI0_1 => PE0, | ||||
|     EXTI0_1 => PE1, | ||||
|     EXTI2_3 => PE2, | ||||
|     EXTI2_3 => PE3, | ||||
|     EXTI4_15 => PE4, | ||||
|     EXTI4_15 => PE5, | ||||
|     EXTI4_15 => PE6, | ||||
|     EXTI4_15 => PE7, | ||||
|     EXTI4_15 => PE8, | ||||
|     EXTI4_15 => PE9, | ||||
|     EXTI4_15 => PE10, | ||||
|     EXTI4_15 => PE11, | ||||
|     EXTI4_15 => PE12, | ||||
|     EXTI4_15 => PE13, | ||||
|     EXTI4_15 => PE14, | ||||
|     EXTI4_15 => PE15, | ||||
| ]); | ||||
|  | ||||
| #[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))] | ||||
| exti!(gpioh, [ | ||||
|     EXTI0_1 => PH0, | ||||
|     EXTI0_1 => PH1, | ||||
|     EXTI4_15 => PH9, | ||||
|     EXTI4_15 => PH10, | ||||
| ]); | ||||
| @@ -1,4 +0,0 @@ | ||||
| pub mod rtc; | ||||
| pub mod serial; | ||||
| pub mod spi; | ||||
| pub mod system; | ||||
| @@ -1,505 +0,0 @@ | ||||
| use crate::hal::bb; | ||||
| use crate::hal::rcc::Clocks; | ||||
| use core::cell::Cell; | ||||
| use core::convert::TryInto; | ||||
| use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; | ||||
| use critical_section::CriticalSection; | ||||
| use embassy::interrupt::InterruptExt; | ||||
| use embassy::time::{Clock, TICKS_PER_SECOND}; | ||||
| use embassy::util::CriticalSectionMutex as Mutex; | ||||
|  | ||||
| use crate::interrupt; | ||||
| use crate::interrupt::Interrupt; | ||||
|  | ||||
| // RTC timekeeping works with something we call "periods", which are time intervals | ||||
| // of 2^15 ticks. The RTC counter value is 16 bits, so one "overflow cycle" is 2 periods. | ||||
| // | ||||
| // A `period` count is maintained in parallel to the RTC hardware `counter`, like this: | ||||
| // - `period` and `counter` start at 0 | ||||
| // - `period` is incremented on overflow (at counter value 0) | ||||
| // - `period` is incremented "midway" between overflows (at counter value 0x8000) | ||||
| // | ||||
| // Therefore, when `period` is even, counter is in 0..0x7FFF. When odd, counter is in 0x8000..0xFFFF | ||||
| // This allows for now() to return the correct value even if it races an overflow. | ||||
| // | ||||
| // To get `now()`, `period` is read first, then `counter` is read. If the counter value matches | ||||
| // the expected range for the `period` parity, we're done. If it doesn't, this means that | ||||
| // a new period start has raced us between reading `period` and `counter`, so we assume the `counter` value | ||||
| // corresponds to the next period. | ||||
| // | ||||
| // `period` is a 32bit integer, so It overflows on 2^32 * 2^15 / 32768 seconds of uptime, which is 136 years. | ||||
| fn calc_now(period: u32, counter: u16) -> u64 { | ||||
|     ((period as u64) << 15) + ((counter as u32 ^ ((period & 1) << 15)) as u64) | ||||
| } | ||||
|  | ||||
| struct AlarmState { | ||||
|     timestamp: Cell<u64>, | ||||
|     callback: Cell<Option<(fn(*mut ()), *mut ())>>, | ||||
| } | ||||
|  | ||||
| impl AlarmState { | ||||
|     fn new() -> Self { | ||||
|         Self { | ||||
|             timestamp: Cell::new(u64::MAX), | ||||
|             callback: Cell::new(None), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| // TODO: This is sometimes wasteful, try to find a better way | ||||
| const ALARM_COUNT: usize = 3; | ||||
|  | ||||
| /// RTC timer that can be used by the executor and to set alarms. | ||||
| /// | ||||
| /// It can work with Timers 2, 3, 4, 5, 9 and 12. Timers 9 and 12 only have one alarm available, | ||||
| /// while the others have three each. | ||||
| /// This timer works internally with a unit of 2^15 ticks, which means that if a call to | ||||
| /// [`embassy::time::Clock::now`] is blocked for that amount of ticks the returned value will be | ||||
| /// wrong (an old value). The current default tick rate is 32768 ticks per second. | ||||
| pub struct RTC<T: Instance> { | ||||
|     rtc: T, | ||||
|     irq: T::Interrupt, | ||||
|  | ||||
|     /// Number of 2^23 periods elapsed since boot. | ||||
|     period: AtomicU32, | ||||
|  | ||||
|     /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled. | ||||
|     alarms: Mutex<[AlarmState; ALARM_COUNT]>, | ||||
|  | ||||
|     clocks: Clocks, | ||||
| } | ||||
|  | ||||
| impl<T: Instance> RTC<T> { | ||||
|     pub fn new(rtc: T, irq: T::Interrupt, clocks: Clocks) -> Self { | ||||
|         Self { | ||||
|             rtc, | ||||
|             irq, | ||||
|             period: AtomicU32::new(0), | ||||
|             alarms: Mutex::new([AlarmState::new(), AlarmState::new(), AlarmState::new()]), | ||||
|             clocks, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn start(&'static self) { | ||||
|         self.rtc.enable_clock(); | ||||
|         self.rtc.stop_and_reset(); | ||||
|  | ||||
|         let multiplier = if T::ppre(&self.clocks) == 1 { 1 } else { 2 }; | ||||
|         let freq = T::pclk(&self.clocks) * multiplier; | ||||
|         let psc = freq / TICKS_PER_SECOND as u32 - 1; | ||||
|         let psc: u16 = psc.try_into().unwrap(); | ||||
|  | ||||
|         self.rtc.set_psc_arr(psc, u16::MAX); | ||||
|         // Mid-way point | ||||
|         self.rtc.set_compare(0, 0x8000); | ||||
|         self.rtc.set_compare_interrupt(0, true); | ||||
|  | ||||
|         self.irq.set_handler(|ptr| unsafe { | ||||
|             let this = &*(ptr as *const () as *const Self); | ||||
|             this.on_interrupt(); | ||||
|         }); | ||||
|         self.irq.set_handler_context(self as *const _ as *mut _); | ||||
|         self.irq.unpend(); | ||||
|         self.irq.enable(); | ||||
|  | ||||
|         self.rtc.start(); | ||||
|     } | ||||
|  | ||||
|     fn on_interrupt(&self) { | ||||
|         if self.rtc.overflow_interrupt_status() { | ||||
|             self.rtc.overflow_clear_flag(); | ||||
|             self.next_period(); | ||||
|         } | ||||
|  | ||||
|         // Half overflow | ||||
|         if self.rtc.compare_interrupt_status(0) { | ||||
|             self.rtc.compare_clear_flag(0); | ||||
|             self.next_period(); | ||||
|         } | ||||
|  | ||||
|         for n in 1..=ALARM_COUNT { | ||||
|             if self.rtc.compare_interrupt_status(n) { | ||||
|                 self.rtc.compare_clear_flag(n); | ||||
|                 critical_section::with(|cs| self.trigger_alarm(n, cs)); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn next_period(&self) { | ||||
|         critical_section::with(|cs| { | ||||
|             let period = self.period.fetch_add(1, Ordering::Relaxed) + 1; | ||||
|             let t = (period as u64) << 15; | ||||
|  | ||||
|             for n in 1..=ALARM_COUNT { | ||||
|                 let alarm = &self.alarms.borrow(cs)[n - 1]; | ||||
|                 let at = alarm.timestamp.get(); | ||||
|  | ||||
|                 let diff = at - t; | ||||
|                 if diff < 0xc000 { | ||||
|                     self.rtc.set_compare(n, at as u16); | ||||
|                     self.rtc.set_compare_interrupt(n, true); | ||||
|                 } | ||||
|             } | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     fn trigger_alarm(&self, n: usize, cs: CriticalSection) { | ||||
|         self.rtc.set_compare_interrupt(n, false); | ||||
|  | ||||
|         let alarm = &self.alarms.borrow(cs)[n - 1]; | ||||
|         alarm.timestamp.set(u64::MAX); | ||||
|  | ||||
|         // Call after clearing alarm, so the callback can set another alarm. | ||||
|         if let Some((f, ctx)) = alarm.callback.get() { | ||||
|             f(ctx); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn set_alarm_callback(&self, n: usize, callback: fn(*mut ()), ctx: *mut ()) { | ||||
|         critical_section::with(|cs| { | ||||
|             let alarm = &self.alarms.borrow(cs)[n - 1]; | ||||
|             alarm.callback.set(Some((callback, ctx))); | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     fn set_alarm(&self, n: usize, timestamp: u64) { | ||||
|         critical_section::with(|cs| { | ||||
|             let alarm = &self.alarms.borrow(cs)[n - 1]; | ||||
|             alarm.timestamp.set(timestamp); | ||||
|  | ||||
|             let t = self.now(); | ||||
|             if timestamp <= t { | ||||
|                 self.trigger_alarm(n, cs); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             let diff = timestamp - t; | ||||
|             if diff < 0xc000 { | ||||
|                 let safe_timestamp = timestamp.max(t + 3); | ||||
|                 self.rtc.set_compare(n, safe_timestamp as u16); | ||||
|                 self.rtc.set_compare_interrupt(n, true); | ||||
|             } else { | ||||
|                 self.rtc.set_compare_interrupt(n, false); | ||||
|             } | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     pub fn alarm1(&'static self) -> Alarm<T> { | ||||
|         Alarm { n: 1, rtc: self } | ||||
|     } | ||||
|     pub fn alarm2(&'static self) -> Option<Alarm<T>> { | ||||
|         if T::REAL_ALARM_COUNT >= 2 { | ||||
|             Some(Alarm { n: 2, rtc: self }) | ||||
|         } else { | ||||
|             None | ||||
|         } | ||||
|     } | ||||
|     pub fn alarm3(&'static self) -> Option<Alarm<T>> { | ||||
|         if T::REAL_ALARM_COUNT >= 3 { | ||||
|             Some(Alarm { n: 3, rtc: self }) | ||||
|         } else { | ||||
|             None | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: Instance> embassy::time::Clock for RTC<T> { | ||||
|     fn now(&self) -> u64 { | ||||
|         let period = self.period.load(Ordering::Relaxed); | ||||
|         compiler_fence(Ordering::Acquire); | ||||
|         let counter = self.rtc.counter(); | ||||
|         calc_now(period, counter) | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub struct Alarm<T: Instance> { | ||||
|     n: usize, | ||||
|     rtc: &'static RTC<T>, | ||||
| } | ||||
|  | ||||
| impl<T: Instance> embassy::time::Alarm for Alarm<T> { | ||||
|     fn set_callback(&self, callback: fn(*mut ()), ctx: *mut ()) { | ||||
|         self.rtc.set_alarm_callback(self.n, callback, ctx); | ||||
|     } | ||||
|  | ||||
|     fn set(&self, timestamp: u64) { | ||||
|         self.rtc.set_alarm(self.n, timestamp); | ||||
|     } | ||||
|  | ||||
|     fn clear(&self) { | ||||
|         self.rtc.set_alarm(self.n, u64::MAX); | ||||
|     } | ||||
| } | ||||
|  | ||||
| mod sealed { | ||||
|     pub trait Sealed {} | ||||
| } | ||||
|  | ||||
| pub trait Instance: sealed::Sealed + Sized + 'static { | ||||
|     type Interrupt: Interrupt; | ||||
|     const REAL_ALARM_COUNT: usize; | ||||
|  | ||||
|     fn enable_clock(&self); | ||||
|     fn set_compare(&self, n: usize, value: u16); | ||||
|     fn set_compare_interrupt(&self, n: usize, enable: bool); | ||||
|     fn compare_interrupt_status(&self, n: usize) -> bool; | ||||
|     fn compare_clear_flag(&self, n: usize); | ||||
|     fn overflow_interrupt_status(&self) -> bool; | ||||
|     fn overflow_clear_flag(&self); | ||||
|     // This method should ensure that the values are really updated before returning | ||||
|     fn set_psc_arr(&self, psc: u16, arr: u16); | ||||
|     fn stop_and_reset(&self); | ||||
|     fn start(&self); | ||||
|     fn counter(&self) -> u16; | ||||
|     fn ppre(clocks: &Clocks) -> u8; | ||||
|     fn pclk(clocks: &Clocks) -> u32; | ||||
| } | ||||
|  | ||||
| #[allow(unused_macros)] | ||||
| macro_rules! impl_timer { | ||||
|     ($module:ident: ($TYPE:ident, $INT:ident, $apbenr:ident, $enrbit:expr, $apbrstr:ident, $rstrbit:expr, $ppre:ident, $pclk: ident), 3) => { | ||||
|         mod $module { | ||||
|             use super::*; | ||||
|             use crate::hal::pac::{$TYPE, RCC}; | ||||
|  | ||||
|             impl sealed::Sealed for $TYPE {} | ||||
|  | ||||
|             impl Instance for $TYPE { | ||||
|                 type Interrupt = interrupt::$INT; | ||||
|                 const REAL_ALARM_COUNT: usize = 3; | ||||
|  | ||||
|                 fn enable_clock(&self) { | ||||
|                     // NOTE(unsafe) It will only be used for atomic operations | ||||
|                     unsafe { | ||||
|                         let rcc = &*RCC::ptr(); | ||||
|  | ||||
|                         bb::set(&rcc.$apbenr, $enrbit); | ||||
|                         bb::set(&rcc.$apbrstr, $rstrbit); | ||||
|                         bb::clear(&rcc.$apbrstr, $rstrbit); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 fn set_compare(&self, n: usize, value: u16) { | ||||
|                     // NOTE(unsafe) these registers accept all the range of u16 values | ||||
|                     match n { | ||||
|                         0 => self.ccr1.write(|w| unsafe { w.bits(value.into()) }), | ||||
|                         1 => self.ccr2.write(|w| unsafe { w.bits(value.into()) }), | ||||
|                         2 => self.ccr3.write(|w| unsafe { w.bits(value.into()) }), | ||||
|                         3 => self.ccr4.write(|w| unsafe { w.bits(value.into()) }), | ||||
|                         _ => {} | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 fn set_compare_interrupt(&self, n: usize, enable: bool) { | ||||
|                     if n > 3 { | ||||
|                         return; | ||||
|                     } | ||||
|                     let bit = n as u8 + 1; | ||||
|                     unsafe { | ||||
|                         if enable { | ||||
|                             bb::set(&self.dier, bit); | ||||
|                         } else { | ||||
|                             bb::clear(&self.dier, bit); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 fn compare_interrupt_status(&self, n: usize) -> bool { | ||||
|                     let status = self.sr.read(); | ||||
|                     match n { | ||||
|                         0 => status.cc1if().bit_is_set(), | ||||
|                         1 => status.cc2if().bit_is_set(), | ||||
|                         2 => status.cc3if().bit_is_set(), | ||||
|                         3 => status.cc4if().bit_is_set(), | ||||
|                         _ => false, | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 fn compare_clear_flag(&self, n: usize) { | ||||
|                     if n > 3 { | ||||
|                         return; | ||||
|                     } | ||||
|                     let bit = n as u8 + 1; | ||||
|                     unsafe { | ||||
|                         bb::clear(&self.sr, bit); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 fn overflow_interrupt_status(&self) -> bool { | ||||
|                     self.sr.read().uif().bit_is_set() | ||||
|                 } | ||||
|  | ||||
|                 fn overflow_clear_flag(&self) { | ||||
|                     unsafe { | ||||
|                         bb::clear(&self.sr, 0); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 fn set_psc_arr(&self, psc: u16, arr: u16) { | ||||
|                     // NOTE(unsafe) All u16 values are valid | ||||
|                     self.psc.write(|w| unsafe { w.bits(psc.into()) }); | ||||
|                     self.arr.write(|w| unsafe { w.bits(arr.into()) }); | ||||
|  | ||||
|                     unsafe { | ||||
|                         // Set URS, generate update, clear URS | ||||
|                         bb::set(&self.cr1, 2); | ||||
|                         self.egr.write(|w| w.ug().set_bit()); | ||||
|                         bb::clear(&self.cr1, 2); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 fn stop_and_reset(&self) { | ||||
|                     unsafe { | ||||
|                         bb::clear(&self.cr1, 0); | ||||
|                     } | ||||
|                     self.cnt.reset(); | ||||
|                 } | ||||
|  | ||||
|                 fn start(&self) { | ||||
|                     unsafe { bb::set(&self.cr1, 0) } | ||||
|                 } | ||||
|  | ||||
|                 fn counter(&self) -> u16 { | ||||
|                     self.cnt.read().bits() as u16 | ||||
|                 } | ||||
|  | ||||
|                 fn ppre(clocks: &Clocks) -> u8 { | ||||
|                     clocks.$ppre() | ||||
|                 } | ||||
|  | ||||
|                 fn pclk(clocks: &Clocks) -> u32 { | ||||
|                     clocks.$pclk().0 | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     ($module:ident: ($TYPE:ident, $INT:ident, $apbenr:ident, $enrbit:expr, $apbrstr:ident, $rstrbit:expr, $ppre:ident, $pclk: ident), 1) => { | ||||
|         mod $module { | ||||
|             use super::*; | ||||
|             use crate::hal::pac::{$TYPE, RCC}; | ||||
|  | ||||
|             impl sealed::Sealed for $TYPE {} | ||||
|  | ||||
|             impl Instance for $TYPE { | ||||
|                 type Interrupt = interrupt::$INT; | ||||
|                 const REAL_ALARM_COUNT: usize = 1; | ||||
|  | ||||
|                 fn enable_clock(&self) { | ||||
|                     // NOTE(unsafe) It will only be used for atomic operations | ||||
|                     unsafe { | ||||
|                         let rcc = &*RCC::ptr(); | ||||
|  | ||||
|                         bb::set(&rcc.$apbenr, $enrbit); | ||||
|                         bb::set(&rcc.$apbrstr, $rstrbit); | ||||
|                         bb::clear(&rcc.$apbrstr, $rstrbit); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 fn set_compare(&self, n: usize, value: u16) { | ||||
|                     // NOTE(unsafe) these registers accept all the range of u16 values | ||||
|                     match n { | ||||
|                         0 => self.ccr1.write(|w| unsafe { w.bits(value.into()) }), | ||||
|                         1 => self.ccr2.write(|w| unsafe { w.bits(value.into()) }), | ||||
|                         _ => {} | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 fn set_compare_interrupt(&self, n: usize, enable: bool) { | ||||
|                     if n > 1 { | ||||
|                         return; | ||||
|                     } | ||||
|                     let bit = n as u8 + 1; | ||||
|                     unsafe { | ||||
|                         if enable { | ||||
|                             bb::set(&self.dier, bit); | ||||
|                         } else { | ||||
|                             bb::clear(&self.dier, bit); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 fn compare_interrupt_status(&self, n: usize) -> bool { | ||||
|                     let status = self.sr.read(); | ||||
|                     match n { | ||||
|                         0 => status.cc1if().bit_is_set(), | ||||
|                         1 => status.cc2if().bit_is_set(), | ||||
|                         _ => false, | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 fn compare_clear_flag(&self, n: usize) { | ||||
|                     if n > 1 { | ||||
|                         return; | ||||
|                     } | ||||
|                     let bit = n as u8 + 1; | ||||
|                     unsafe { | ||||
|                         bb::clear(&self.sr, bit); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 fn overflow_interrupt_status(&self) -> bool { | ||||
|                     self.sr.read().uif().bit_is_set() | ||||
|                 } | ||||
|  | ||||
|                 fn overflow_clear_flag(&self) { | ||||
|                     unsafe { | ||||
|                         bb::clear(&self.sr, 0); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 fn set_psc_arr(&self, psc: u16, arr: u16) { | ||||
|                     // NOTE(unsafe) All u16 values are valid | ||||
|                     self.psc.write(|w| unsafe { w.bits(psc.into()) }); | ||||
|                     self.arr.write(|w| unsafe { w.bits(arr.into()) }); | ||||
|  | ||||
|                     unsafe { | ||||
|                         // Set URS, generate update, clear URS | ||||
|                         bb::set(&self.cr1, 2); | ||||
|                         self.egr.write(|w| w.ug().set_bit()); | ||||
|                         bb::clear(&self.cr1, 2); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 fn stop_and_reset(&self) { | ||||
|                     unsafe { | ||||
|                         bb::clear(&self.cr1, 0); | ||||
|                     } | ||||
|                     self.cnt.reset(); | ||||
|                 } | ||||
|  | ||||
|                 fn start(&self) { | ||||
|                     unsafe { bb::set(&self.cr1, 0) } | ||||
|                 } | ||||
|  | ||||
|                 fn counter(&self) -> u16 { | ||||
|                     self.cnt.read().bits() as u16 | ||||
|                 } | ||||
|  | ||||
|                 fn ppre(clocks: &Clocks) -> u8 { | ||||
|                     clocks.$ppre() | ||||
|                 } | ||||
|  | ||||
|                 fn pclk(clocks: &Clocks) -> u32 { | ||||
|                     clocks.$pclk().0 | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
| } | ||||
|  | ||||
| #[cfg(not(feature = "stm32f410"))] | ||||
| impl_timer!(tim2: (TIM2, TIM2, apb1enr, 0, apb1rstr, 0, ppre1, pclk1), 3); | ||||
|  | ||||
| #[cfg(not(feature = "stm32f410"))] | ||||
| impl_timer!(tim3: (TIM3, TIM3, apb1enr, 1, apb1rstr, 1, ppre1, pclk1), 3); | ||||
|  | ||||
| #[cfg(not(feature = "stm32f410"))] | ||||
| impl_timer!(tim4: (TIM4, TIM4, apb1enr, 2, apb1rstr, 2, ppre1, pclk1), 3); | ||||
|  | ||||
| impl_timer!(tim5: (TIM5, TIM5, apb1enr, 3, apb1rstr, 3, ppre1, pclk1), 3); | ||||
|  | ||||
| impl_timer!(tim9: (TIM9, TIM1_BRK_TIM9, apb2enr, 16, apb2rstr, 16, ppre2, pclk2), 1); | ||||
|  | ||||
| #[cfg(not(any(feature = "stm32f401", feature = "stm32f410", feature = "stm32f411")))] | ||||
| impl_timer!(tim12: (TIM12, TIM8_BRK_TIM12, apb1enr, 6, apb1rstr, 6, ppre1, pclk1), 1); | ||||
| @@ -1,357 +0,0 @@ | ||||
| //! Async Serial. | ||||
|  | ||||
| use core::future::Future; | ||||
| use core::marker::PhantomData; | ||||
| use embassy::interrupt::Interrupt; | ||||
| use embassy::traits::uart::{Error, Read, ReadUntilIdle, Write}; | ||||
| use embassy::util::InterruptFuture; | ||||
| use futures::{select_biased, FutureExt}; | ||||
|  | ||||
| use crate::hal::{ | ||||
|     dma, | ||||
|     dma::config::DmaConfig, | ||||
|     dma::traits::{Channel, DMASet, PeriAddress, Stream}, | ||||
|     dma::{MemoryToPeripheral, PeripheralToMemory, Transfer}, | ||||
|     rcc::Clocks, | ||||
|     serial, | ||||
|     serial::config::{Config as SerialConfig, DmaConfig as SerialDmaConfig}, | ||||
|     serial::{Event as SerialEvent, Pins}, | ||||
| }; | ||||
| use crate::interrupt; | ||||
| use crate::pac; | ||||
|  | ||||
| /// Interface to the Serial peripheral | ||||
| pub struct Serial< | ||||
|     USART: PeriAddress<MemSize = u8> + WithInterrupt, | ||||
|     TSTREAM: Stream + WithInterrupt, | ||||
|     RSTREAM: Stream + WithInterrupt, | ||||
|     CHANNEL: Channel, | ||||
| > { | ||||
|     tx_stream: Option<TSTREAM>, | ||||
|     rx_stream: Option<RSTREAM>, | ||||
|     usart: Option<USART>, | ||||
|     tx_int: TSTREAM::Interrupt, | ||||
|     rx_int: RSTREAM::Interrupt, | ||||
|     usart_int: USART::Interrupt, | ||||
|     channel: PhantomData<CHANNEL>, | ||||
| } | ||||
|  | ||||
| // static mut INSTANCE: *const Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> = ptr::null_mut(); | ||||
|  | ||||
| impl<USART, TSTREAM, RSTREAM, CHANNEL> Serial<USART, TSTREAM, RSTREAM, CHANNEL> | ||||
| where | ||||
|     USART: serial::Instance | ||||
|         + PeriAddress<MemSize = u8> | ||||
|         + DMASet<TSTREAM, CHANNEL, MemoryToPeripheral> | ||||
|         + DMASet<RSTREAM, CHANNEL, PeripheralToMemory> | ||||
|         + WithInterrupt, | ||||
|     TSTREAM: Stream + WithInterrupt, | ||||
|     RSTREAM: Stream + WithInterrupt, | ||||
|     CHANNEL: Channel, | ||||
| { | ||||
|     // Leaking futures is forbidden! | ||||
|     pub unsafe fn new<PINS>( | ||||
|         usart: USART, | ||||
|         streams: (TSTREAM, RSTREAM), | ||||
|         pins: PINS, | ||||
|         tx_int: TSTREAM::Interrupt, | ||||
|         rx_int: RSTREAM::Interrupt, | ||||
|         usart_int: USART::Interrupt, | ||||
|         mut config: SerialConfig, | ||||
|         clocks: Clocks, | ||||
|     ) -> Self | ||||
|     where | ||||
|         PINS: Pins<USART>, | ||||
|     { | ||||
|         config.dma = SerialDmaConfig::TxRx; | ||||
|  | ||||
|         let (usart, _) = serial::Serial::new(usart, pins, config, clocks) | ||||
|             .unwrap() | ||||
|             .release(); | ||||
|  | ||||
|         let (tx_stream, rx_stream) = streams; | ||||
|  | ||||
|         Serial { | ||||
|             tx_stream: Some(tx_stream), | ||||
|             rx_stream: Some(rx_stream), | ||||
|             usart: Some(usart), | ||||
|             tx_int: tx_int, | ||||
|             rx_int: rx_int, | ||||
|             usart_int: usart_int, | ||||
|             channel: PhantomData, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<USART, TSTREAM, RSTREAM, CHANNEL> Read for Serial<USART, TSTREAM, RSTREAM, CHANNEL> | ||||
| where | ||||
|     USART: serial::Instance | ||||
|         + PeriAddress<MemSize = u8> | ||||
|         + DMASet<TSTREAM, CHANNEL, MemoryToPeripheral> | ||||
|         + DMASet<RSTREAM, CHANNEL, PeripheralToMemory> | ||||
|         + WithInterrupt | ||||
|         + 'static, | ||||
|     TSTREAM: Stream + WithInterrupt + 'static, | ||||
|     RSTREAM: Stream + WithInterrupt + 'static, | ||||
|     CHANNEL: Channel + 'static, | ||||
| { | ||||
|     type ReadFuture<'a> = impl Future<Output = Result<(), Error>> + 'a; | ||||
|  | ||||
|     /// Receives serial data. | ||||
|     /// | ||||
|     /// The future is pending until the buffer is completely filled. | ||||
|     fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { | ||||
|         let static_buf = unsafe { core::mem::transmute::<&'a mut [u8], &'static mut [u8]>(buf) }; | ||||
|  | ||||
|         async move { | ||||
|             let rx_stream = self.rx_stream.take().unwrap(); | ||||
|             let usart = self.usart.take().unwrap(); | ||||
|  | ||||
|             let mut rx_transfer = Transfer::init( | ||||
|                 rx_stream, | ||||
|                 usart, | ||||
|                 static_buf, | ||||
|                 None, | ||||
|                 DmaConfig::default() | ||||
|                     .transfer_complete_interrupt(true) | ||||
|                     .memory_increment(true) | ||||
|                     .double_buffer(false), | ||||
|             ); | ||||
|  | ||||
|             let fut = InterruptFuture::new(&mut self.rx_int); | ||||
|             rx_transfer.start(|_usart| {}); | ||||
|             fut.await; | ||||
|  | ||||
|             let (rx_stream, usart, _, _) = rx_transfer.free(); | ||||
|             self.rx_stream.replace(rx_stream); | ||||
|             self.usart.replace(usart); | ||||
|  | ||||
|             Ok(()) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<USART, TSTREAM, RSTREAM, CHANNEL> Write for Serial<USART, TSTREAM, RSTREAM, CHANNEL> | ||||
| where | ||||
|     USART: serial::Instance | ||||
|         + PeriAddress<MemSize = u8> | ||||
|         + DMASet<TSTREAM, CHANNEL, MemoryToPeripheral> | ||||
|         + DMASet<RSTREAM, CHANNEL, PeripheralToMemory> | ||||
|         + WithInterrupt | ||||
|         + 'static, | ||||
|     TSTREAM: Stream + WithInterrupt + 'static, | ||||
|     RSTREAM: Stream + WithInterrupt + 'static, | ||||
|     CHANNEL: Channel + 'static, | ||||
| { | ||||
|     type WriteFuture<'a> = impl Future<Output = Result<(), Error>> + 'a; | ||||
|  | ||||
|     /// Sends serial data. | ||||
|     fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { | ||||
|         #[allow(mutable_transmutes)] | ||||
|         let static_buf = unsafe { core::mem::transmute::<&'a [u8], &'static mut [u8]>(buf) }; | ||||
|  | ||||
|         async move { | ||||
|             let tx_stream = self.tx_stream.take().unwrap(); | ||||
|             let usart = self.usart.take().unwrap(); | ||||
|  | ||||
|             let mut tx_transfer = Transfer::init( | ||||
|                 tx_stream, | ||||
|                 usart, | ||||
|                 static_buf, | ||||
|                 None, | ||||
|                 DmaConfig::default() | ||||
|                     .transfer_complete_interrupt(true) | ||||
|                     .memory_increment(true) | ||||
|                     .double_buffer(false), | ||||
|             ); | ||||
|  | ||||
|             let fut = InterruptFuture::new(&mut self.tx_int); | ||||
|  | ||||
|             tx_transfer.start(|_usart| {}); | ||||
|             fut.await; | ||||
|  | ||||
|             let (tx_stream, usart, _buf, _) = tx_transfer.free(); | ||||
|  | ||||
|             self.tx_stream.replace(tx_stream); | ||||
|             self.usart.replace(usart); | ||||
|  | ||||
|             Ok(()) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<USART, TSTREAM, RSTREAM, CHANNEL> ReadUntilIdle for Serial<USART, TSTREAM, RSTREAM, CHANNEL> | ||||
| where | ||||
|     USART: serial::Instance | ||||
|         + PeriAddress<MemSize = u8> | ||||
|         + DMASet<TSTREAM, CHANNEL, MemoryToPeripheral> | ||||
|         + DMASet<RSTREAM, CHANNEL, PeripheralToMemory> | ||||
|         + WithInterrupt | ||||
|         + 'static, | ||||
|     TSTREAM: Stream + WithInterrupt + 'static, | ||||
|     RSTREAM: Stream + WithInterrupt + 'static, | ||||
|     CHANNEL: Channel + 'static, | ||||
| { | ||||
|     type ReadUntilIdleFuture<'a> = impl Future<Output = Result<usize, Error>> + 'a; | ||||
|  | ||||
|     /// Receives serial data. | ||||
|     /// | ||||
|     /// The future is pending until either the buffer is completely full, or the RX line falls idle after receiving some data. | ||||
|     /// | ||||
|     /// Returns the number of bytes read. | ||||
|     fn read_until_idle<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadUntilIdleFuture<'a> { | ||||
|         let static_buf = unsafe { core::mem::transmute::<&'a mut [u8], &'static mut [u8]>(buf) }; | ||||
|  | ||||
|         async move { | ||||
|             let rx_stream = self.rx_stream.take().unwrap(); | ||||
|             let usart = self.usart.take().unwrap(); | ||||
|  | ||||
|             unsafe { | ||||
|                 /*  __HAL_UART_ENABLE_IT(&uart->UartHandle, UART_IT_IDLE); */ | ||||
|                 (*USART::ptr()).cr1.modify(|_, w| w.idleie().set_bit()); | ||||
|  | ||||
|                 /* __HAL_UART_CLEAR_IDLEFLAG(&uart->UartHandle); */ | ||||
|                 (*USART::ptr()).sr.read(); | ||||
|                 (*USART::ptr()).dr.read(); | ||||
|             }; | ||||
|  | ||||
|             let mut rx_transfer = Transfer::init( | ||||
|                 rx_stream, | ||||
|                 usart, | ||||
|                 static_buf, | ||||
|                 None, | ||||
|                 DmaConfig::default() | ||||
|                     .transfer_complete_interrupt(true) | ||||
|                     .memory_increment(true) | ||||
|                     .double_buffer(false), | ||||
|             ); | ||||
|  | ||||
|             let total_bytes = RSTREAM::get_number_of_transfers() as usize; | ||||
|  | ||||
|             let fut = InterruptFuture::new(&mut self.rx_int); | ||||
|             let fut_idle = InterruptFuture::new(&mut self.usart_int); | ||||
|  | ||||
|             rx_transfer.start(|_usart| {}); | ||||
|  | ||||
|             futures::future::select(fut, fut_idle).await; | ||||
|  | ||||
|             let (rx_stream, usart, _, _) = rx_transfer.free(); | ||||
|  | ||||
|             let remaining_bytes = RSTREAM::get_number_of_transfers() as usize; | ||||
|  | ||||
|             unsafe { | ||||
|                 (*USART::ptr()).cr1.modify(|_, w| w.idleie().clear_bit()); | ||||
|             } | ||||
|             self.rx_stream.replace(rx_stream); | ||||
|             self.usart.replace(usart); | ||||
|  | ||||
|             Ok(total_bytes - remaining_bytes) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| mod private { | ||||
|     pub trait Sealed {} | ||||
| } | ||||
|  | ||||
| pub trait WithInterrupt: private::Sealed { | ||||
|     type Interrupt: Interrupt; | ||||
| } | ||||
|  | ||||
| macro_rules! dma { | ||||
|      ($($PER:ident => ($dma:ident, $stream:ident),)+) => { | ||||
|          $( | ||||
|              impl private::Sealed for dma::$stream<pac::$dma> {} | ||||
|              impl WithInterrupt for dma::$stream<pac::$dma> { | ||||
|                  type Interrupt = interrupt::$PER; | ||||
|              } | ||||
|          )+ | ||||
|      } | ||||
|  } | ||||
|  | ||||
| macro_rules! usart { | ||||
|     ($($PER:ident => ($usart:ident),)+) => { | ||||
|         $( | ||||
|             impl private::Sealed for pac::$usart {} | ||||
|             impl WithInterrupt for pac::$usart { | ||||
|                 type Interrupt = interrupt::$PER; | ||||
|             } | ||||
|         )+ | ||||
|     } | ||||
| } | ||||
|  | ||||
| dma! { | ||||
|     DMA2_STREAM0 => (DMA2, Stream0), | ||||
|     DMA2_STREAM1 => (DMA2, Stream1), | ||||
|     DMA2_STREAM2 => (DMA2, Stream2), | ||||
|     DMA2_STREAM3 => (DMA2, Stream3), | ||||
|     DMA2_STREAM4 => (DMA2, Stream4), | ||||
|     DMA2_STREAM5 => (DMA2, Stream5), | ||||
|     DMA2_STREAM6 => (DMA2, Stream6), | ||||
|     DMA2_STREAM7 => (DMA2, Stream7), | ||||
|     DMA1_STREAM0 => (DMA1, Stream0), | ||||
|     DMA1_STREAM1 => (DMA1, Stream1), | ||||
|     DMA1_STREAM2 => (DMA1, Stream2), | ||||
|     DMA1_STREAM3 => (DMA1, Stream3), | ||||
|     DMA1_STREAM4 => (DMA1, Stream4), | ||||
|     DMA1_STREAM5 => (DMA1, Stream5), | ||||
|     DMA1_STREAM6 => (DMA1, Stream6), | ||||
| } | ||||
|  | ||||
| #[cfg(any(feature = "stm32f401", feature = "stm32f410", feature = "stm32f411",))] | ||||
| usart! { | ||||
|     USART1 => (USART1), | ||||
|     USART2 => (USART2), | ||||
|     USART6 => (USART6), | ||||
| } | ||||
|  | ||||
| #[cfg(any(feature = "stm32f405", feature = "stm32f407"))] | ||||
| usart! { | ||||
|     USART1 => (USART1), | ||||
|     USART2 => (USART2), | ||||
|     USART3 => (USART3), | ||||
|     USART6 => (USART6), | ||||
|  | ||||
|     UART4 => (UART4), | ||||
|     UART5 => (UART5), | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "stm32f412")] | ||||
| usart! { | ||||
|     USART1 => (USART1), | ||||
|     USART2 => (USART2), | ||||
|     USART3 => (USART3), | ||||
|     USART6 => (USART6), | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "stm32f413")] | ||||
| usart! { | ||||
|     USART1 => (USART1), | ||||
|     USART2 => (USART2), | ||||
|     USART3 => (USART3), | ||||
|     USART6 => (USART6), | ||||
|     USART7 => (USART7), | ||||
|     USART8 => (USART8), | ||||
|  | ||||
|     UART5 => (UART5), | ||||
|     UART9 => (UART9), | ||||
|     UART10 => (UART10), | ||||
| } | ||||
|  | ||||
| #[cfg(any( | ||||
|     feature = "stm32f427", | ||||
|     feature = "stm32f429", | ||||
|     feature = "stm32f446", | ||||
|     feature = "stm32f469" | ||||
| ))] | ||||
| usart! { | ||||
|     USART1 => (USART1), | ||||
|     USART2 => (USART2), | ||||
|     USART3 => (USART3), | ||||
|     USART6 => (USART6), | ||||
|  | ||||
|     UART4 => (UART4), | ||||
|     UART5 => (UART5), | ||||
| //    UART7 => (UART7), | ||||
| //    UART8 => (UART8), | ||||
| } | ||||
| @@ -1,492 +0,0 @@ | ||||
| //! Async SPI | ||||
|  | ||||
| use embassy::time; | ||||
|  | ||||
| use core::{future::Future, marker::PhantomData, mem, ops::Deref, pin::Pin, ptr}; | ||||
| use embassy::{interrupt::Interrupt, traits::spi::FullDuplex, util::InterruptFuture}; | ||||
| use nb; | ||||
|  | ||||
| pub use crate::hal::spi::{Mode, Phase, Polarity}; | ||||
| use crate::hal::{ | ||||
|     bb, dma, | ||||
|     dma::config::DmaConfig, | ||||
|     dma::traits::{Channel, DMASet, PeriAddress, Stream}, | ||||
|     dma::{MemoryToPeripheral, PeripheralToMemory, Transfer}, | ||||
|     rcc::Clocks, | ||||
|     spi::Pins, | ||||
|     time::Hertz, | ||||
| }; | ||||
| use crate::interrupt; | ||||
| use crate::pac; | ||||
| use futures::future; | ||||
|  | ||||
| #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||||
| #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||||
| #[non_exhaustive] | ||||
| pub enum Error { | ||||
|     TxBufferTooLong, | ||||
|     RxBufferTooLong, | ||||
|     Overrun, | ||||
|     ModeFault, | ||||
|     Crc, | ||||
| } | ||||
|  | ||||
| fn read_sr<T: Instance>(spi: &T) -> nb::Result<u8, Error> { | ||||
|     let sr = spi.sr.read(); | ||||
|     Err(if sr.ovr().bit_is_set() { | ||||
|         nb::Error::Other(Error::Overrun) | ||||
|     } else if sr.modf().bit_is_set() { | ||||
|         nb::Error::Other(Error::ModeFault) | ||||
|     } else if sr.crcerr().bit_is_set() { | ||||
|         nb::Error::Other(Error::Crc) | ||||
|     } else if sr.rxne().bit_is_set() { | ||||
|         // NOTE(read_volatile) read only 1 byte (the svd2rust API only allows | ||||
|         // reading a half-word) | ||||
|         return Ok(unsafe { ptr::read_volatile(&spi.dr as *const _ as *const u8) }); | ||||
|     } else { | ||||
|         nb::Error::WouldBlock | ||||
|     }) | ||||
| } | ||||
|  | ||||
| fn write_sr<T: Instance>(spi: &T, byte: u8) -> nb::Result<(), Error> { | ||||
|     let sr = spi.sr.read(); | ||||
|     Err(if sr.ovr().bit_is_set() { | ||||
|         // Read from the DR to clear the OVR bit | ||||
|         let _ = spi.dr.read(); | ||||
|         nb::Error::Other(Error::Overrun) | ||||
|     } else if sr.modf().bit_is_set() { | ||||
|         // Write to CR1 to clear MODF | ||||
|         spi.cr1.modify(|_r, w| w); | ||||
|         nb::Error::Other(Error::ModeFault) | ||||
|     } else if sr.crcerr().bit_is_set() { | ||||
|         // Clear the CRCERR bit | ||||
|         spi.sr.modify(|_r, w| { | ||||
|             w.crcerr().clear_bit(); | ||||
|             w | ||||
|         }); | ||||
|         nb::Error::Other(Error::Crc) | ||||
|     } else if sr.txe().bit_is_set() { | ||||
|         // NOTE(write_volatile) see note above | ||||
|         unsafe { ptr::write_volatile(&spi.dr as *const _ as *mut u8, byte) } | ||||
|         return Ok(()); | ||||
|     } else { | ||||
|         nb::Error::WouldBlock | ||||
|     }) | ||||
| } | ||||
|  | ||||
| /// Interface to the Serial peripheral | ||||
| pub struct Spi< | ||||
|     SPI: PeriAddress<MemSize = u8> + WithInterrupt, | ||||
|     TSTREAM: Stream + WithInterrupt, | ||||
|     RSTREAM: Stream + WithInterrupt, | ||||
|     CHANNEL: Channel, | ||||
| > { | ||||
|     tx_stream: Option<TSTREAM>, | ||||
|     rx_stream: Option<RSTREAM>, | ||||
|     spi: Option<SPI>, | ||||
|     tx_int: TSTREAM::Interrupt, | ||||
|     rx_int: RSTREAM::Interrupt, | ||||
|     spi_int: SPI::Interrupt, | ||||
|     channel: PhantomData<CHANNEL>, | ||||
| } | ||||
|  | ||||
| impl<SPI, TSTREAM, RSTREAM, CHANNEL> Spi<SPI, TSTREAM, RSTREAM, CHANNEL> | ||||
| where | ||||
|     SPI: Instance | ||||
|         + PeriAddress<MemSize = u8> | ||||
|         + DMASet<TSTREAM, CHANNEL, MemoryToPeripheral> | ||||
|         + DMASet<RSTREAM, CHANNEL, PeripheralToMemory> | ||||
|         + WithInterrupt, | ||||
|     TSTREAM: Stream + WithInterrupt, | ||||
|     RSTREAM: Stream + WithInterrupt, | ||||
|     CHANNEL: Channel, | ||||
| { | ||||
|     // Leaking futures is forbidden! | ||||
|     pub unsafe fn new<PINS>( | ||||
|         spi: SPI, | ||||
|         streams: (TSTREAM, RSTREAM), | ||||
|         pins: PINS, | ||||
|         tx_int: TSTREAM::Interrupt, | ||||
|         rx_int: RSTREAM::Interrupt, | ||||
|         spi_int: SPI::Interrupt, | ||||
|         mode: Mode, | ||||
|         freq: Hertz, | ||||
|         clocks: Clocks, | ||||
|     ) -> Self | ||||
|     where | ||||
|         PINS: Pins<SPI>, | ||||
|     { | ||||
|         let (tx_stream, rx_stream) = streams; | ||||
|  | ||||
|         //        let spi1: crate::pac::SPI1 = unsafe { mem::transmute(()) }; | ||||
|         //        let mut hspi = crate::hal::spi::Spi::spi1( | ||||
|         //            spi1, | ||||
|         //            ( | ||||
|         //                crate::hal::spi::NoSck, | ||||
|         //                crate::hal::spi::NoMiso, | ||||
|         //                crate::hal::spi::NoMosi, | ||||
|         //            ), | ||||
|         //            mode, | ||||
|         //            freq, | ||||
|         //            clocks, | ||||
|         //        ); | ||||
|  | ||||
|         unsafe { SPI::enable_clock() }; | ||||
|  | ||||
|         let clock = SPI::clock_speed(clocks); | ||||
|  | ||||
|         // disable SS output | ||||
|         // spi.cr2 | ||||
|         //     .write(|w| w.ssoe().clear_bit().rxdmaen().set_bit().txdmaen().set_bit()); | ||||
|         spi.cr2.write(|w| w.ssoe().clear_bit()); | ||||
|  | ||||
|         let br = match clock.0 / freq.0 { | ||||
|             0 => unreachable!(), | ||||
|             1..=2 => 0b000, | ||||
|             3..=5 => 0b001, | ||||
|             6..=11 => 0b010, | ||||
|             12..=23 => 0b011, | ||||
|             24..=47 => 0b100, | ||||
|             48..=95 => 0b101, | ||||
|             96..=191 => 0b110, | ||||
|             _ => 0b111, | ||||
|         }; | ||||
|  | ||||
|         // mstr: master configuration | ||||
|         // lsbfirst: MSB first | ||||
|         // ssm: enable software slave management (NSS pin free for other uses) | ||||
|         // ssi: set nss high = master mode | ||||
|         // dff: 8 bit frames | ||||
|         // bidimode: 2-line unidirectional | ||||
|         // spe: enable the SPI bus | ||||
|         spi.cr1.write(|w| { | ||||
|             w.cpha() | ||||
|                 .bit(mode.phase == Phase::CaptureOnSecondTransition) | ||||
|                 .cpol() | ||||
|                 .bit(mode.polarity == Polarity::IdleHigh) | ||||
|                 .mstr() | ||||
|                 .set_bit() | ||||
|                 .br() | ||||
|                 .bits(br) | ||||
|                 .lsbfirst() | ||||
|                 .clear_bit() | ||||
|                 .ssm() | ||||
|                 .set_bit() | ||||
|                 .ssi() | ||||
|                 .set_bit() | ||||
|                 .rxonly() | ||||
|                 .clear_bit() | ||||
|                 .dff() | ||||
|                 .clear_bit() | ||||
|                 .bidimode() | ||||
|                 .clear_bit() | ||||
|                 .spe() | ||||
|                 .set_bit() | ||||
|         }); | ||||
|  | ||||
|         Self { | ||||
|             tx_stream: Some(tx_stream), | ||||
|             rx_stream: Some(rx_stream), | ||||
|             spi: Some(spi), | ||||
|             tx_int: tx_int, | ||||
|             rx_int: rx_int, | ||||
|             spi_int: spi_int, | ||||
|             channel: PhantomData, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<SPI, TSTREAM, RSTREAM, CHANNEL> FullDuplex<u8> for Spi<SPI, TSTREAM, RSTREAM, CHANNEL> | ||||
| where | ||||
|     SPI: Instance | ||||
|         + PeriAddress<MemSize = u8> | ||||
|         + DMASet<TSTREAM, CHANNEL, MemoryToPeripheral> | ||||
|         + DMASet<RSTREAM, CHANNEL, PeripheralToMemory> | ||||
|         + WithInterrupt | ||||
|         + 'static, | ||||
|     TSTREAM: Stream + WithInterrupt + 'static, | ||||
|     RSTREAM: Stream + WithInterrupt + 'static, | ||||
|     CHANNEL: Channel + 'static, | ||||
| { | ||||
|     type Error = Error; | ||||
|  | ||||
|     type WriteFuture<'a> = impl Future<Output = Result<(), Error>> + 'a; | ||||
|     type ReadFuture<'a> = impl Future<Output = Result<(), Error>> + 'a; | ||||
|     type WriteReadFuture<'a> = impl Future<Output = Result<(), Error>> + 'a; | ||||
|  | ||||
|     fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { | ||||
|         #[allow(mutable_transmutes)] | ||||
|         let static_buf: &'static mut [u8] = unsafe { mem::transmute(buf) }; | ||||
|  | ||||
|         async move { | ||||
|             let rx_stream = self.rx_stream.take().unwrap(); | ||||
|             let spi = self.spi.take().unwrap(); | ||||
|  | ||||
|             spi.cr2.modify(|_, w| w.errie().set_bit()); | ||||
|  | ||||
|             let mut rx_transfer = Transfer::init( | ||||
|                 rx_stream, | ||||
|                 spi, | ||||
|                 static_buf, | ||||
|                 None, | ||||
|                 DmaConfig::default() | ||||
|                     .transfer_complete_interrupt(true) | ||||
|                     .memory_increment(true) | ||||
|                     .double_buffer(false), | ||||
|             ); | ||||
|  | ||||
|             let fut = InterruptFuture::new(&mut self.rx_int); | ||||
|             let fut_err = InterruptFuture::new(&mut self.spi_int); | ||||
|  | ||||
|             rx_transfer.start(|_spi| {}); | ||||
|             future::select(fut, fut_err).await; | ||||
|  | ||||
|             let (rx_stream, spi, _buf, _) = rx_transfer.free(); | ||||
|  | ||||
|             spi.cr2.modify(|_, w| w.errie().clear_bit()); | ||||
|             self.rx_stream.replace(rx_stream); | ||||
|             self.spi.replace(spi); | ||||
|  | ||||
|             Ok(()) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { | ||||
|         #[allow(mutable_transmutes)] | ||||
|         let static_buf: &'static mut [u8] = unsafe { mem::transmute(buf) }; | ||||
|  | ||||
|         async move { | ||||
|             let tx_stream = self.tx_stream.take().unwrap(); | ||||
|             let spi = self.spi.take().unwrap(); | ||||
|  | ||||
|             spi.cr2 | ||||
|                 .modify(|_, w| w.errie().set_bit().txeie().set_bit().rxneie().set_bit()); | ||||
|  | ||||
|             //            let mut tx_transfer = Transfer::init( | ||||
|             //                tx_stream, | ||||
|             //                spi, | ||||
|             //                static_buf, | ||||
|             //                None, | ||||
|             //                DmaConfig::default() | ||||
|             //                    .transfer_complete_interrupt(true) | ||||
|             //                    .memory_increment(true) | ||||
|             //                    .double_buffer(false), | ||||
|             //            ); | ||||
|             // | ||||
|             //            let fut = InterruptFuture::new(&mut self.tx_int); | ||||
|             // | ||||
|             //            tx_transfer.start(|_spi| {}); | ||||
|             //            fut.await; | ||||
|  | ||||
|             // let (tx_stream, spi, _buf, _) = tx_transfer.free(); | ||||
|  | ||||
|             for i in 0..(static_buf.len() - 1) { | ||||
|                 let byte = static_buf[i]; | ||||
|                 loop { | ||||
|                     match write_sr(&spi, byte) { | ||||
|                         Ok(()) => break, | ||||
|                         _ => {} | ||||
|                     } | ||||
|                     InterruptFuture::new(&mut self.spi_int).await; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             spi.cr2.modify(|_, w| { | ||||
|                 w.errie() | ||||
|                     .clear_bit() | ||||
|                     .txeie() | ||||
|                     .clear_bit() | ||||
|                     .rxneie() | ||||
|                     .clear_bit() | ||||
|             }); | ||||
|             self.tx_stream.replace(tx_stream); | ||||
|             self.spi.replace(spi); | ||||
|  | ||||
|             Ok(()) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn read_write<'a>( | ||||
|         &'a mut self, | ||||
|         read_buf: &'a mut [u8], | ||||
|         write_buf: &'a [u8], | ||||
|     ) -> Self::WriteReadFuture<'a> { | ||||
|         #[allow(mutable_transmutes)] | ||||
|         let write_static_buf: &'static mut [u8] = unsafe { mem::transmute(write_buf) }; | ||||
|         let read_static_buf: &'static mut [u8] = unsafe { mem::transmute(read_buf) }; | ||||
|  | ||||
|         async move { | ||||
|             let tx_stream = self.tx_stream.take().unwrap(); | ||||
|             let rx_stream = self.rx_stream.take().unwrap(); | ||||
|             let spi_tx = self.spi.take().unwrap(); | ||||
|             let spi_rx: SPI = unsafe { mem::transmute_copy(&spi_tx) }; | ||||
|  | ||||
|             spi_rx | ||||
|                 .cr2 | ||||
|                 .modify(|_, w| w.errie().set_bit().txeie().set_bit().rxneie().set_bit()); | ||||
|  | ||||
|             //            let mut tx_transfer = Transfer::init( | ||||
|             //                tx_stream, | ||||
|             //                spi_tx, | ||||
|             //                write_static_buf, | ||||
|             //                None, | ||||
|             //                DmaConfig::default() | ||||
|             //                    .transfer_complete_interrupt(true) | ||||
|             //                    .memory_increment(true) | ||||
|             //                    .double_buffer(false), | ||||
|             //            ); | ||||
|             // | ||||
|             //            let mut rx_transfer = Transfer::init( | ||||
|             //                rx_stream, | ||||
|             //                spi_rx, | ||||
|             //                read_static_buf, | ||||
|             //                None, | ||||
|             //                DmaConfig::default() | ||||
|             //                    .transfer_complete_interrupt(true) | ||||
|             //                    .memory_increment(true) | ||||
|             //                    .double_buffer(false), | ||||
|             //            ); | ||||
|             // | ||||
|             //            let tx_fut = InterruptFuture::new(&mut self.tx_int); | ||||
|             //            let rx_fut = InterruptFuture::new(&mut self.rx_int); | ||||
|             //            let rx_fut_err = InterruptFuture::new(&mut self.spi_int); | ||||
|             // | ||||
|             //            rx_transfer.start(|_spi| {}); | ||||
|             //            tx_transfer.start(|_spi| {}); | ||||
|             // | ||||
|             //            time::Timer::after(time::Duration::from_millis(500)).await; | ||||
|             // | ||||
|             //            // tx_fut.await; | ||||
|             //            // future::select(rx_fut, rx_fut_err).await; | ||||
|             // | ||||
|             //            let (rx_stream, spi_rx, _buf, _) = rx_transfer.free(); | ||||
|             //            let (tx_stream, _, _buf, _) = tx_transfer.free(); | ||||
|  | ||||
|             for i in 0..(read_static_buf.len() - 1) { | ||||
|                 let byte = write_static_buf[i]; | ||||
|                 loop { | ||||
|                     let fut = InterruptFuture::new(&mut self.spi_int); | ||||
|                     match write_sr(&spi_tx, byte) { | ||||
|                         Ok(()) => break, | ||||
|                         _ => {} | ||||
|                     } | ||||
|                     fut.await; | ||||
|                 } | ||||
|  | ||||
|                 loop { | ||||
|                     let fut = InterruptFuture::new(&mut self.spi_int); | ||||
|                     match read_sr(&spi_tx) { | ||||
|                         Ok(byte) => { | ||||
|                             read_static_buf[i] = byte; | ||||
|                             break; | ||||
|                         } | ||||
|                         _ => {} | ||||
|                     } | ||||
|                     fut.await; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             spi_rx.cr2.modify(|_, w| { | ||||
|                 w.errie() | ||||
|                     .clear_bit() | ||||
|                     .txeie() | ||||
|                     .clear_bit() | ||||
|                     .rxneie() | ||||
|                     .clear_bit() | ||||
|             }); | ||||
|             self.rx_stream.replace(rx_stream); | ||||
|             self.tx_stream.replace(tx_stream); | ||||
|             self.spi.replace(spi_rx); | ||||
|  | ||||
|             Ok(()) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| mod private { | ||||
|     pub trait Sealed {} | ||||
| } | ||||
|  | ||||
| pub trait WithInterrupt: private::Sealed { | ||||
|     type Interrupt: Interrupt; | ||||
| } | ||||
|  | ||||
| pub trait Instance: Deref<Target = pac::spi1::RegisterBlock> + private::Sealed { | ||||
|     unsafe fn enable_clock(); | ||||
|     fn clock_speed(clocks: Clocks) -> Hertz; | ||||
| } | ||||
|  | ||||
| macro_rules! dma { | ||||
|      ($($PER:ident => ($dma:ident, $stream:ident),)+) => { | ||||
|          $( | ||||
|              impl private::Sealed for dma::$stream<pac::$dma> {} | ||||
|              impl WithInterrupt for dma::$stream<pac::$dma> { | ||||
|                  type Interrupt = interrupt::$PER; | ||||
|              } | ||||
|          )+ | ||||
|      } | ||||
|  } | ||||
|  | ||||
| macro_rules! spi { | ||||
|     ($($PER:ident => ($SPI:ident, $pclkX:ident,  $apbXenr:ident, $en:expr),)+) => { | ||||
|         $( | ||||
|             impl private::Sealed for pac::$SPI {} | ||||
|             impl Instance for pac::$SPI { | ||||
|                 unsafe fn enable_clock() { | ||||
|                     const EN_BIT: u8 = $en; | ||||
|                     // NOTE(unsafe) self reference will only be used for atomic writes with no side effects. | ||||
|                     let rcc = &(*pac::RCC::ptr()); | ||||
|                     // Enable clock. | ||||
|                     bb::set(&rcc.$apbXenr, EN_BIT); | ||||
|                     // Stall the pipeline to work around erratum 2.1.13 (DM00037591) | ||||
|                     cortex_m::asm::dsb(); | ||||
|                 } | ||||
|  | ||||
|                 fn clock_speed(clocks: Clocks) -> Hertz { | ||||
|                     clocks.$pclkX() | ||||
|                 } | ||||
|             } | ||||
|             impl WithInterrupt for pac::$SPI { | ||||
|                 type Interrupt = interrupt::$PER; | ||||
|             } | ||||
|         )+ | ||||
|     } | ||||
| } | ||||
|  | ||||
| dma! { | ||||
|     DMA2_STREAM0 => (DMA2, Stream0), | ||||
|     DMA2_STREAM1 => (DMA2, Stream1), | ||||
|     DMA2_STREAM2 => (DMA2, Stream2), | ||||
|     DMA2_STREAM3 => (DMA2, Stream3), | ||||
|     DMA2_STREAM4 => (DMA2, Stream4), | ||||
|     DMA2_STREAM5 => (DMA2, Stream5), | ||||
|     DMA2_STREAM6 => (DMA2, Stream6), | ||||
|     DMA2_STREAM7 => (DMA2, Stream7), | ||||
|     DMA1_STREAM0 => (DMA1, Stream0), | ||||
|     DMA1_STREAM1 => (DMA1, Stream1), | ||||
|     DMA1_STREAM2 => (DMA1, Stream2), | ||||
|     DMA1_STREAM3 => (DMA1, Stream3), | ||||
|     DMA1_STREAM4 => (DMA1, Stream4), | ||||
|     DMA1_STREAM5 => (DMA1, Stream5), | ||||
|     DMA1_STREAM6 => (DMA1, Stream6), | ||||
| } | ||||
|  | ||||
| #[cfg(any( | ||||
|     feature = "stm32f401", | ||||
|     feature = "stm32f410", | ||||
|     feature = "stm32f411", | ||||
|     feature = "stm32f446", | ||||
| ))] | ||||
| spi! { | ||||
|     SPI1 => (SPI1, pclk2, apb2enr, 12), | ||||
|     SPI2 => (SPI2, pclk1, apb2enr, 14), | ||||
| //    SPI6 => (SPI6, pclk2, apb2enr, 21), | ||||
|     SPI4 => (SPI3, pclk2, apb2enr, 13), | ||||
| //    SPI5 => (SPI3, pclk2, apb2enr, 20), | ||||
| } | ||||
|  | ||||
| #[cfg(any(feature = "stm32f405", feature = "stm32f407"))] | ||||
| spi! { | ||||
|     SPI1 => (SPI1, pclk2, apb2enr, 12), | ||||
|     SPI3 => (SPI3, pclk1, apb2enr, 15), | ||||
| } | ||||
| @@ -1,61 +0,0 @@ | ||||
| use crate::{hal::prelude::*, pac, Peripherals}; | ||||
|  | ||||
| #[derive(Default)] | ||||
| pub struct Config { | ||||
|     pub use_hse: Option<u32>, | ||||
|     pub sysclk: Option<u32>, | ||||
|     pub pclk1: Option<u32>, | ||||
|     pub require_pll48clk: bool, | ||||
| } | ||||
|  | ||||
| impl Config { | ||||
|     pub fn new() -> Self { | ||||
|         Default::default() | ||||
|     } | ||||
|  | ||||
|     pub fn use_hse(mut self, freq: u32) -> Self { | ||||
|         self.use_hse = Some(freq); | ||||
|         self | ||||
|     } | ||||
|  | ||||
|     pub fn sysclk(mut self, freq: u32) -> Self { | ||||
|         self.sysclk = Some(freq); | ||||
|         self | ||||
|     } | ||||
|  | ||||
|     pub fn pclk1(mut self, freq: u32) -> Self { | ||||
|         self.pclk1 = Some(freq); | ||||
|         self | ||||
|     } | ||||
|  | ||||
|     pub fn require_pll48clk(mut self) -> Self { | ||||
|         self.require_pll48clk = true; | ||||
|         self | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// safety: must only call once. | ||||
| pub unsafe fn configure(config: Config) { | ||||
|     let dp = pac::Peripherals::take().unwrap(); | ||||
|     let mut cfgr = dp.RCC.constrain().cfgr; | ||||
|  | ||||
|     if let Some(hz) = config.use_hse { | ||||
|         cfgr = cfgr.use_hse(hz.mhz()); | ||||
|     }; | ||||
|  | ||||
|     if let Some(hz) = config.sysclk { | ||||
|         cfgr = cfgr.sysclk(hz.mhz()); | ||||
|     }; | ||||
|  | ||||
|     if let Some(hz) = config.pclk1 { | ||||
|         cfgr = cfgr.pclk1(hz.mhz()); | ||||
|     }; | ||||
|  | ||||
|     if config.require_pll48clk { | ||||
|         cfgr = cfgr.require_pll48clk(); | ||||
|     }; | ||||
|  | ||||
|     let clocks = cfgr.freeze(); | ||||
|  | ||||
|     unsafe { Peripherals::set_peripherals(clocks) }; | ||||
| } | ||||
| @@ -1,114 +0,0 @@ | ||||
| #![macro_use] | ||||
| #![allow(clippy::module_inception)] | ||||
| #![allow(unused)] | ||||
|  | ||||
| #[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_rules! trace { | ||||
|         ($($msg:expr),+ $(,)?) => { | ||||
|             () | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     macro_rules! debug { | ||||
|         ($($msg:expr),+ $(,)?) => { | ||||
|             () | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     macro_rules! info { | ||||
|         ($($msg:expr),+ $(,)?) => { | ||||
|             () | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     macro_rules! warn { | ||||
|         ($($msg:expr),+ $(,)?) => { | ||||
|             () | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     macro_rules! error { | ||||
|         ($($msg:expr),+ $(,)?) => { | ||||
|             () | ||||
|         }; | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(not(feature = "defmt"))] | ||||
| 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 | ||||
|     } | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,2 +0,0 @@ | ||||
| pub mod rtc; | ||||
| pub mod system; | ||||
| @@ -1,372 +0,0 @@ | ||||
| use crate::hal::rcc::Clocks; | ||||
| use atomic_polyfill::{compiler_fence, AtomicU32, Ordering}; | ||||
| use core::cell::Cell; | ||||
| use core::convert::TryInto; | ||||
| use critical_section::CriticalSection; | ||||
| use embassy::interrupt::InterruptExt; | ||||
| use embassy::time::{Clock, TICKS_PER_SECOND}; | ||||
| use embassy::util::CriticalSectionMutex as Mutex; | ||||
|  | ||||
| use crate::interrupt; | ||||
| use crate::interrupt::Interrupt; | ||||
|  | ||||
| // RTC timekeeping works with something we call "periods", which are time intervals | ||||
| // of 2^15 ticks. The RTC counter value is 16 bits, so one "overflow cycle" is 2 periods. | ||||
| // | ||||
| // A `period` count is maintained in parallel to the RTC hardware `counter`, like this: | ||||
| // - `period` and `counter` start at 0 | ||||
| // - `period` is incremented on overflow (at counter value 0) | ||||
| // - `period` is incremented "midway" between overflows (at counter value 0x8000) | ||||
| // | ||||
| // Therefore, when `period` is even, counter is in 0..0x7FFF. When odd, counter is in 0x8000..0xFFFF | ||||
| // This allows for now() to return the correct value even if it races an overflow. | ||||
| // | ||||
| // To get `now()`, `period` is read first, then `counter` is read. If the counter value matches | ||||
| // the expected range for the `period` parity, we're done. If it doesn't, this means that | ||||
| // a new period start has raced us between reading `period` and `counter`, so we assume the `counter` value | ||||
| // corresponds to the next period. | ||||
| // | ||||
| // `period` is a 32bit integer, so It overflows on 2^32 * 2^15 / 32768 seconds of uptime, which is 136 years. | ||||
| fn calc_now(period: u32, counter: u16) -> u64 { | ||||
|     ((period as u64) << 15) + ((counter as u32 ^ ((period & 1) << 15)) as u64) | ||||
| } | ||||
|  | ||||
| struct AlarmState { | ||||
|     timestamp: Cell<u64>, | ||||
|     callback: Cell<Option<(fn(*mut ()), *mut ())>>, | ||||
| } | ||||
|  | ||||
| impl AlarmState { | ||||
|     fn new() -> Self { | ||||
|         Self { | ||||
|             timestamp: Cell::new(u64::MAX), | ||||
|             callback: Cell::new(None), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| // TODO: This is sometimes wasteful, try to find a better way | ||||
| const ALARM_COUNT: usize = 3; | ||||
|  | ||||
| /// RTC timer that can be used by the executor and to set alarms. | ||||
| /// | ||||
| /// It can work with Timers 2 and 3. | ||||
|  | ||||
| /// This timer works internally with a unit of 2^15 ticks, which means that if a call to | ||||
| /// [`embassy::time::Clock::now`] is blocked for that amount of ticks the returned value will be | ||||
| /// wrong (an old value). The current default tick rate is 32768 ticks per second. | ||||
| pub struct RTC<T: Instance> { | ||||
|     rtc: T, | ||||
|     irq: T::Interrupt, | ||||
|  | ||||
|     /// Number of 2^23 periods elapsed since boot. | ||||
|     period: AtomicU32, | ||||
|  | ||||
|     /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled. | ||||
|     alarms: Mutex<[AlarmState; ALARM_COUNT]>, | ||||
|  | ||||
|     clocks: Clocks, | ||||
| } | ||||
|  | ||||
| impl<T: Instance> RTC<T> { | ||||
|     pub fn new(rtc: T, irq: T::Interrupt, clocks: Clocks) -> Self { | ||||
|         Self { | ||||
|             rtc, | ||||
|             irq, | ||||
|             period: AtomicU32::new(0), | ||||
|             alarms: Mutex::new([AlarmState::new(), AlarmState::new(), AlarmState::new()]), | ||||
|             clocks, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn start(&'static self) { | ||||
|         self.rtc.enable_clock(); | ||||
|         self.rtc.stop_and_reset(); | ||||
|  | ||||
|         let freq = T::pclk(&self.clocks); | ||||
|         let psc = freq / TICKS_PER_SECOND as u32 - 1; | ||||
|         let psc: u16 = psc.try_into().unwrap(); | ||||
|  | ||||
|         self.rtc.set_psc_arr(psc, u16::MAX); | ||||
|         // Mid-way point | ||||
|         self.rtc.set_compare(0, 0x8000); | ||||
|         self.rtc.set_compare_interrupt(0, true); | ||||
|  | ||||
|         self.irq.set_handler(|ptr| unsafe { | ||||
|             let this = &*(ptr as *const () as *const Self); | ||||
|             this.on_interrupt(); | ||||
|         }); | ||||
|         self.irq.set_handler_context(self as *const _ as *mut _); | ||||
|         self.irq.unpend(); | ||||
|         self.irq.enable(); | ||||
|  | ||||
|         self.rtc.start(); | ||||
|     } | ||||
|  | ||||
|     fn on_interrupt(&self) { | ||||
|         if self.rtc.overflow_interrupt_status() { | ||||
|             self.rtc.overflow_clear_flag(); | ||||
|             self.next_period(); | ||||
|         } | ||||
|  | ||||
|         // Half overflow | ||||
|         if self.rtc.compare_interrupt_status(0) { | ||||
|             self.rtc.compare_clear_flag(0); | ||||
|             self.next_period(); | ||||
|         } | ||||
|  | ||||
|         for n in 1..=ALARM_COUNT { | ||||
|             if self.rtc.compare_interrupt_status(n) { | ||||
|                 self.rtc.compare_clear_flag(n); | ||||
|                 critical_section::with(|cs| self.trigger_alarm(n, cs)); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn next_period(&self) { | ||||
|         critical_section::with(|cs| { | ||||
|             let period = self.period.fetch_add(1, Ordering::Relaxed) + 1; | ||||
|             let t = (period as u64) << 15; | ||||
|  | ||||
|             for n in 1..=ALARM_COUNT { | ||||
|                 let alarm = &self.alarms.borrow(cs)[n - 1]; | ||||
|                 let at = alarm.timestamp.get(); | ||||
|  | ||||
|                 let diff = at - t; | ||||
|                 if diff < 0xc000 { | ||||
|                     self.rtc.set_compare(n, at as u16); | ||||
|                     self.rtc.set_compare_interrupt(n, true); | ||||
|                 } | ||||
|             } | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     fn trigger_alarm(&self, n: usize, cs: CriticalSection) { | ||||
|         self.rtc.set_compare_interrupt(n, false); | ||||
|  | ||||
|         let alarm = &self.alarms.borrow(cs)[n - 1]; | ||||
|         alarm.timestamp.set(u64::MAX); | ||||
|  | ||||
|         // Call after clearing alarm, so the callback can set another alarm. | ||||
|         if let Some((f, ctx)) = alarm.callback.get() { | ||||
|             f(ctx); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn set_alarm_callback(&self, n: usize, callback: fn(*mut ()), ctx: *mut ()) { | ||||
|         critical_section::with(|cs| { | ||||
|             let alarm = &self.alarms.borrow(cs)[n - 1]; | ||||
|             alarm.callback.set(Some((callback, ctx))); | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     fn set_alarm(&self, n: usize, timestamp: u64) { | ||||
|         critical_section::with(|cs| { | ||||
|             let alarm = &self.alarms.borrow(cs)[n - 1]; | ||||
|             alarm.timestamp.set(timestamp); | ||||
|  | ||||
|             let t = self.now(); | ||||
|             if timestamp <= t { | ||||
|                 self.trigger_alarm(n, cs); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             let diff = timestamp - t; | ||||
|             if diff < 0xc000 { | ||||
|                 let safe_timestamp = timestamp.max(t + 3); | ||||
|                 self.rtc.set_compare(n, safe_timestamp as u16); | ||||
|                 self.rtc.set_compare_interrupt(n, true); | ||||
|             } else { | ||||
|                 self.rtc.set_compare_interrupt(n, false); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     pub fn alarm1(&'static self) -> Alarm<T> { | ||||
|         Alarm { n: 1, rtc: self } | ||||
|     } | ||||
|     pub fn alarm2(&'static self) -> Option<Alarm<T>> { | ||||
|         if T::REAL_ALARM_COUNT >= 2 { | ||||
|             Some(Alarm { n: 2, rtc: self }) | ||||
|         } else { | ||||
|             None | ||||
|         } | ||||
|     } | ||||
|     pub fn alarm3(&'static self) -> Option<Alarm<T>> { | ||||
|         if T::REAL_ALARM_COUNT >= 3 { | ||||
|             Some(Alarm { n: 3, rtc: self }) | ||||
|         } else { | ||||
|             None | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: Instance> embassy::time::Clock for RTC<T> { | ||||
|     fn now(&self) -> u64 { | ||||
|         let period = self.period.load(Ordering::Relaxed); | ||||
|         compiler_fence(Ordering::Acquire); | ||||
|         let counter = self.rtc.counter(); | ||||
|         calc_now(period, counter) | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub struct Alarm<T: Instance> { | ||||
|     n: usize, | ||||
|     rtc: &'static RTC<T>, | ||||
| } | ||||
|  | ||||
| impl<T: Instance> embassy::time::Alarm for Alarm<T> { | ||||
|     fn set_callback(&self, callback: fn(*mut ()), ctx: *mut ()) { | ||||
|         self.rtc.set_alarm_callback(self.n, callback, ctx); | ||||
|     } | ||||
|  | ||||
|     fn set(&self, timestamp: u64) { | ||||
|         self.rtc.set_alarm(self.n, timestamp); | ||||
|     } | ||||
|  | ||||
|     fn clear(&self) { | ||||
|         self.rtc.set_alarm(self.n, u64::MAX); | ||||
|     } | ||||
| } | ||||
|  | ||||
| mod sealed { | ||||
|     pub trait Sealed {} | ||||
| } | ||||
|  | ||||
| pub trait Instance: sealed::Sealed + Sized + 'static { | ||||
|     type Interrupt: Interrupt; | ||||
|     const REAL_ALARM_COUNT: usize; | ||||
|  | ||||
|     fn enable_clock(&self); | ||||
|     fn set_compare(&self, n: usize, value: u16); | ||||
|     fn set_compare_interrupt(&self, n: usize, enable: bool); | ||||
|     fn compare_interrupt_status(&self, n: usize) -> bool; | ||||
|     fn compare_clear_flag(&self, n: usize); | ||||
|     fn overflow_interrupt_status(&self) -> bool; | ||||
|     fn overflow_clear_flag(&self); | ||||
|     // This method should ensure that the values are really updated before returning | ||||
|     fn set_psc_arr(&self, psc: u16, arr: u16); | ||||
|     fn stop_and_reset(&self); | ||||
|     fn start(&self); | ||||
|     fn counter(&self) -> u16; | ||||
|     fn pclk(clocks: &Clocks) -> u32; | ||||
| } | ||||
|  | ||||
| #[allow(unused_macros)] | ||||
| macro_rules! impl_timer { | ||||
|     ($module:ident: ($TYPE:ident, $INT:ident,  $timXen:ident, $timXrst:ident, $apbenr:ident, $apbrstr:ident, $pclk: ident)) => { | ||||
|         mod $module { | ||||
|             use super::*; | ||||
|             use crate::hal::pac::{$TYPE, RCC}; | ||||
|  | ||||
|             impl sealed::Sealed for $TYPE {} | ||||
|  | ||||
|             impl Instance for $TYPE { | ||||
|                 type Interrupt = interrupt::$INT; | ||||
|                 const REAL_ALARM_COUNT: usize = 3; | ||||
|  | ||||
|                 fn enable_clock(&self) { | ||||
|                     // NOTE(unsafe) It will only be used for atomic operations | ||||
|                     unsafe { | ||||
|                         let rcc = &*RCC::ptr(); | ||||
|  | ||||
|                         rcc.$apbenr.modify(|_, w| w.$timXen().set_bit()); | ||||
|                         rcc.$apbrstr.modify(|_, w| w.$timXrst().set_bit()); | ||||
|                         rcc.$apbrstr.modify(|_, w| w.$timXrst().clear_bit()); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 fn set_compare(&self, n: usize, value: u16) { | ||||
|                     // NOTE(unsafe) these registers accept all the range of u16 values | ||||
|                     match n { | ||||
|                         0 => self.ccr1.write(|w| unsafe { w.bits(value.into()) }), | ||||
|                         1 => self.ccr2.write(|w| unsafe { w.bits(value.into()) }), | ||||
|                         2 => self.ccr3.write(|w| unsafe { w.bits(value.into()) }), | ||||
|                         3 => self.ccr4.write(|w| unsafe { w.bits(value.into()) }), | ||||
|                         _ => {} | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 fn set_compare_interrupt(&self, n: usize, enable: bool) { | ||||
|                     if n > 3 { | ||||
|                         return; | ||||
|                     } | ||||
|                     let bit = n as u8 + 1; | ||||
|                     unsafe { | ||||
|                         if enable { | ||||
|                             self.dier.modify(|r, w| w.bits(r.bits() | (1 << bit))); | ||||
|                         } else { | ||||
|                             self.dier.modify(|r, w| w.bits(r.bits() & !(1 << bit))); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 fn compare_interrupt_status(&self, n: usize) -> bool { | ||||
|                     let status = self.sr.read(); | ||||
|                     match n { | ||||
|                         0 => status.cc1if().bit_is_set(), | ||||
|                         1 => status.cc2if().bit_is_set(), | ||||
|                         2 => status.cc3if().bit_is_set(), | ||||
|                         3 => status.cc4if().bit_is_set(), | ||||
|                         _ => false, | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 fn compare_clear_flag(&self, n: usize) { | ||||
|                     if n > 3 { | ||||
|                         return; | ||||
|                     } | ||||
|                     let bit = n as u8 + 1; | ||||
|                     unsafe { | ||||
|                         self.sr.modify(|r, w| w.bits(r.bits() & !(1 << bit))); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 fn overflow_interrupt_status(&self) -> bool { | ||||
|                     self.sr.read().uif().bit_is_set() | ||||
|                 } | ||||
|  | ||||
|                 fn overflow_clear_flag(&self) { | ||||
|                     unsafe { | ||||
|                         self.sr.modify(|_, w| w.uif().clear_bit()); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 fn set_psc_arr(&self, psc: u16, arr: u16) { | ||||
|                     // NOTE(unsafe) All u16 values are valid | ||||
|                     self.psc.write(|w| unsafe { w.bits(psc.into()) }); | ||||
|                     self.arr.write(|w| unsafe { w.bits(arr.into()) }); | ||||
|  | ||||
|                     unsafe { | ||||
|                         // Set URS, generate update, clear URS | ||||
|                         self.cr1.modify(|_, w| w.urs().set_bit()); | ||||
|                         self.egr.write(|w| w.ug().set_bit()); | ||||
|                         self.cr1.modify(|_, w| w.urs().clear_bit()); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 fn stop_and_reset(&self) { | ||||
|                     unsafe { | ||||
|                         self.cr1.modify(|_, w| w.cen().clear_bit()); | ||||
|                     } | ||||
|                     self.cnt.reset(); | ||||
|                 } | ||||
|  | ||||
|                 fn start(&self) { | ||||
|                     self.cr1.modify(|_, w| w.cen().set_bit()); | ||||
|                 } | ||||
|  | ||||
|                 fn counter(&self) -> u16 { | ||||
|                     self.cnt.read().bits() as u16 | ||||
|                 } | ||||
|  | ||||
|                 fn pclk(clocks: &Clocks) -> u32 { | ||||
|                     clocks.$pclk().0 | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
| } | ||||
|  | ||||
| impl_timer!(tim2: (TIM2, TIM2, tim2en, tim2rst, apb1enr, apb1rstr, apb1_tim_clk)); | ||||
| impl_timer!(tim3: (TIM3, TIM3, tim3en, tim3rst, apb1enr, apb1rstr, apb1_tim_clk)); | ||||
| @@ -1,17 +0,0 @@ | ||||
| use crate::{hal, pac, Peripherals}; | ||||
|  | ||||
| pub use hal::{ | ||||
|     prelude::*, | ||||
|     rcc::{Clocks, Config}, | ||||
| }; | ||||
|  | ||||
| /// safety: must only call once. | ||||
| pub unsafe fn configure(config: Config) { | ||||
|     let dp = pac::Peripherals::take().unwrap(); | ||||
|  | ||||
|     let rcc = dp.RCC.freeze(config); | ||||
|  | ||||
|     let clocks = rcc.clocks; | ||||
|  | ||||
|     unsafe { Peripherals::set_peripherals(clocks) }; | ||||
| } | ||||
| @@ -1,478 +0,0 @@ | ||||
| #![no_std] | ||||
| #![feature(generic_associated_types)] | ||||
| #![feature(asm)] | ||||
| #![feature(min_type_alias_impl_trait)] | ||||
| #![feature(impl_trait_in_bindings)] | ||||
| #![feature(type_alias_impl_trait)] | ||||
| #![allow(incomplete_features)] | ||||
|  | ||||
| #[cfg(any( | ||||
|     feature = "stm32f401", | ||||
|     feature = "stm32f405", | ||||
|     feature = "stm32f407", | ||||
|     feature = "stm32f410", | ||||
|     feature = "stm32f411", | ||||
|     feature = "stm32f412", | ||||
|     feature = "stm32f413", | ||||
|     feature = "stm32f415", | ||||
|     feature = "stm32f417", | ||||
|     feature = "stm32f423", | ||||
|     feature = "stm32f427", | ||||
|     feature = "stm32f429", | ||||
|     feature = "stm32f437", | ||||
|     feature = "stm32f439", | ||||
|     feature = "stm32f446", | ||||
|     feature = "stm32f469", | ||||
|     feature = "stm32f479", | ||||
| ))] | ||||
| mod f4; | ||||
|  | ||||
| #[cfg(any( | ||||
|     feature = "stm32f401", | ||||
|     feature = "stm32f405", | ||||
|     feature = "stm32f407", | ||||
|     feature = "stm32f412", | ||||
|     feature = "stm32f413", | ||||
|     feature = "stm32f415", | ||||
|     feature = "stm32f417", | ||||
|     feature = "stm32f423", | ||||
|     feature = "stm32f427", | ||||
|     feature = "stm32f429", | ||||
|     feature = "stm32f437", | ||||
|     feature = "stm32f439", | ||||
|     feature = "stm32f446", | ||||
|     feature = "stm32f469", | ||||
|     feature = "stm32f479", | ||||
| ))] | ||||
| pub use {stm32f4xx_hal as hal, stm32f4xx_hal::stm32 as pac}; | ||||
|  | ||||
| #[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))] | ||||
| pub use {stm32l0xx_hal as hal, stm32l0xx_hal::pac}; | ||||
|  | ||||
| #[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))] | ||||
| mod l0; | ||||
|  | ||||
| #[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))] | ||||
| pub use l0::{rtc, system}; | ||||
|  | ||||
| pub mod fmt; | ||||
|  | ||||
| pub mod exti; | ||||
| pub mod interrupt; | ||||
|  | ||||
| #[cfg(any( | ||||
|     feature = "stm32f405", | ||||
|     feature = "stm32f407", | ||||
|     feature = "stm32f412", | ||||
|     feature = "stm32f413", | ||||
|     feature = "stm32f415", | ||||
|     feature = "stm32f417", | ||||
|     feature = "stm32f423", | ||||
|     feature = "stm32f427", | ||||
|     feature = "stm32f429", | ||||
|     feature = "stm32f437", | ||||
|     feature = "stm32f439", | ||||
|     feature = "stm32f446", | ||||
|     feature = "stm32f469", | ||||
|     feature = "stm32f479", | ||||
| ))] | ||||
| pub mod can; | ||||
|  | ||||
| #[cfg(any( | ||||
|     feature = "stm32f401", | ||||
|     feature = "stm32f405", | ||||
|     feature = "stm32f407", | ||||
|     feature = "stm32f412", | ||||
|     feature = "stm32f413", | ||||
|     feature = "stm32f415", | ||||
|     feature = "stm32f417", | ||||
|     feature = "stm32f423", | ||||
|     feature = "stm32f427", | ||||
|     feature = "stm32f429", | ||||
|     feature = "stm32f437", | ||||
|     feature = "stm32f439", | ||||
|     feature = "stm32f446", | ||||
|     feature = "stm32f469", | ||||
|     feature = "stm32f479", | ||||
| ))] | ||||
| pub use f4::{rtc, serial, spi, system}; | ||||
|  | ||||
| #[cfg(any( | ||||
|     feature = "stm32f401", | ||||
|     feature = "stm32f405", | ||||
|     feature = "stm32f407", | ||||
|     feature = "stm32f410", | ||||
|     feature = "stm32f411", | ||||
|     feature = "stm32f412", | ||||
|     feature = "stm32f413", | ||||
|     feature = "stm32f415", | ||||
|     feature = "stm32f417", | ||||
|     feature = "stm32f423", | ||||
|     feature = "stm32f427", | ||||
|     feature = "stm32f429", | ||||
|     feature = "stm32f437", | ||||
|     feature = "stm32f439", | ||||
|     feature = "stm32f446", | ||||
|     feature = "stm32f469", | ||||
|     feature = "stm32f479", | ||||
| ))] | ||||
| unsafe impl embassy_extras::usb::USBInterrupt for interrupt::OTG_FS {} | ||||
|  | ||||
| use core::option::Option; | ||||
| use hal::prelude::*; | ||||
| use hal::rcc::Clocks; | ||||
|  | ||||
| #[cfg(feature = "stm32f401")] | ||||
| embassy_extras::std_peripherals! { | ||||
|     ADC_COMMON, | ||||
|     ADC1, | ||||
|     CRC, | ||||
|     DBGMCU, | ||||
|     EXTI, | ||||
|     FLASH, | ||||
|     IWDG, | ||||
|     OTG_FS_DEVICE, | ||||
|     OTG_FS_GLOBAL, | ||||
|     OTG_FS_HOST, | ||||
|     OTG_FS_PWRCLK, | ||||
|     PWR, | ||||
|     //RCC, | ||||
|     RTC, | ||||
|     SDIO, | ||||
|     SYSCFG, | ||||
|     TIM1, | ||||
|     TIM8, | ||||
|     TIM10, | ||||
|     TIM11, | ||||
|     TIM2, | ||||
|     //TIM3, | ||||
|     TIM4, | ||||
|     TIM5, | ||||
|     TIM9, | ||||
|     USART1, | ||||
|     USART2, | ||||
|     USART6, | ||||
|     WWDG, | ||||
|     DMA2, | ||||
|     DMA1, | ||||
|     GPIOH, | ||||
|     GPIOE, | ||||
|     GPIOD, | ||||
|     GPIOC, | ||||
|     GPIOB, | ||||
|     GPIOA, | ||||
|     I2C3, | ||||
|     I2C2, | ||||
|     I2C1, | ||||
|     I2S2EXT, | ||||
|     I2S3EXT, | ||||
|     SPI1, | ||||
|     SPI2, | ||||
|     SPI3, | ||||
|     SPI4, | ||||
|     FPU, | ||||
|     STK, | ||||
|     NVIC_STIR, | ||||
|     FPU_CPACR, | ||||
|     SCB_ACTRL, | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "stm32f446")] | ||||
| embassy_extras::std_peripherals! { | ||||
|     DCMI, | ||||
|     FMC, | ||||
|     DBGMCU, | ||||
|     DMA2, | ||||
|     DMA1, | ||||
| //    RCC, | ||||
|     GPIOH, | ||||
|     GPIOG, | ||||
|     GPIOF, | ||||
|     GPIOE, | ||||
|     GPIOD, | ||||
|     GPIOC, | ||||
|     GPIOB, | ||||
|     GPIOA, | ||||
|     SYSCFG, | ||||
|     SPI1, | ||||
|     SPI2, | ||||
|     SPI3, | ||||
|     SPI4, | ||||
|     ADC1, | ||||
|     ADC2, | ||||
|     ADC3, | ||||
|     USART6, | ||||
|     USART1, | ||||
|     USART2, | ||||
|     USART3, | ||||
|     DAC, | ||||
|     I2C3, | ||||
|     I2C2, | ||||
|     I2C1, | ||||
|     IWDG, | ||||
|     WWDG, | ||||
|     RTC, | ||||
|     UART4, | ||||
|     UART5, | ||||
|     ADC_COMMON, | ||||
|     TIM1, | ||||
|     TIM2, | ||||
|     TIM8, | ||||
| //    TIM3, | ||||
|     TIM4, | ||||
|     TIM5, | ||||
|     TIM9, | ||||
|     TIM12, | ||||
|     TIM10, | ||||
|     TIM13, | ||||
|     TIM14, | ||||
|     TIM11, | ||||
|     TIM6, | ||||
|     TIM7, | ||||
|     CRC, | ||||
|     OTG_FS_GLOBAL, | ||||
|     OTG_FS_HOST, | ||||
|     OTG_FS_DEVICE, | ||||
|     OTG_FS_PWRCLK, | ||||
|     CAN1, | ||||
|     CAN2, | ||||
|     FLASH, | ||||
|     EXTI, | ||||
|     OTG_HS_GLOBAL, | ||||
|     OTG_HS_HOST, | ||||
|     OTG_HS_DEVICE, | ||||
|     OTG_HS_PWRCLK, | ||||
|     SAI1, | ||||
|     SAI2, | ||||
|     PWR, | ||||
|     QUADSPI, | ||||
|     SPDIFRX, | ||||
| //    SDMMC, | ||||
|     HDMI_CEC, | ||||
|     FPU, | ||||
|     STK, | ||||
|     NVIC_STIR, | ||||
|     FPU_CPACR, | ||||
|     SCB_ACTRL, | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "stm32f405")] | ||||
| embassy_extras::std_peripherals! { | ||||
|     RNG, | ||||
|     DCMI, | ||||
|     FSMC, | ||||
|     DBGMCU, | ||||
|     DMA2, | ||||
|     DMA1, | ||||
| //    RCC, | ||||
|     GPIOI, | ||||
|     GPIOH, | ||||
|     GPIOG, | ||||
|     GPIOF, | ||||
|     GPIOE, | ||||
|     GPIOD, | ||||
|     GPIOC, | ||||
|     GPIOJ, | ||||
|     GPIOK, | ||||
|     GPIOB, | ||||
|     GPIOA, | ||||
|     SYSCFG, | ||||
|     SPI1, | ||||
|     SPI2, | ||||
|     SPI3, | ||||
|     I2S2EXT, | ||||
|     I2S3EXT, | ||||
|     SPI4, | ||||
|     SPI5, | ||||
|     SPI6, | ||||
|     SDIO, | ||||
|     ADC1, | ||||
|     ADC2, | ||||
|     ADC3, | ||||
|     USART6, | ||||
|     USART1, | ||||
|     USART2, | ||||
|     USART3, | ||||
|     DAC, | ||||
|     PWR, | ||||
|     I2C3, | ||||
|     I2C2, | ||||
|     I2C1, | ||||
|     IWDG, | ||||
|     WWDG, | ||||
|     RTC, | ||||
|     UART4, | ||||
|     UART5, | ||||
|     UART7, | ||||
|     UART8, | ||||
|     ADC_COMMON, | ||||
|     TIM1, | ||||
|     TIM8, | ||||
|     TIM2, | ||||
| //    TIM3, | ||||
|     TIM4, | ||||
|     TIM5, | ||||
|     TIM9, | ||||
|     TIM12, | ||||
|     TIM10, | ||||
|     TIM13, | ||||
|     TIM14, | ||||
|     TIM11, | ||||
|     TIM6, | ||||
|     TIM7, | ||||
|     ETHERNET_MAC, | ||||
|     ETHERNET_MMC, | ||||
|     ETHERNET_PTP, | ||||
|     ETHERNET_DMA, | ||||
|     CRC, | ||||
|     OTG_FS_GLOBAL, | ||||
|     OTG_FS_HOST, | ||||
|     OTG_FS_DEVICE, | ||||
|     OTG_FS_PWRCLK, | ||||
|     CAN1, | ||||
|     CAN2, | ||||
|     FLASH, | ||||
|     EXTI, | ||||
|     OTG_HS_GLOBAL, | ||||
|     OTG_HS_HOST, | ||||
|     OTG_HS_DEVICE, | ||||
|     OTG_HS_PWRCLK, | ||||
|     SAI1, | ||||
|     LTDC, | ||||
|     HASH, | ||||
|     CRYP, | ||||
|     FPU, | ||||
|     STK, | ||||
|     NVIC_STIR, | ||||
|     FPU_CPACR, | ||||
|     SCB_ACTRL, | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "stm32f407")] | ||||
| embassy_extras::std_peripherals! { | ||||
|     RNG, | ||||
|     DCMI, | ||||
|     FSMC, | ||||
|     DBGMCU, | ||||
|     DMA2, | ||||
|     DMA1, | ||||
| //    RCC, | ||||
|     GPIOI, | ||||
|     GPIOH, | ||||
|     GPIOG, | ||||
|     GPIOF, | ||||
|     GPIOE, | ||||
|     GPIOD, | ||||
|     GPIOC, | ||||
|     GPIOJ, | ||||
|     GPIOK, | ||||
|     GPIOB, | ||||
|     GPIOA, | ||||
|     SYSCFG, | ||||
|     SPI1, | ||||
|     SPI2, | ||||
|     SPI3, | ||||
|     I2S2EXT, | ||||
|     I2S3EXT, | ||||
|     SPI4, | ||||
|     SPI5, | ||||
|     SPI6, | ||||
|     SDIO, | ||||
|     ADC1, | ||||
|     ADC2, | ||||
|     ADC3, | ||||
|     USART6, | ||||
|     USART1, | ||||
|     USART2, | ||||
|     USART3, | ||||
|     DAC, | ||||
|     PWR, | ||||
|     I2C3, | ||||
|     I2C2, | ||||
|     I2C1, | ||||
|     IWDG, | ||||
|     WWDG, | ||||
|     RTC, | ||||
|     UART4, | ||||
|     UART5, | ||||
|     UART7, | ||||
|     UART8, | ||||
|     ADC_COMMON, | ||||
|     TIM1, | ||||
|     TIM8, | ||||
|     TIM2, | ||||
| //    TIM3, | ||||
|     TIM4, | ||||
|     TIM5, | ||||
|     TIM9, | ||||
|     TIM12, | ||||
|     TIM10, | ||||
|     TIM13, | ||||
|     TIM14, | ||||
|     TIM11, | ||||
|     TIM6, | ||||
|     TIM7, | ||||
|     ETHERNET_MAC, | ||||
|     ETHERNET_MMC, | ||||
|     ETHERNET_PTP, | ||||
|     ETHERNET_DMA, | ||||
|     CRC, | ||||
|     OTG_FS_GLOBAL, | ||||
|     OTG_FS_HOST, | ||||
|     OTG_FS_DEVICE, | ||||
|     OTG_FS_PWRCLK, | ||||
|     CAN1, | ||||
|     CAN2, | ||||
|     FLASH, | ||||
|     EXTI, | ||||
|     OTG_HS_GLOBAL, | ||||
|     OTG_HS_HOST, | ||||
|     OTG_HS_DEVICE, | ||||
|     OTG_HS_PWRCLK, | ||||
|     SAI1, | ||||
|     LTDC, | ||||
|     HASH, | ||||
|     CRYP, | ||||
|     FPU, | ||||
|     STK, | ||||
|     NVIC_STIR, | ||||
|     FPU_CPACR, | ||||
|     SCB_ACTRL, | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "stm32l0x2")] | ||||
| embassy_extras::std_peripherals! { | ||||
|     SPI1, | ||||
|     SPI2, | ||||
|     USART1, | ||||
|     USART2, | ||||
|     USART4, | ||||
|     USART5, | ||||
|     I2C1, | ||||
|     I2C2, | ||||
|     I2C3, | ||||
|     RNG, | ||||
|     TIM2, | ||||
|     TIM3, | ||||
|     TIM6, | ||||
|     TIM7, | ||||
|     TIM21, | ||||
|     TIM22, | ||||
|     DAC, | ||||
|     RTC, | ||||
|     PWR, | ||||
|     CRC, | ||||
|     GPIOA, | ||||
|     GPIOB, | ||||
|     GPIOC, | ||||
|     GPIOD, | ||||
|     GPIOE, | ||||
|     GPIOH, | ||||
|     SYSCFG, | ||||
|     DMA1, | ||||
|     EXTI, | ||||
|     ADC, | ||||
|     IWDG, | ||||
|     WWDG, | ||||
|     DBG, | ||||
| } | ||||
		Reference in New Issue
	
	Block a user