mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-25 00:02:28 +00:00
feat: add basic support for nRF51 chips to embassy-nrf
This commit is contained in:
parent
fb22b46ebb
commit
4410aacafb
@ -15,6 +15,7 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-nrf/s
|
||||
|
||||
features = ["time", "defmt", "unstable-pac", "gpiote", "time-driver-rtc1"]
|
||||
flavors = [
|
||||
{ regex_feature = "nrf51", target = "thumbv6m-none-eabi" },
|
||||
{ regex_feature = "nrf52.*", target = "thumbv7em-none-eabihf" },
|
||||
{ regex_feature = "nrf53.*", target = "thumbv8m.main-none-eabihf" },
|
||||
{ regex_feature = "nrf91.*", target = "thumbv8m.main-none-eabihf" },
|
||||
@ -28,6 +29,7 @@ rustdoc-args = ["--cfg", "docsrs"]
|
||||
default = ["rt"]
|
||||
## Cortex-M runtime (enabled by default)
|
||||
rt = [
|
||||
"nrf51-pac?/rt",
|
||||
"nrf52805-pac?/rt",
|
||||
"nrf52810-pac?/rt",
|
||||
"nrf52811-pac?/rt",
|
||||
@ -71,6 +73,8 @@ reset-pin-as-gpio = []
|
||||
qspi-multiwrite-flash = []
|
||||
|
||||
#! ### Chip selection features
|
||||
## nRF51
|
||||
nrf51 = ["nrf51-pac", "_nrf51", "portable-atomic/unsafe-assume-single-core"]
|
||||
## nRF52805
|
||||
nrf52805 = ["nrf52805-pac", "_nrf52"]
|
||||
## nRF52810
|
||||
@ -104,6 +108,7 @@ _nrf5340-net = ["_nrf5340", "nrf5340-net-pac"]
|
||||
_nrf5340 = ["_gpio-p1", "_dppi"]
|
||||
_nrf9160 = ["nrf9160-pac", "_dppi"]
|
||||
_nrf52 = ["_ppi"]
|
||||
_nrf51 = ["_ppi"]
|
||||
|
||||
_time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-32_768"]
|
||||
|
||||
@ -132,6 +137,8 @@ embedded-hal-async = { version = "1.0" }
|
||||
embedded-io = { version = "0.6.0" }
|
||||
embedded-io-async = { version = "0.6.1" }
|
||||
|
||||
portable-atomic = { version = "1", default-features = false, features = ["require-cas"] }
|
||||
|
||||
defmt = { version = "0.3", optional = true }
|
||||
log = { version = "0.4.14", optional = true }
|
||||
cortex-m-rt = ">=0.6.15,<0.8"
|
||||
@ -144,6 +151,7 @@ embedded-storage-async = "0.4.0"
|
||||
cfg-if = "1.0.0"
|
||||
document-features = "0.2.7"
|
||||
|
||||
nrf51-pac = { version = "0.12.0", optional = true }
|
||||
nrf52805-pac = { version = "0.12.0", optional = true }
|
||||
nrf52810-pac = { version = "0.12.0", optional = true }
|
||||
nrf52811-pac = { version = "0.12.0", optional = true }
|
||||
|
168
embassy-nrf/src/chips/nrf51.rs
Normal file
168
embassy-nrf/src/chips/nrf51.rs
Normal file
@ -0,0 +1,168 @@
|
||||
pub use nrf51_pac as pac;
|
||||
|
||||
/// The maximum buffer size that the EasyDMA can send/recv in one operation.
|
||||
pub const EASY_DMA_SIZE: usize = (1 << 14) - 1;
|
||||
pub const FORCE_COPY_BUFFER_SIZE: usize = 256;
|
||||
|
||||
pub const FLASH_SIZE: usize = 128 * 1024;
|
||||
|
||||
embassy_hal_internal::peripherals! {
|
||||
// RTC
|
||||
RTC0,
|
||||
RTC1,
|
||||
|
||||
// WDT
|
||||
WDT,
|
||||
|
||||
// NVMC
|
||||
NVMC,
|
||||
|
||||
// RNG
|
||||
RNG,
|
||||
|
||||
// UARTE
|
||||
UART0,
|
||||
|
||||
// SPI/TWI
|
||||
TWI0,
|
||||
SPI0,
|
||||
|
||||
// ADC
|
||||
ADC,
|
||||
|
||||
// TIMER
|
||||
TIMER0,
|
||||
TIMER1,
|
||||
TIMER2,
|
||||
|
||||
// GPIOTE
|
||||
GPIOTE_CH0,
|
||||
GPIOTE_CH1,
|
||||
GPIOTE_CH2,
|
||||
GPIOTE_CH3,
|
||||
|
||||
// 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,
|
||||
|
||||
// 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,
|
||||
|
||||
// TEMP
|
||||
TEMP,
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
embassy_hal_internal::interrupt_mod!(
|
||||
POWER_CLOCK,
|
||||
RADIO,
|
||||
UART0,
|
||||
SPI0_TWI0,
|
||||
SPI1_TWI1,
|
||||
GPIOTE,
|
||||
ADC,
|
||||
TIMER0,
|
||||
TIMER1,
|
||||
TIMER2,
|
||||
RTC0,
|
||||
TEMP,
|
||||
RNG,
|
||||
ECB,
|
||||
CCM_AAR,
|
||||
WDT,
|
||||
RTC1,
|
||||
QDEC,
|
||||
LPCOMP,
|
||||
SWI0,
|
||||
SWI1,
|
||||
SWI2,
|
||||
SWI3,
|
||||
SWI4,
|
||||
SWI5,
|
||||
);
|
@ -8,8 +8,17 @@ use cfg_if::cfg_if;
|
||||
use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef};
|
||||
|
||||
use self::sealed::Pin as _;
|
||||
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
use crate::pac::p0 as gpio;
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
use crate::pac::p0::pin_cnf::{DRIVE_A, PULL_A};
|
||||
|
||||
#[cfg(feature = "nrf51")]
|
||||
use crate::pac::gpio;
|
||||
#[cfg(feature = "nrf51")]
|
||||
use crate::pac::gpio::pin_cnf::{DRIVE_A, PULL_A};
|
||||
|
||||
use crate::{pac, Peripheral};
|
||||
|
||||
/// A GPIO port with up to 32 pins.
|
||||
@ -376,6 +385,9 @@ pub(crate) mod sealed {
|
||||
fn block(&self) -> &gpio::RegisterBlock {
|
||||
unsafe {
|
||||
match self.pin_port() / 32 {
|
||||
#[cfg(feature = "nrf51")]
|
||||
0 => &*pac::GPIO::ptr(),
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
0 => &*pac::P0::ptr(),
|
||||
#[cfg(feature = "_gpio-p1")]
|
||||
1 => &*pac::P1::ptr(),
|
||||
|
@ -40,6 +40,7 @@ pub(crate) mod util;
|
||||
#[cfg(feature = "_time-driver")]
|
||||
mod time_driver;
|
||||
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
pub mod buffered_uarte;
|
||||
pub mod gpio;
|
||||
#[cfg(feature = "gpiote")]
|
||||
@ -58,7 +59,12 @@ pub mod nvmc;
|
||||
))]
|
||||
pub mod pdm;
|
||||
pub mod ppi;
|
||||
#[cfg(not(any(feature = "nrf52805", feature = "nrf52820", feature = "_nrf5340-net")))]
|
||||
#[cfg(not(any(
|
||||
feature = "nrf51",
|
||||
feature = "nrf52805",
|
||||
feature = "nrf52820",
|
||||
feature = "_nrf5340-net"
|
||||
)))]
|
||||
pub mod pwm;
|
||||
#[cfg(not(any(feature = "nrf51", feature = "_nrf9160", feature = "_nrf5340-net")))]
|
||||
pub mod qdec;
|
||||
@ -66,15 +72,20 @@ pub mod qdec;
|
||||
pub mod qspi;
|
||||
#[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf9160")))]
|
||||
pub mod rng;
|
||||
#[cfg(not(any(feature = "nrf52820", feature = "_nrf5340-net")))]
|
||||
#[cfg(not(any(feature = "nrf51", feature = "nrf52820", feature = "_nrf5340-net")))]
|
||||
pub mod saadc;
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
pub mod spim;
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
pub mod spis;
|
||||
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))]
|
||||
pub mod temp;
|
||||
pub mod timer;
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
pub mod twim;
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
pub mod twis;
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
pub mod uarte;
|
||||
#[cfg(any(
|
||||
feature = "_nrf5340-app",
|
||||
@ -87,6 +98,7 @@ pub mod usb;
|
||||
pub mod wdt;
|
||||
|
||||
// This mod MUST go last, so that it sees all the `impl_foo!` macros
|
||||
#[cfg_attr(feature = "nrf51", path = "chips/nrf51.rs")]
|
||||
#[cfg_attr(feature = "nrf52805", path = "chips/nrf52805.rs")]
|
||||
#[cfg_attr(feature = "nrf52810", path = "chips/nrf52810.rs")]
|
||||
#[cfg_attr(feature = "nrf52811", path = "chips/nrf52811.rs")]
|
||||
@ -374,6 +386,7 @@ pub fn init(config: config::Config) -> Peripherals {
|
||||
let mut needs_reset = false;
|
||||
|
||||
// Setup debug protection.
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
match config.debug {
|
||||
config::Debug::Allowed => {
|
||||
#[cfg(feature = "_nrf52")]
|
||||
@ -489,7 +502,7 @@ pub fn init(config: config::Config) -> Peripherals {
|
||||
}
|
||||
|
||||
// Configure LFCLK.
|
||||
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))]
|
||||
#[cfg(not(any(feature = "nrf51", feature = "_nrf5340", 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()),
|
||||
|
@ -84,6 +84,7 @@ impl<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> Drop for
|
||||
let n = self.ch.number();
|
||||
r.ch[n].eep.write(|w| unsafe { w.bits(0) });
|
||||
r.ch[n].tep.write(|w| unsafe { w.bits(0) });
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
r.fork[n].tep.write(|w| unsafe { w.bits(0) });
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
use core::future::poll_fn;
|
||||
use core::marker::PhantomData;
|
||||
use core::ptr;
|
||||
use core::sync::atomic::{AtomicPtr, Ordering};
|
||||
use portable_atomic::{AtomicPtr, Ordering};
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_hal_internal::drop::OnDrop;
|
||||
|
@ -1,6 +1,6 @@
|
||||
use core::cell::Cell;
|
||||
use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering};
|
||||
use core::{mem, ptr};
|
||||
use portable_atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering};
|
||||
|
||||
use critical_section::CriticalSection;
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
|
@ -122,12 +122,16 @@ impl<'d, T: Instance> Timer<'d, T> {
|
||||
// since changing BITMODE while running can cause 'unpredictable behaviour' according to the specification.
|
||||
this.stop();
|
||||
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
if is_counter {
|
||||
regs.mode.write(|w| w.mode().low_power_counter());
|
||||
} else {
|
||||
regs.mode.write(|w| w.mode().timer());
|
||||
}
|
||||
|
||||
#[cfg(feature = "nrf51")]
|
||||
regs.mode.write(|w| w.mode().timer());
|
||||
|
||||
// Make the counter's max value as high as possible.
|
||||
// TODO: is there a reason someone would want to set this lower?
|
||||
regs.bitmode.write(|w| w.bitmode()._32bit());
|
||||
@ -238,7 +242,11 @@ pub struct Cc<'d, T: Instance> {
|
||||
impl<'d, T: Instance> Cc<'d, T> {
|
||||
/// Get the current value stored in the register.
|
||||
pub fn read(&self) -> u32 {
|
||||
T::regs().cc[self.n].read().cc().bits()
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
return T::regs().cc[self.n].read().cc().bits();
|
||||
|
||||
#[cfg(feature = "nrf51")]
|
||||
return T::regs().cc[self.n].read().bits();
|
||||
}
|
||||
|
||||
/// Set the value stored in the register.
|
||||
@ -246,7 +254,11 @@ impl<'d, T: Instance> Cc<'d, T> {
|
||||
/// `event_compare` will fire when the timer's counter reaches this value.
|
||||
pub fn write(&self, value: u32) {
|
||||
// SAFETY: there are no invalid values for the CC register.
|
||||
T::regs().cc[self.n].write(|w| unsafe { w.cc().bits(value) })
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
T::regs().cc[self.n].write(|w| unsafe { w.cc().bits(value) });
|
||||
|
||||
#[cfg(feature = "nrf51")]
|
||||
T::regs().cc[self.n].write(|w| unsafe { w.bits(value) });
|
||||
}
|
||||
|
||||
/// Capture the current value of the timer's counter in this register, and return it.
|
||||
|
9
examples/nrf51/.cargo/config.toml
Normal file
9
examples/nrf51/.cargo/config.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||
# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list`
|
||||
runner = "probe-rs run --chip nRF51822_xxAA"
|
||||
|
||||
[build]
|
||||
target = "thumbv6m-none-eabi"
|
||||
|
||||
[env]
|
||||
DEFMT_LOG = "trace"
|
20
examples/nrf51/Cargo.toml
Normal file
20
examples/nrf51/Cargo.toml
Normal file
@ -0,0 +1,20 @@
|
||||
[package]
|
||||
edition = "2021"
|
||||
name = "embassy-nrf51-examples"
|
||||
version = "0.1.0"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
|
||||
embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
|
||||
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "time-driver-rtc1", "unstable-pac", "time", "rt"] }
|
||||
|
||||
defmt = "0.3"
|
||||
defmt-rtt = "0.4"
|
||||
|
||||
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
|
||||
cortex-m-rt = "0.7"
|
||||
panic-probe = { version = "0.3", features = ["print-defmt"] }
|
||||
|
||||
[profile.release]
|
||||
debug = 2
|
35
examples/nrf51/build.rs
Normal file
35
examples/nrf51/build.rs
Normal file
@ -0,0 +1,35 @@
|
||||
//! 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");
|
||||
|
||||
println!("cargo:rustc-link-arg-bins=--nmagic");
|
||||
println!("cargo:rustc-link-arg-bins=-Tlink.x");
|
||||
println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
|
||||
}
|
5
examples/nrf51/memory.x
Normal file
5
examples/nrf51/memory.x
Normal file
@ -0,0 +1,5 @@
|
||||
MEMORY
|
||||
{
|
||||
FLASH : ORIGIN = 0x00000000, LENGTH = 256K
|
||||
RAM : ORIGIN = 0x20000000, LENGTH = 32K
|
||||
}
|
21
examples/nrf51/src/bin/blinky.rs
Normal file
21
examples/nrf51/src/bin/blinky.rs
Normal file
@ -0,0 +1,21 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::gpio::{Level, Output, OutputDrive};
|
||||
use embassy_time::Timer;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
let mut led = Output::new(p.P0_21, Level::Low, OutputDrive::Standard);
|
||||
|
||||
loop {
|
||||
led.set_high();
|
||||
Timer::after_millis(300).await;
|
||||
led.set_low();
|
||||
Timer::after_millis(300).await;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user