2022-03-08 16:42:46 +01:00
//! ## EasyDMA considerations
//!
//! On nRF chips, peripherals can use the so called EasyDMA feature to offload the task of interacting
//! with peripherals. It takes care of sending/receiving data over a variety of bus protocols (TWI/I2C, UART, SPI).
//! However, EasyDMA requires the buffers used to transmit and receive data to reside in RAM. Unfortunately, Rust
//! slices will not always do so. The following example using the SPI peripheral shows a common situation where this might happen:
//!
//! ```no_run
//! // As we pass a slice to the function whose contents will not ever change,
//! // the compiler writes it into the flash and thus the pointer to it will
//! // reference static memory. Since EasyDMA requires slices to reside in RAM,
//! // this function call will fail.
//! let result = spim.write_from_ram(&[1, 2, 3]);
//! assert_eq!(result, Err(Error::DMABufferNotInDataMemory));
//!
//! // The data is still static and located in flash. However, since we are assigning
//! // it to a variable, the compiler will load it into memory. Passing a reference to the
//! // variable will yield a pointer that references dynamic memory, thus making EasyDMA happy.
//! // This function call succeeds.
//! let data = [1, 2, 3];
//! let result = spim.write_from_ram(&data);
//! assert!(result.is_ok());
//! ```
//!
//! Each peripheral struct which uses EasyDMA ([`Spim`](spim::Spim), [`Uarte`](uarte::Uarte), [`Twim`](twim::Twim)) has two variants of their mutating functions:
//! - Functions with the suffix (e.g. [`write_from_ram`](Spim::write_from_ram), [`transfer_from_ram`](Spim::transfer_from_ram)) will return an error if the passed slice does not reside in RAM.
//! - Functions without the suffix (e.g. [`write`](Spim::write), [`transfer`](Spim::transfer)) will check whether the data is in RAM and copy it into memory prior to transmission.
//!
//! Since copying incurs a overhead, you are given the option to choose from `_from_ram` variants which will
//! fail and notify you, or the more convenient versions without the suffix which are potentially a little bit
//! more inefficient. Be aware that this overhead is not only in terms of instruction count but also in terms of memory usage
//! as the methods without the suffix will be allocating a statically sized buffer (up to 512 bytes for the nRF52840).
//!
//! Note that the methods that read data like [`read`](spim::Spim::read) and [`transfer_in_place`](spim::Spim::transfer_in_place) do not have the corresponding `_from_ram` variants as
//! mutable slices always reside in RAM.
2020-09-22 18:03:43 +02:00
#![ no_std ]
2022-02-12 00:24:04 +01:00
#![ cfg_attr(
feature = " nightly " ,
2022-02-23 23:30:50 +01:00
feature ( generic_associated_types , type_alias_impl_trait )
2022-02-12 00:24:04 +01:00
) ]
2020-09-22 18:03:43 +02:00
#[ cfg(not(any(
2021-05-11 03:04:59 +02:00
feature = " nrf51 " ,
feature = " nrf52805 " ,
feature = " nrf52810 " ,
feature = " nrf52811 " ,
feature = " nrf52820 " ,
feature = " nrf52832 " ,
feature = " nrf52833 " ,
feature = " nrf52840 " ,
2021-10-28 03:07:06 +02:00
feature = " nrf5340-app-s " ,
feature = " nrf5340-app-ns " ,
2021-05-11 03:04:59 +02:00
feature = " nrf5340-net " ,
2021-10-26 17:11:51 +02:00
feature = " nrf9160-s " ,
feature = " nrf9160-ns " ,
2020-09-22 18:03:43 +02:00
) ) ) ]
2021-05-11 03:04:59 +02:00
compile_error! ( " No chip feature activated. You must activate exactly one of the following features: nrf52810, nrf52811, nrf52832, nrf52833, nrf52840 " ) ;
2021-01-18 14:22:55 +01:00
2020-12-01 17:46:56 +01:00
// This mod MUST go first, so that the others see its macros.
pub ( crate ) mod fmt ;
2021-05-11 03:04:59 +02:00
pub ( crate ) mod util ;
2020-12-01 17:46:56 +01:00
2021-08-20 15:42:42 +02:00
#[ cfg(feature = " _time-driver " ) ]
2021-08-03 22:08:13 +02:00
mod time_driver ;
2020-12-28 23:57:50 +01:00
pub mod buffered_uarte ;
2021-03-19 04:08:44 +01:00
pub mod gpio ;
2021-08-20 15:42:42 +02:00
#[ cfg(feature = " gpiote " ) ]
2020-09-23 00:32:49 +02:00
pub mod gpiote ;
2021-10-28 03:07:06 +02:00
#[ cfg(not(any(feature = " _nrf5340 " , feature = " _nrf9160 " ))) ]
2021-10-22 02:09:55 +02:00
pub mod nvmc ;
2021-03-27 04:40:05 +01:00
pub mod ppi ;
2021-10-28 03:07:06 +02:00
#[ cfg(not(any(feature = " nrf52805 " , feature = " nrf52820 " , feature = " _nrf5340-net " ))) ]
2021-05-12 04:56:11 +02:00
pub mod pwm ;
2021-05-11 03:04:59 +02:00
#[ cfg(feature = " nrf52840 " ) ]
2020-09-22 18:03:43 +02:00
pub mod qspi ;
2021-10-28 03:07:06 +02:00
#[ cfg(not(any(feature = " _nrf5340 " , feature = " _nrf9160 " ))) ]
2021-06-29 09:26:16 +02:00
pub mod rng ;
2021-10-28 03:07:06 +02:00
#[ cfg(not(any(feature = " nrf52820 " , feature = " _nrf5340-net " ))) ]
2021-03-24 18:33:17 +01:00
pub mod saadc ;
2021-01-18 14:22:55 +01:00
pub mod spim ;
2021-10-28 03:07:06 +02:00
#[ cfg(not(any(feature = " _nrf5340 " , feature = " _nrf9160 " ))) ]
2021-10-19 08:37:19 +02:00
pub mod temp ;
2021-03-28 22:40:41 +02:00
pub mod timer ;
2021-05-11 03:07:37 +02:00
pub mod twim ;
2020-12-23 16:18:29 +01:00
pub mod uarte ;
2021-12-15 18:11:00 +01:00
#[ cfg(any(
feature = " _nrf5340-app " ,
feature = " nrf52820 " ,
feature = " nrf52833 " ,
feature = " nrf52840 "
) ) ]
2022-03-30 01:18:37 +02:00
#[ cfg(feature = " nightly " ) ]
2021-12-14 01:50:08 +01:00
pub mod usb ;
2021-10-28 03:07:06 +02:00
#[ cfg(not(feature = " _nrf5340 " )) ]
2021-08-07 14:26:28 +02:00
pub mod wdt ;
2021-03-21 21:58:59 +01:00
2021-05-11 03:04:59 +02:00
// This mod MUST go last, so that it sees all the `impl_foo!` macros
2021-10-26 17:11:51 +02:00
#[ cfg_attr(feature = " nrf52805 " , path = " chips/nrf52805.rs " ) ]
#[ cfg_attr(feature = " nrf52810 " , path = " chips/nrf52810.rs " ) ]
#[ cfg_attr(feature = " nrf52811 " , path = " chips/nrf52811.rs " ) ]
#[ cfg_attr(feature = " nrf52820 " , path = " chips/nrf52820.rs " ) ]
#[ cfg_attr(feature = " nrf52832 " , path = " chips/nrf52832.rs " ) ]
#[ cfg_attr(feature = " nrf52833 " , path = " chips/nrf52833.rs " ) ]
#[ cfg_attr(feature = " nrf52840 " , path = " chips/nrf52840.rs " ) ]
2021-10-28 03:07:06 +02:00
#[ cfg_attr(feature = " _nrf5340-app " , path = " chips/nrf5340_app.rs " ) ]
#[ cfg_attr(feature = " _nrf5340-net " , path = " chips/nrf5340_net.rs " ) ]
2021-10-26 17:11:51 +02:00
#[ cfg_attr(feature = " _nrf9160 " , path = " chips/nrf9160.rs " ) ]
2021-10-11 10:39:38 +02:00
mod chip ;
2021-05-11 03:04:59 +02:00
2021-08-22 01:23:03 +02:00
pub use chip ::EASY_DMA_SIZE ;
2021-07-14 22:19:04 +02:00
#[ cfg(feature = " unstable-pac " ) ]
pub use chip ::pac ;
#[ cfg(not(feature = " unstable-pac " )) ]
2021-05-11 03:04:59 +02:00
pub ( crate ) use chip ::pac ;
2021-07-14 22:19:04 +02:00
2022-03-27 19:29:29 +02:00
pub use embassy ::util ::Unborrow ;
pub use embassy_hal_common ::unborrow ;
2021-10-12 11:43:57 +02:00
pub use chip ::{ peripherals , Peripherals } ;
2021-10-11 10:39:38 +02:00
2021-05-11 03:04:59 +02:00
pub mod interrupt {
pub use crate ::chip ::irqs ::* ;
pub use cortex_m ::interrupt ::{ CriticalSection , Mutex } ;
pub use embassy ::interrupt ::{ declare , take , Interrupt } ;
2021-07-29 13:44:51 +02:00
pub use embassy_hal_common ::interrupt ::Priority3 as Priority ;
2021-03-21 21:58:59 +01:00
}
2021-05-12 01:00:43 +02:00
pub use embassy_macros ::interrupt ;
2021-05-12 01:57:01 +02:00
pub mod config {
pub enum HfclkSource {
Internal ,
ExternalXtal ,
}
pub enum LfclkSource {
InternalRC ,
2021-10-28 03:07:06 +02:00
#[ cfg(not(any(feature = " _nrf5340 " , feature = " _nrf9160 " ))) ]
2021-05-12 01:57:01 +02:00
Synthesized ,
ExternalXtal ,
2021-10-28 03:07:06 +02:00
#[ cfg(not(any(feature = " _nrf5340 " , feature = " _nrf9160 " ))) ]
2021-05-12 01:57:01 +02:00
ExternalLowSwing ,
2021-10-28 03:07:06 +02:00
#[ cfg(not(any(feature = " _nrf5340 " , feature = " _nrf9160 " ))) ]
2021-05-12 01:57:01 +02:00
ExternalFullSwing ,
}
#[ non_exhaustive ]
pub struct Config {
pub hfclk_source : HfclkSource ,
pub lfclk_source : LfclkSource ,
2021-08-20 15:42:42 +02:00
#[ cfg(feature = " gpiote " ) ]
2021-05-17 21:27:27 +02:00
pub gpiote_interrupt_priority : crate ::interrupt ::Priority ,
2021-08-20 15:42:42 +02:00
#[ cfg(feature = " _time-driver " ) ]
2021-08-18 22:12:36 +02:00
pub time_interrupt_priority : crate ::interrupt ::Priority ,
2021-05-12 01:57:01 +02:00
}
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 ,
2021-08-20 15:42:42 +02:00
#[ cfg(feature = " gpiote " ) ]
2021-05-17 21:27:27 +02:00
gpiote_interrupt_priority : crate ::interrupt ::Priority ::P0 ,
2021-08-20 15:42:42 +02:00
#[ cfg(feature = " _time-driver " ) ]
2021-08-18 22:12:36 +02:00
time_interrupt_priority : crate ::interrupt ::Priority ::P0 ,
2021-05-12 01:57:01 +02:00
}
}
}
}
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 ( ) ;
2021-10-28 03:07:06 +02:00
let r = unsafe { & * pac ::CLOCK ::ptr ( ) } ;
2021-05-12 01:57:01 +02:00
// 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.
2021-10-28 03:07:06 +02:00
#[ cfg(not(any(feature = " _nrf5340 " , feature = " _nrf9160 " ))) ]
2021-05-12 01:57:01 +02:00
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
} ) ,
}
2021-10-26 17:11:51 +02:00
#[ cfg(feature = " _nrf9160 " ) ]
2021-10-11 10:39:38 +02:00
match config . lfclk_source {
config ::LfclkSource ::InternalRC = > r . lfclksrc . write ( | w | w . src ( ) . lfrc ( ) ) ,
config ::LfclkSource ::ExternalXtal = > r . lfclksrc . write ( | w | w . src ( ) . lfxo ( ) ) ,
}
2021-05-12 01:57:01 +02:00
// 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
2021-08-20 15:42:42 +02:00
#[ cfg(feature = " gpiote " ) ]
2021-08-03 22:08:13 +02:00
gpiote ::init ( config . gpiote_interrupt_priority ) ;
// init RTC time driver
2021-08-20 15:42:42 +02:00
#[ cfg(feature = " _time-driver " ) ]
2021-08-18 22:12:36 +02:00
time_driver ::init ( config . time_interrupt_priority ) ;
2021-05-12 01:57:01 +02:00
peripherals
}