2022-06-23 12:59:18 +02:00
//! # Embassy nRF HAL
//!
//! HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so raw register manipulation is not needed.
//!
//! The Embassy nRF HAL targets the Nordic Semiconductor nRF family of hardware. The HAL implements both blocking and async APIs
//! for many peripherals. The benefit of using the async APIs is that the HAL takes care of waiting for peripherals to
//! complete operations in low power mod and handling interrupts, so that applications can focus on more important matters.
//!
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:
2022-06-23 12:59:18 +02:00
//! - Functions with the suffix (e.g. [`write_from_ram`](spim::Spim::write_from_ram), [`transfer_from_ram`](spim::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::Spim::write), [`transfer`](spim::Spim::transfer)) will check whether the data is in RAM and copy it into memory prior to transmission.
2022-03-08 16:42:46 +01:00
//!
//! 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-06-12 22:15:44 +02:00
#![ cfg_attr(feature = " nightly " , feature(generic_associated_types, type_alias_impl_trait)) ]
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 ;
2022-05-04 20:48:37 +02:00
#[ cfg(feature = " nightly " ) ]
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 ;
2022-05-07 00:46:36 +02:00
#[ cfg(not(any(feature = " nrf51 " , feature = " _nrf9160 " , feature = " _nrf5340 " ))) ]
pub mod qdec ;
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 ;
2022-06-11 05:08:57 +02:00
pub mod interrupt {
2022-06-23 12:59:18 +02:00
//! nRF interrupts for cortex-m devices.
2022-06-11 05:08:57 +02:00
pub use cortex_m ::interrupt ::{ CriticalSection , Mutex } ;
pub use embassy_cortex_m ::interrupt ::* ;
2022-06-12 22:15:44 +02:00
pub use crate ::chip ::irqs ::* ;
2022-06-11 05:08:57 +02:00
}
// Reexports
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-10-12 11:43:57 +02:00
pub use chip ::{ peripherals , Peripherals } ;
2022-06-11 05:08:57 +02:00
pub use embassy_cortex_m ::executor ;
pub use embassy_hal_common ::{ unborrow , Unborrow } ;
pub use embassy_macros ::cortex_m_interrupt as interrupt ;
2021-05-12 01:57:01 +02:00
pub mod config {
2022-06-23 12:59:18 +02:00
//! Configuration options used when initializing the HAL.
/// High frequency clock source.
2021-05-12 01:57:01 +02:00
pub enum HfclkSource {
2022-06-23 12:59:18 +02:00
/// Internal source
2021-05-12 01:57:01 +02:00
Internal ,
2022-06-23 12:59:18 +02:00
/// External source from xtal.
2021-05-12 01:57:01 +02:00
ExternalXtal ,
}
2022-06-23 12:59:18 +02:00
/// Low frequency clock source
2021-05-12 01:57:01 +02:00
pub enum LfclkSource {
2022-06-23 12:59:18 +02:00
/// Internal RC oscillator
2021-05-12 01:57:01 +02:00
InternalRC ,
2022-06-23 12:59:18 +02:00
/// Synthesized from the high frequency clock source.
2021-10-28 03:07:06 +02:00
#[ cfg(not(any(feature = " _nrf5340 " , feature = " _nrf9160 " ))) ]
2021-05-12 01:57:01 +02:00
Synthesized ,
2022-06-23 12:59:18 +02:00
/// External source from xtal.
2021-05-12 01:57:01 +02:00
ExternalXtal ,
2022-06-23 12:59:18 +02:00
/// External source from xtal with low swing applied.
2021-10-28 03:07:06 +02:00
#[ cfg(not(any(feature = " _nrf5340 " , feature = " _nrf9160 " ))) ]
2021-05-12 01:57:01 +02:00
ExternalLowSwing ,
2022-06-23 12:59:18 +02:00
/// External source from xtal with full swing applied.
2021-10-28 03:07:06 +02:00
#[ cfg(not(any(feature = " _nrf5340 " , feature = " _nrf9160 " ))) ]
2021-05-12 01:57:01 +02:00
ExternalFullSwing ,
}
2022-06-23 12:59:18 +02:00
/// Configuration for peripherals. Default configuration should work on any nRF chip.
2021-05-12 01:57:01 +02:00
#[ non_exhaustive ]
pub struct Config {
2022-06-23 12:59:18 +02:00
/// High frequency clock source.
2021-05-12 01:57:01 +02:00
pub hfclk_source : HfclkSource ,
2022-06-23 12:59:18 +02:00
/// Low frequency clock source.
2021-05-12 01:57:01 +02:00
pub lfclk_source : LfclkSource ,
2022-06-23 12:59:18 +02:00
/// GPIOTE interrupt priority. Should be lower priority than softdevice if used.
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 ,
2022-06-23 12:59:18 +02:00
/// Time driver interrupt priority. Should be lower priority than softdevice if used.
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
}
}
}
}
2022-06-23 12:59:18 +02:00
/// Initialize peripherals with the provided configuration. This should only be called once at startup.
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
}