423: nRF9160 support r=Dirbaio a=diondokter

- Created a chip file with all the peripherals, interrupts and peripheral implementations.
- All peripherals now use an alias for the NS (non-secure) version of the nRF9160 version.
- Implementations of peripherals that don't exist are ignored.
- Most PPI functionality has been stubbed out because the nRF91 has the newer DPPI which is not compatible with the current API. (The channels are also set to not configurable, so they are kinda useless now, but in principle the stubs should never be called)


Co-authored-by: Dion Dokter <dion@tweedegolf.com>
This commit is contained in:
bors[bot] 2021-10-13 21:11:41 +00:00 committed by GitHub
commit 05bc4d198e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 381 additions and 12 deletions

View file

@ -54,6 +54,9 @@ jobs:
- package: embassy-nrf
target: thumbv7em-none-eabi
features: nrf52833
- package: embassy-nrf
target: thumbv8m.main-none-eabihf
features: nrf9160
- package: embassy-nrf
target: thumbv7em-none-eabi
features: nrf52840

View file

@ -25,6 +25,7 @@ nrf52820 = ["nrf52820-pac"]
nrf52832 = ["nrf52832-pac"]
nrf52833 = ["nrf52833-pac"]
nrf52840 = ["nrf52840-pac"]
nrf9160 = ["nrf9160-pac"]
# Features starting with `_` are for internal use only. They're not intended
# to be enabled by other crates, and are not covered by semver guarantees.
@ -55,3 +56,4 @@ nrf52820-pac = { version = "0.10.1", optional = true, features = [ "rt" ] }
nrf52832-pac = { version = "0.10.1", optional = true, features = [ "rt" ] }
nrf52833-pac = { version = "0.10.1", optional = true, features = [ "rt" ] }
nrf52840-pac = { version = "0.10.1", optional = true, features = [ "rt" ] }
nrf9160-pac = { version = "0.10.1", optional = true, features = [ "rt" ] }

View file

@ -0,0 +1,248 @@
#[allow(unused_imports)]
pub mod pac {
// The nRF9160 has a secure and non-secure (NS) mode.
// For now we only support the NS mode, but those peripherals have `_ns` appended to them.
// To avoid cfg spam, weŕe going to rename the ones we use here.
#[rustfmt::skip]
pub(crate) use nrf9160_pac::{
p0_ns as p0,
pwm0_ns as pwm0,
rtc0_ns as rtc0,
spim0_ns as spim0,
timer0_ns as timer0,
twim0_ns as twim0,
uarte0_ns as uarte0,
DPPIC_NS as PPI,
GPIOTE1_NS as GPIOTE,
P0_NS as P0,
RTC1_NS as RTC1,
WDT_NS as WDT,
saadc_ns as saadc,
SAADC_NS as SAADC,
CLOCK_NS as CLOCK,
};
pub use nrf9160_pac::*;
}
/// The maximum buffer size that the EasyDMA can send/recv in one operation.
pub const EASY_DMA_SIZE: usize = (1 << 13) - 1;
pub const FORCE_COPY_BUFFER_SIZE: usize = 1024;
embassy_hal_common::peripherals! {
// RTC
RTC0,
RTC1,
// WDT
WDT,
// UARTE, TWI & SPI
UARTETWISPI0,
UARTETWISPI1,
UARTETWISPI2,
UARTETWISPI3,
// SAADC
SAADC,
// PWM
PWM0,
PWM1,
PWM2,
PWM3,
// 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_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!(UARTETWISPI0, UARTE0_NS, UARTE0_SPIM0_SPIS0_TWIM0_TWIS0);
impl_uarte!(UARTETWISPI1, UARTE1_NS, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1);
impl_uarte!(UARTETWISPI2, UARTE2_NS, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2);
impl_uarte!(UARTETWISPI3, UARTE3_NS, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3);
impl_spim!(UARTETWISPI0, SPIM0_NS, UARTE0_SPIM0_SPIS0_TWIM0_TWIS0);
impl_spim!(UARTETWISPI1, SPIM1_NS, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1);
impl_spim!(UARTETWISPI2, SPIM2_NS, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2);
impl_spim!(UARTETWISPI3, SPIM3_NS, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3);
impl_twim!(UARTETWISPI0, TWIM0_NS, UARTE0_SPIM0_SPIS0_TWIM0_TWIS0);
impl_twim!(UARTETWISPI1, TWIM1_NS, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1);
impl_twim!(UARTETWISPI2, TWIM2_NS, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2);
impl_twim!(UARTETWISPI3, TWIM3_NS, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3);
impl_pwm!(PWM0, PWM0_NS, PWM0);
impl_pwm!(PWM1, PWM1_NS, PWM1);
impl_pwm!(PWM2, PWM2_NS, PWM2);
impl_pwm!(PWM3, PWM3_NS, PWM3);
impl_timer!(TIMER0, TIMER0_NS, TIMER0);
impl_timer!(TIMER1, TIMER1_NS, TIMER1);
impl_timer!(TIMER2, TIMER2_NS, 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);
impl_ppi_channel!(PPI_CH0, 0);
impl_ppi_channel!(PPI_CH1, 1);
impl_ppi_channel!(PPI_CH2, 2);
impl_ppi_channel!(PPI_CH3, 3);
impl_ppi_channel!(PPI_CH4, 4);
impl_ppi_channel!(PPI_CH5, 5);
impl_ppi_channel!(PPI_CH6, 6);
impl_ppi_channel!(PPI_CH7, 7);
impl_ppi_channel!(PPI_CH8, 8);
impl_ppi_channel!(PPI_CH9, 9);
impl_ppi_channel!(PPI_CH10, 10);
impl_ppi_channel!(PPI_CH11, 11);
impl_ppi_channel!(PPI_CH12, 12);
impl_ppi_channel!(PPI_CH13, 13);
impl_ppi_channel!(PPI_CH14, 14);
impl_ppi_channel!(PPI_CH15, 15);
impl_saadc_input!(P0_13, ANALOGINPUT0);
impl_saadc_input!(P0_14, ANALOGINPUT1);
impl_saadc_input!(P0_15, ANALOGINPUT2);
impl_saadc_input!(P0_16, ANALOGINPUT3);
impl_saadc_input!(P0_17, ANALOGINPUT4);
impl_saadc_input!(P0_18, ANALOGINPUT5);
impl_saadc_input!(P0_19, ANALOGINPUT6);
impl_saadc_input!(P0_20, ANALOGINPUT7);
pub mod irqs {
use crate::pac::Interrupt as InterruptEnum;
use embassy_macros::interrupt_declare as declare;
declare!(SPU);
declare!(CLOCK_POWER);
declare!(UARTE0_SPIM0_SPIS0_TWIM0_TWIS0);
declare!(UARTE1_SPIM1_SPIS1_TWIM1_TWIS1);
declare!(UARTE2_SPIM2_SPIS2_TWIM2_TWIS2);
declare!(UARTE3_SPIM3_SPIS3_TWIM3_TWIS3);
declare!(GPIOTE0);
declare!(SAADC);
declare!(TIMER0);
declare!(TIMER1);
declare!(TIMER2);
declare!(RTC0);
declare!(RTC1);
declare!(WDT);
declare!(EGU0);
declare!(EGU1);
declare!(EGU2);
declare!(EGU3);
declare!(EGU4);
declare!(EGU5);
declare!(PWM0);
declare!(PWM1);
declare!(PWM2);
declare!(PDM);
declare!(PWM3);
declare!(I2S);
declare!(IPC);
declare!(FPU);
declare!(GPIOTE1);
declare!(KMU);
declare!(CRYPTOCELL);
}

View file

@ -17,7 +17,7 @@ use self::sealed::Pin as _;
/// A GPIO port with up to 32 pins.
#[derive(Debug, Eq, PartialEq)]
pub enum Port {
/// Port 0, available on all nRF52 and nRF51 MCUs.
/// Port 0, available on nRF9160 and all nRF52 and nRF51 MCUs.
Port0,
/// Port 1, only available on some nRF52 MCUs.

View file

@ -55,7 +55,11 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) {
// Enable interrupts
#[cfg(not(feature = "nrf9160"))]
let irq = unsafe { interrupt::GPIOTE::steal() };
#[cfg(feature = "nrf9160")]
let irq = unsafe { interrupt::GPIOTE1::steal() };
irq.unpend();
irq.set_priority(irq_prio);
irq.enable();
@ -65,8 +69,19 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) {
g.intenset.write(|w| w.port().set());
}
#[cfg(not(feature = "nrf9160"))]
#[interrupt]
unsafe fn GPIOTE() {
fn GPIOTE() {
unsafe { handle_gpiote_interrupt() };
}
#[cfg(feature = "nrf9160")]
#[interrupt]
fn GPIOTE1() {
unsafe { handle_gpiote_interrupt() };
}
unsafe fn handle_gpiote_interrupt() {
let g = &*pac::GPIOTE::ptr();
for i in 0..CHANNEL_COUNT {

View file

@ -34,6 +34,7 @@ pub mod ppi;
pub mod pwm;
#[cfg(feature = "nrf52840")]
pub mod qspi;
#[cfg(not(feature = "nrf9160"))]
pub mod rng;
#[cfg(not(feature = "nrf52820"))]
pub mod saadc;
@ -65,6 +66,9 @@ mod chip;
#[cfg(feature = "nrf52840")]
#[path = "chips/nrf52840.rs"]
mod chip;
#[cfg(feature = "nrf9160")]
#[path = "chips/nrf9160.rs"]
mod chip;
pub use chip::EASY_DMA_SIZE;
@ -73,6 +77,7 @@ pub use chip::pac;
#[cfg(not(feature = "unstable-pac"))]
pub(crate) use chip::pac;
use crate::pac::CLOCK;
pub use chip::{peripherals, Peripherals};
pub mod interrupt {
@ -91,9 +96,12 @@ pub mod config {
pub enum LfclkSource {
InternalRC,
#[cfg(not(feature = "nrf9160"))]
Synthesized,
ExternalXtal,
#[cfg(not(feature = "nrf9160"))]
ExternalLowSwing,
#[cfg(not(feature = "nrf9160"))]
ExternalFullSwing,
}
@ -129,7 +137,7 @@ pub fn init(config: config::Config) -> Peripherals {
// before doing anything important.
let peripherals = Peripherals::take();
let r = unsafe { &*pac::CLOCK::ptr() };
let r = unsafe { &*CLOCK::ptr() };
// Start HFCLK.
match config.hfclk_source {
@ -143,6 +151,7 @@ pub fn init(config: config::Config) -> Peripherals {
}
// Configure LFCLK.
#[cfg(not(feature = "nrf9160"))]
match config.lfclk_source {
config::LfclkSource::InternalRC => r.lfclksrc.write(|w| w.src().rc()),
config::LfclkSource::Synthesized => r.lfclksrc.write(|w| w.src().synth()),
@ -162,6 +171,11 @@ pub fn init(config: config::Config) -> Peripherals {
w
}),
}
#[cfg(feature = "nrf9160")]
match config.lfclk_source {
config::LfclkSource::InternalRC => r.lfclksrc.write(|w| w.src().lfrc()),
config::LfclkSource::ExternalXtal => r.lfclksrc.write(|w| w.src().lfxo()),
}
// Start LFCLK.
// Datasheet says this could take 100us from synth source

View file

@ -11,13 +11,12 @@
//! On nRF52 devices, there is also a fork task endpoint, where the user can configure one more task
//! to be triggered by the same event, even fixed PPI channels have a configurable fork task.
use crate::{pac, peripherals};
use core::marker::PhantomData;
use core::ptr::NonNull;
use embassy::util::Unborrow;
use embassy_hal_common::{unborrow, unsafe_impl_unborrow};
use crate::{pac, peripherals};
// ======================
// driver
@ -29,11 +28,13 @@ pub struct Ppi<'d, C: Channel> {
impl<'d, C: Channel> Ppi<'d, C> {
pub fn new(ch: impl Unborrow<Target = C> + 'd) -> Self {
unborrow!(ch);
#[allow(unused_mut)]
let mut this = Self {
ch,
phantom: PhantomData,
};
#[cfg(not(feature = "nrf51"))]
#[cfg(not(any(feature = "nrf51", feature = "nrf9160")))]
this.clear_fork_task();
this
}
@ -52,7 +53,7 @@ impl<'d, C: Channel> Ppi<'d, C> {
.write(|w| unsafe { w.bits(1 << self.ch.number()) });
}
#[cfg(not(feature = "nrf51"))]
#[cfg(not(any(feature = "nrf51", feature = "nrf9160")))]
/// Sets the fork task that must be triggered when the configured event occurs. The user must
/// provide a reference to the task.
pub fn set_fork_task(&mut self, task: Task) {
@ -62,12 +63,25 @@ impl<'d, C: Channel> Ppi<'d, C> {
.write(|w| unsafe { w.bits(task.0.as_ptr() as u32) })
}
#[cfg(not(feature = "nrf51"))]
#[cfg(not(any(feature = "nrf51", feature = "nrf9160")))]
/// Clear the fork task endpoint. Previously set task will no longer be triggered.
pub fn clear_fork_task(&mut self) {
let r = unsafe { &*pac::PPI::ptr() };
r.fork[self.ch.number()].tep.write(|w| unsafe { w.bits(0) })
}
#[cfg(feature = "nrf9160")]
/// Sets the fork task that must be triggered when the configured event occurs. The user must
/// provide a reference to the task.
pub fn set_fork_task(&mut self, _task: Task) {
todo!("Tasks not yet implemented for nrf9160");
}
#[cfg(feature = "nrf9160")]
/// Clear the fork task endpoint. Previously set task will no longer be triggered.
pub fn clear_fork_task(&mut self) {
todo!("Tasks not yet implemented for nrf9160");
}
}
impl<'d, C: Channel> Drop for Ppi<'d, C> {
@ -76,6 +90,7 @@ impl<'d, C: Channel> Drop for Ppi<'d, C> {
}
}
#[cfg(not(feature = "nrf9160"))]
impl<'d, C: ConfigurableChannel> Ppi<'d, C> {
/// Sets the task to be triggered when the configured event occurs.
pub fn set_task(&mut self, task: Task) {
@ -94,6 +109,19 @@ impl<'d, C: ConfigurableChannel> Ppi<'d, C> {
}
}
#[cfg(feature = "nrf9160")]
impl<'d, C: ConfigurableChannel> Ppi<'d, C> {
/// Sets the task to be triggered when the configured event occurs.
pub fn set_task(&mut self, _task: Task) {
todo!("Tasks not yet implemented for nrf9160")
}
/// Sets the event that will trigger the chosen task(s).
pub fn set_event(&mut self, _event: Event) {
todo!("Events not yet implemented for nrf9160")
}
}
// ======================
// traits

View file

@ -68,8 +68,6 @@ impl<'d, T: Instance> Uarte<'d, T> {
let r = T::regs();
assert!(r.enable.read().enable().is_disabled());
rxd.conf().write(|w| w.input().connect().drive().h0h1());
r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) });
@ -114,6 +112,7 @@ impl<'d, T: Instance> Uarte<'d, T> {
irq.enable();
// Enable
Self::apply_workaround_for_enable_anomaly();
r.enable.write(|w| w.enable().enabled());
Self {
@ -121,6 +120,61 @@ impl<'d, T: Instance> Uarte<'d, T> {
}
}
#[cfg(not(any(feature = "nrf9160", feature = "nrf5340")))]
fn apply_workaround_for_enable_anomaly() {
// Do nothing
}
#[cfg(any(feature = "nrf9160", feature = "nrf5340"))]
fn apply_workaround_for_enable_anomaly() {
use core::ops::Deref;
let r = T::regs();
// Apply workaround for anomalies:
// - nRF9160 - anomaly 23
// - nRF5340 - anomaly 44
let rxenable_reg: *const u32 = ((r.deref() as *const _ as usize) + 0x564) as *const u32;
let txenable_reg: *const u32 = ((r.deref() as *const _ as usize) + 0x568) as *const u32;
// NB Safety: This is taken from Nordic's driver -
// https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197
if unsafe { core::ptr::read_volatile(txenable_reg) } == 1 {
r.tasks_stoptx.write(|w| unsafe { w.bits(1) });
}
// NB Safety: This is taken from Nordic's driver -
// https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197
if unsafe { core::ptr::read_volatile(rxenable_reg) } == 1 {
r.enable.write(|w| w.enable().enabled());
r.tasks_stoprx.write(|w| unsafe { w.bits(1) });
let mut workaround_succeded = false;
// The UARTE is able to receive up to four bytes after the STOPRX task has been triggered.
// On lowest supported baud rate (1200 baud), with parity bit and two stop bits configured
// (resulting in 12 bits per data byte sent), this may take up to 40 ms.
for _ in 0..40000 {
// NB Safety: This is taken from Nordic's driver -
// https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197
if unsafe { core::ptr::read_volatile(rxenable_reg) } == 0 {
workaround_succeded = true;
break;
} else {
// Need to sleep for 1us here
}
}
if !workaround_succeded {
panic!("Failed to apply workaround for UART");
}
let errors = r.errorsrc.read().bits();
// NB Safety: safe to write back the bits we just read to clear them
r.errorsrc.write(|w| unsafe { w.bits(errors) });
r.enable.write(|w| w.enable().disabled());
}
}
fn on_interrupt(_: *mut ()) {
let r = T::regs();
let s = T::state();

View file

@ -58,7 +58,12 @@ impl Watchdog {
let crv = config.timeout_ticks.max(MIN_TICKS);
let rren = (1u32 << N) - 1;
if r.runstatus.read().runstatus().bit() {
#[cfg(not(feature = "nrf9160"))]
let runstatus = r.runstatus.read().runstatus().bit();
#[cfg(feature = "nrf9160")]
let runstatus = r.runstatus.read().runstatuswdt().bit();
if runstatus {
let curr_config = r.config.read();
if curr_config.halt().bit() != config.run_during_debug_halt
|| curr_config.sleep().bit() != config.run_during_sleep

View file

@ -3,4 +3,4 @@
[toolchain]
channel = "nightly-2021-08-18"
components = [ "rust-src", "rustfmt" ]
targets = [ "thumbv7em-none-eabi", "thumbv7m-none-eabi", "thumbv6m-none-eabi", "thumbv7em-none-eabihf", "wasm32-unknown-unknown" ]
targets = [ "thumbv7em-none-eabi", "thumbv7m-none-eabi", "thumbv6m-none-eabi", "thumbv7em-none-eabihf", "thumbv8m.main-none-eabihf", "wasm32-unknown-unknown" ]