Merge remote-tracking branch 'origin/main' into nrf-pdm

This commit is contained in:
Quentin Smith
2023-07-17 21:31:43 -04:00
863 changed files with 74741 additions and 28517 deletions

View File

@ -0,0 +1,3 @@
[profile.release]
# Allows defmt to display log locations even in release
debug = true

View File

@ -1,6 +1,6 @@
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
# replace nRF82840_xxAA with your chip as listed in `probe-run --list-chips`
runner = "probe-run --chip nRF52840_xxAA"
# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list`
runner = "probe-rs run --chip nRF52840_xxAA"
[build]
target = "thumbv7em-none-eabi"

View File

@ -2,19 +2,26 @@
edition = "2021"
name = "embassy-boot-nrf-examples"
version = "0.1.0"
license = "MIT OR Apache-2.0"
[dependencies]
embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly"] }
embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", "nightly", "nrf52840"] }
embassy-boot-nrf = { version = "0.1.0", path = "../../../../embassy-boot/nrf" }
embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] }
embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly"] }
embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", "nightly"] }
embassy-boot = { version = "0.1.0", path = "../../../../embassy-boot/boot", features = ["nightly"] }
embassy-boot-nrf = { version = "0.1.0", path = "../../../../embassy-boot/nrf", features = ["nightly"] }
embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
defmt = { version = "0.3", optional = true }
defmt-rtt = { version = "0.3", optional = true }
defmt-rtt = { version = "0.4", optional = true }
panic-reset = { version = "0.1.1" }
embedded-hal = { version = "0.2.6" }
cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
cortex-m-rt = "0.7.0"
[features]
ed25519-dalek = ["embassy-boot/ed25519-dalek"]
ed25519-salty = ["embassy-boot/ed25519-salty"]
skip-include = []

View File

@ -1,6 +1,6 @@
# Examples using bootloader
Example for nRF52 demonstrating the bootloader. The example consists of application binaries, 'a'
Example for nRF demonstrating the bootloader. The example consists of application binaries, 'a'
which allows you to press a button to start the DFU process, and 'b' which is the updated
application.
@ -20,15 +20,19 @@ application.
cp memory-bl.x ../../bootloader/nrf/memory.x
# Flash bootloader
cargo flash --manifest-path ../../bootloader/nrf/Cargo.toml --features embassy-nrf/nrf52840 --release --chip nRF52840_xxAA
cargo flash --manifest-path ../../bootloader/nrf/Cargo.toml --features embassy-nrf/nrf52840 --target thumbv7em-none-eabi --release --chip nRF52840_xxAA
# Build 'b'
cargo build --release --bin b
cargo build --release --bin b --features embassy-nrf/nrf52840
# Generate binary for 'b'
cargo objcopy --release --bin b -- -O binary b.bin
cargo objcopy --release --bin b --features embassy-nrf/nrf52840 --target thumbv7em-none-eabi -- -O binary b.bin
```
# Flash `a` (which includes b.bin)
```
cargo flash --release --bin a --chip nRF52840_xxAA
cargo flash --release --bin a --features embassy-nrf/nrf52840 --target thumbv7em-none-eabi --chip nRF52840_xxAA
```
You should then see a solid LED. Pressing button 1 will cause the DFU to be loaded by the bootloader. Upon
successfully loading, you'll see the LED flash. After 5 seconds, because there is no petting of the watchdog,
you'll see the LED go solid again. This indicates that the bootloader has reverted the update.

View File

@ -0,0 +1,19 @@
MEMORY
{
/* NOTE 1 K = 1 KiBi = 1024 bytes */
/* Assumes Secure Partition Manager (SPM) flashed at the start */
FLASH : ORIGIN = 0x00050000, LENGTH = 24K
BOOTLOADER_STATE : ORIGIN = 0x00056000, LENGTH = 4K
ACTIVE : ORIGIN = 0x00057000, LENGTH = 64K
DFU : ORIGIN = 0x00067000, LENGTH = 68K
RAM (rwx) : ORIGIN = 0x20018000, LENGTH = 32K
}
__bootloader_state_start = ORIGIN(BOOTLOADER_STATE);
__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE);
__bootloader_active_start = ORIGIN(ACTIVE);
__bootloader_active_end = ORIGIN(ACTIVE) + LENGTH(ACTIVE);
__bootloader_dfu_start = ORIGIN(DFU);
__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU);

View File

@ -5,7 +5,7 @@ MEMORY
BOOTLOADER_STATE : ORIGIN = 0x00006000, LENGTH = 4K
ACTIVE : ORIGIN = 0x00007000, LENGTH = 64K
DFU : ORIGIN = 0x00017000, LENGTH = 68K
RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 32K
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
}
__bootloader_state_start = ORIGIN(BOOTLOADER_STATE);

View File

@ -0,0 +1,16 @@
MEMORY
{
/* NOTE 1 K = 1 KiBi = 1024 bytes */
/* Assumes Secure Partition Manager (SPM) flashed at the start */
BOOTLOADER : ORIGIN = 0x00050000, LENGTH = 24K
BOOTLOADER_STATE : ORIGIN = 0x00056000, LENGTH = 4K
FLASH : ORIGIN = 0x00057000, LENGTH = 64K
DFU : ORIGIN = 0x00067000, LENGTH = 68K
RAM (rwx) : ORIGIN = 0x20018000, LENGTH = 32K
}
__bootloader_state_start = ORIGIN(BOOTLOADER_STATE);
__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE);
__bootloader_dfu_start = ORIGIN(DFU);
__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU);

View File

@ -5,7 +5,7 @@ MEMORY
BOOTLOADER_STATE : ORIGIN = 0x00006000, LENGTH = 4K
FLASH : ORIGIN = 0x00007000, LENGTH = 64K
DFU : ORIGIN = 0x00017000, LENGTH = 68K
RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 32K
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
}
__bootloader_state_start = ORIGIN(BOOTLOADER_STATE);

View File

@ -1,42 +1,71 @@
#![no_std]
#![no_main]
#![macro_use]
#![feature(generic_associated_types)]
#![feature(type_alias_impl_trait)]
use embassy_boot_nrf::FirmwareUpdater;
use embassy_boot_nrf::{FirmwareUpdater, FirmwareUpdaterConfig};
use embassy_embedded_hal::adapter::BlockingAsync;
use embassy_executor::Spawner;
use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull};
use embassy_nrf::nvmc::Nvmc;
use embassy_nrf::wdt::{self, Watchdog};
use embassy_sync::mutex::Mutex;
use panic_reset as _;
#[cfg(feature = "skip-include")]
static APP_B: &[u8] = &[0, 1, 2, 3];
#[cfg(not(feature = "skip-include"))]
static APP_B: &[u8] = include_bytes!("../../b.bin");
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_nrf::init(Default::default());
let mut button = Input::new(p.P0_11, Pull::Up);
let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard);
//let mut led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard);
//let mut button = Input::new(p.P1_02, Pull::Up);
let nvmc = Nvmc::new(p.NVMC);
let mut nvmc = BlockingAsync::new(nvmc);
// nRF91 DK
// let mut led = Output::new(p.P0_02, Level::Low, OutputDrive::Standard);
// let mut button = Input::new(p.P0_06, Pull::Up);
let mut updater = FirmwareUpdater::default();
// The following code block illustrates how to obtain a watchdog that is configured
// as per the existing watchdog. Ordinarily, we'd use the handle returned to "pet" the
// watchdog periodically. If we don't, and we're not going to for this example, then
// the watchdog will cause the device to reset as per its configured timeout in the bootloader.
// This helps is avoid a situation where new firmware might be bad and block our executor.
// If firmware is bad in this way then the bootloader will revert to any previous version.
let wdt_config = wdt::Config::try_new(&p.WDT).unwrap();
let (_wdt, [_wdt_handle]) = match Watchdog::try_new(p.WDT, wdt_config) {
Ok(x) => x,
Err(_) => {
// Watchdog already active with the wrong number of handles, waiting for it to timeout...
loop {
cortex_m::asm::wfe();
}
}
};
let nvmc = Nvmc::new(p.NVMC);
let nvmc = Mutex::new(BlockingAsync::new(nvmc));
let config = FirmwareUpdaterConfig::from_linkerfile(&nvmc);
let mut updater = FirmwareUpdater::new(config);
loop {
led.set_low();
button.wait_for_any_edge().await;
if button.is_low() {
let mut offset = 0;
let mut magic = [0; 4];
for chunk in APP_B.chunks(4096) {
let mut buf: [u8; 4096] = [0; 4096];
buf[..chunk.len()].copy_from_slice(chunk);
updater.write_firmware(offset, &buf, &mut nvmc, 4096).await.unwrap();
updater.write_firmware(&mut magic, offset, &buf).await.unwrap();
offset += chunk.len();
}
updater.update(&mut nvmc).await.unwrap();
updater.mark_updated(&mut magic).await.unwrap();
led.set_high();
cortex_m::peripheral::SCB::sys_reset();
}

View File

@ -1,7 +1,6 @@
#![no_std]
#![no_main]
#![macro_use]
#![feature(generic_associated_types)]
#![feature(type_alias_impl_trait)]
use embassy_executor::Spawner;
@ -13,7 +12,10 @@ use panic_reset as _;
async fn main(_spawner: Spawner) {
let p = embassy_nrf::init(Default::default());
let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard);
//let mut led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard);
// let mut led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard);
// nRF91 DK
// let mut led = Output::new(p.P0_02, Level::Low, OutputDrive::Standard);
loop {
led.set_high();

View File

@ -0,0 +1,12 @@
[unstable]
build-std = ["core"]
build-std-features = ["panic_immediate_abort"]
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
runner = "probe-rs run --chip RP2040"
[build]
target = "thumbv6m-none-eabi"
[env]
DEFMT_LOG = "trace"

View File

@ -0,0 +1,35 @@
[package]
edition = "2021"
name = "embassy-boot-rp-examples"
version = "0.1.0"
license = "MIT OR Apache-2.0"
[dependencies]
embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] }
embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly"] }
embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", "unstable-traits", "nightly"] }
embassy-boot-rp = { version = "0.1.0", path = "../../../../embassy-boot/rp", features = ["nightly"] }
embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
defmt = "0.3"
defmt-rtt = "0.4"
panic-probe = { version = "0.3", features = ["print-defmt"], optional = true }
panic-reset = { version = "0.1.1", optional = true }
embedded-hal = { version = "0.2.6" }
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
cortex-m-rt = "0.7.0"
embedded-storage = "0.3.0"
[features]
default = ["panic-reset"]
debug = [
"embassy-rp/defmt",
"embassy-boot-rp/defmt",
"panic-probe"
]
skip-include = []
[profile.release]
debug = true

View File

@ -0,0 +1,28 @@
# Examples using bootloader
Example for Raspberry Pi Pico demonstrating the bootloader. The example consists of application binaries, 'a'
which waits for 5 seconds before flashing the 'b' binary, which blinks the LED.
NOTE: The 'b' binary does not mark the new binary as active, so if you reset the device, it will roll back to the 'a' binary before automatically updating it again.
## Prerequisites
* `cargo-binutils`
* `cargo-flash`
* `embassy-boot-rp`
## Usage
```
# Flash bootloader
cargo flash --manifest-path ../../bootloader/rp/Cargo.toml --release --chip RP2040
# Build 'b'
cargo build --release --bin b
# Generate binary for 'b'
cargo objcopy --release --bin b -- -O binary b.bin
# Flash `a` (which includes b.bin)
cargo flash --release --bin a --chip RP2040
```

View File

@ -0,0 +1,15 @@
MEMORY
{
/* NOTE 1 K = 1 KiBi = 1024 bytes */
BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
BOOTLOADER_STATE : ORIGIN = 0x10006000, LENGTH = 4K
FLASH : ORIGIN = 0x10007000, LENGTH = 512K
DFU : ORIGIN = 0x10087000, LENGTH = 516K
RAM : ORIGIN = 0x20000000, LENGTH = 256K
}
__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(BOOT2);
__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - ORIGIN(BOOT2);
__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(BOOT2);
__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(BOOT2);

View File

@ -0,0 +1,67 @@
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use core::cell::RefCell;
use defmt_rtt as _;
use embassy_boot_rp::*;
use embassy_executor::Spawner;
use embassy_rp::flash::Flash;
use embassy_rp::gpio::{Level, Output};
use embassy_rp::watchdog::Watchdog;
use embassy_sync::blocking_mutex::Mutex;
use embassy_time::{Duration, Timer};
use embedded_storage::nor_flash::NorFlash;
#[cfg(feature = "panic-probe")]
use panic_probe as _;
#[cfg(feature = "panic-reset")]
use panic_reset as _;
#[cfg(feature = "skip-include")]
static APP_B: &[u8] = &[0, 1, 2, 3];
#[cfg(not(feature = "skip-include"))]
static APP_B: &[u8] = include_bytes!("../../b.bin");
const FLASH_SIZE: usize = 2 * 1024 * 1024;
#[embassy_executor::main]
async fn main(_s: Spawner) {
let p = embassy_rp::init(Default::default());
let mut led = Output::new(p.PIN_25, Level::Low);
// Override bootloader watchdog
let mut watchdog = Watchdog::new(p.WATCHDOG);
watchdog.start(Duration::from_secs(8));
let flash: Flash<_, FLASH_SIZE> = Flash::new(p.FLASH);
let flash = Mutex::new(RefCell::new(flash));
let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash);
let mut updater = BlockingFirmwareUpdater::new(config);
Timer::after(Duration::from_secs(5)).await;
watchdog.feed();
led.set_high();
let mut offset = 0;
let mut buf: AlignedBuffer<4096> = AlignedBuffer([0; 4096]);
defmt::info!("preparing update");
let writer = updater
.prepare_update(&mut buf.0[..1])
.map_err(|e| defmt::warn!("E: {:?}", defmt::Debug2Format(&e)))
.unwrap();
defmt::info!("writer created, starting write");
for chunk in APP_B.chunks(4096) {
buf.0[..chunk.len()].copy_from_slice(chunk);
defmt::info!("writing block at offset {}", offset);
writer.write(offset, &buf.0[..]).unwrap();
offset += chunk.len() as u32;
}
watchdog.feed();
defmt::info!("firmware written, marking update");
updater.mark_updated(&mut buf.0[..1]).unwrap();
Timer::after(Duration::from_secs(2)).await;
led.set_low();
defmt::info!("update marked, resetting");
cortex_m::peripheral::SCB::sys_reset();
}

View File

@ -0,0 +1,23 @@
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use embassy_executor::Spawner;
use embassy_rp::gpio;
use embassy_time::{Duration, Timer};
use gpio::{Level, Output};
use {defmt_rtt as _, panic_reset as _};
#[embassy_executor::main]
async fn main(_s: Spawner) {
let p = embassy_rp::init(Default::default());
let mut led = Output::new(p.PIN_25, Level::Low);
loop {
led.set_high();
Timer::after(Duration::from_millis(100)).await;
led.set_low();
Timer::after(Duration::from_millis(100)).await;
}
}

View File

@ -1,6 +1,6 @@
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
# replace STM32F429ZITx with your chip as listed in `probe-run --list-chips`
runner = "probe-run --chip STM32F303VCTx"
# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
runner = "probe-rs run --chip STM32F303VCTx"
[build]
target = "thumbv7em-none-eabihf"

View File

@ -2,21 +2,22 @@
edition = "2021"
name = "embassy-boot-stm32f3-examples"
version = "0.1.0"
license = "MIT OR Apache-2.0"
[dependencies]
embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-32768hz"] }
embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32f303re", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
defmt = { version = "0.3", optional = true }
defmt-rtt = { version = "0.3", optional = true }
defmt-rtt = { version = "0.4", optional = true }
panic-reset = { version = "0.1.1" }
embedded-hal = { version = "0.2.6" }
cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
cortex-m-rt = "0.7.0"
[features]
@ -25,3 +26,4 @@ defmt = [
"embassy-stm32/defmt",
"embassy-boot-stm32/defmt",
]
skip-include = []

View File

@ -4,21 +4,25 @@
#[cfg(feature = "defmt-rtt")]
use defmt_rtt::*;
use embassy_boot_stm32::FirmwareUpdater;
use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig};
use embassy_embedded_hal::adapter::BlockingAsync;
use embassy_executor::Spawner;
use embassy_stm32::exti::ExtiInput;
use embassy_stm32::flash::Flash;
use embassy_stm32::flash::{Flash, WRITE_SIZE};
use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
use embassy_sync::mutex::Mutex;
use panic_reset as _;
#[cfg(feature = "skip-include")]
static APP_B: &[u8] = &[0, 1, 2, 3];
#[cfg(not(feature = "skip-include"))]
static APP_B: &[u8] = include_bytes!("../../b.bin");
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(Default::default());
let flash = Flash::unlock(p.FLASH);
let mut flash = BlockingAsync::new(flash);
let flash = Flash::new_blocking(p.FLASH);
let flash = Mutex::new(BlockingAsync::new(flash));
let button = Input::new(p.PC13, Pull::Up);
let mut button = ExtiInput::new(button, p.EXTI13);
@ -26,16 +30,18 @@ async fn main(_spawner: Spawner) {
let mut led = Output::new(p.PA5, Level::Low, Speed::Low);
led.set_high();
let mut updater = FirmwareUpdater::default();
let config = FirmwareUpdaterConfig::from_linkerfile(&flash);
let mut updater = FirmwareUpdater::new(config);
button.wait_for_falling_edge().await;
let mut offset = 0;
let mut magic = AlignedBuffer([0; WRITE_SIZE]);
for chunk in APP_B.chunks(2048) {
let mut buf: [u8; 2048] = [0; 2048];
buf[..chunk.len()].copy_from_slice(chunk);
updater.write_firmware(offset, &buf, &mut flash, 2048).await.unwrap();
updater.write_firmware(magic.as_mut(), offset, &buf).await.unwrap();
offset += chunk.len();
}
updater.update(&mut flash).await.unwrap();
updater.mark_updated(magic.as_mut()).await.unwrap();
led.set_low();
cortex_m::peripheral::SCB::sys_reset();
}

View File

@ -1,6 +1,6 @@
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
# replace STM32F429ZITx with your chip as listed in `probe-run --list-chips`
runner = "probe-run --chip STM32F767ZITx -v"
# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
runner = "probe-rs run --chip STM32F767ZITx"
[build]
target = "thumbv7em-none-eabihf"

View File

@ -2,21 +2,23 @@
edition = "2021"
name = "embassy-boot-stm32f7-examples"
version = "0.1.0"
license = "MIT OR Apache-2.0"
[dependencies]
embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-32768hz"] }
embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32f767zi", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
defmt = { version = "0.3", optional = true }
defmt-rtt = { version = "0.3", optional = true }
defmt-rtt = { version = "0.4", optional = true }
panic-reset = { version = "0.1.1" }
embedded-hal = { version = "0.2.6" }
embedded-storage = "0.3.0"
cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
cortex-m-rt = "0.7.0"
[features]
@ -25,3 +27,4 @@ defmt = [
"embassy-stm32/defmt",
"embassy-boot-stm32/defmt",
]
skip-include = []

View File

@ -2,23 +2,29 @@
#![no_main]
#![feature(type_alias_impl_trait)]
use core::cell::RefCell;
#[cfg(feature = "defmt-rtt")]
use defmt_rtt::*;
use embassy_boot_stm32::FirmwareUpdater;
use embassy_embedded_hal::adapter::BlockingAsync;
use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterConfig};
use embassy_executor::Spawner;
use embassy_stm32::exti::ExtiInput;
use embassy_stm32::flash::Flash;
use embassy_stm32::flash::{Flash, WRITE_SIZE};
use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
use embassy_sync::blocking_mutex::Mutex;
use embedded_storage::nor_flash::NorFlash;
use panic_reset as _;
#[cfg(feature = "skip-include")]
static APP_B: &[u8] = &[0, 1, 2, 3];
#[cfg(not(feature = "skip-include"))]
static APP_B: &[u8] = include_bytes!("../../b.bin");
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(Default::default());
let flash = Flash::unlock(p.FLASH);
let mut flash = BlockingAsync::new(flash);
let flash = Flash::new_blocking(p.FLASH);
let flash = Mutex::new(RefCell::new(flash));
let button = Input::new(p.PC13, Pull::Down);
let mut button = ExtiInput::new(button, p.EXTI13);
@ -26,16 +32,19 @@ async fn main(_spawner: Spawner) {
let mut led = Output::new(p.PB7, Level::Low, Speed::Low);
led.set_high();
let mut updater = FirmwareUpdater::default();
let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash);
let mut updater = BlockingFirmwareUpdater::new(config);
let mut magic = AlignedBuffer([0; WRITE_SIZE]);
let writer = updater.prepare_update(magic.as_mut()).unwrap();
button.wait_for_rising_edge().await;
let mut offset = 0;
let mut buf: [u8; 256 * 1024] = [0; 256 * 1024];
for chunk in APP_B.chunks(256 * 1024) {
buf[..chunk.len()].copy_from_slice(chunk);
updater.write_firmware(offset, &buf, &mut flash, 2048).await.unwrap();
offset += chunk.len();
let mut buf = AlignedBuffer([0; 4096]);
for chunk in APP_B.chunks(4096) {
buf.as_mut()[..chunk.len()].copy_from_slice(chunk);
writer.write(offset, buf.as_ref()).unwrap();
offset += chunk.len() as u32;
}
updater.update(&mut flash).await.unwrap();
updater.mark_updated(magic.as_mut()).unwrap();
led.set_low();
cortex_m::peripheral::SCB::sys_reset();
}

View File

@ -1,6 +1,6 @@
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
# replace STM32F429ZITx with your chip as listed in `probe-run --list-chips`
runner = "probe-run --chip STM32H743ZITx"
# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
runner = "probe-rs run --chip STM32H743ZITx"
[build]
target = "thumbv7em-none-eabihf"

View File

@ -2,21 +2,23 @@
edition = "2021"
name = "embassy-boot-stm32h7-examples"
version = "0.1.0"
license = "MIT OR Apache-2.0"
[dependencies]
embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-32768hz"] }
embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32h743zi", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
defmt = { version = "0.3", optional = true }
defmt-rtt = { version = "0.3", optional = true }
defmt-rtt = { version = "0.4", optional = true }
panic-reset = { version = "0.1.1" }
embedded-hal = { version = "0.2.6" }
embedded-storage = "0.3.0"
cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
cortex-m-rt = "0.7.0"
[features]
@ -25,3 +27,4 @@ defmt = [
"embassy-stm32/defmt",
"embassy-boot-stm32/defmt",
]
skip-include = []

View File

@ -1,8 +1,9 @@
#!/bin/bash
probe-rs erase --chip STM32H743ZITx
mv ../../bootloader/stm32/memory.x ../../bootloader/stm32/memory-old.x
cp memory-bl.x ../../bootloader/stm32/memory.x
cargo flash --manifest-path ../../bootloader/stm32/Cargo.toml --release --features embassy-stm32/stm32f767zi --chip STM32F767ZITx --target thumbv7em-none-eabihf
cargo flash --manifest-path ../../bootloader/stm32/Cargo.toml --release --features embassy-stm32/stm32h743zi --chip STM32H743ZITx --target thumbv7em-none-eabihf
rm ../../bootloader/stm32/memory.x
mv ../../bootloader/stm32/memory-old.x ../../bootloader/stm32/memory.x

View File

@ -2,23 +2,29 @@
#![no_main]
#![feature(type_alias_impl_trait)]
use core::cell::RefCell;
#[cfg(feature = "defmt-rtt")]
use defmt_rtt::*;
use embassy_boot_stm32::FirmwareUpdater;
use embassy_embedded_hal::adapter::BlockingAsync;
use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterConfig};
use embassy_executor::Spawner;
use embassy_stm32::exti::ExtiInput;
use embassy_stm32::flash::Flash;
use embassy_stm32::flash::{Flash, WRITE_SIZE};
use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
use embassy_sync::blocking_mutex::Mutex;
use embedded_storage::nor_flash::NorFlash;
use panic_reset as _;
#[cfg(feature = "skip-include")]
static APP_B: &[u8] = &[0, 1, 2, 3];
#[cfg(not(feature = "skip-include"))]
static APP_B: &[u8] = include_bytes!("../../b.bin");
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(Default::default());
let flash = Flash::unlock(p.FLASH);
let mut flash = BlockingAsync::new(flash);
let flash = Flash::new_blocking(p.FLASH);
let flash = Mutex::new(RefCell::new(flash));
let button = Input::new(p.PC13, Pull::Down);
let mut button = ExtiInput::new(button, p.EXTI13);
@ -26,16 +32,19 @@ async fn main(_spawner: Spawner) {
let mut led = Output::new(p.PB14, Level::Low, Speed::Low);
led.set_high();
let mut updater = FirmwareUpdater::default();
let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash);
let mut magic = AlignedBuffer([0; WRITE_SIZE]);
let mut updater = BlockingFirmwareUpdater::new(config);
let writer = updater.prepare_update(magic.as_mut()).unwrap();
button.wait_for_rising_edge().await;
let mut offset = 0;
let mut buf: [u8; 128 * 1024] = [0; 128 * 1024];
for chunk in APP_B.chunks(128 * 1024) {
buf[..chunk.len()].copy_from_slice(chunk);
updater.write_firmware(offset, &buf, &mut flash, 2048).await.unwrap();
offset += chunk.len();
let mut buf = AlignedBuffer([0; 4096]);
for chunk in APP_B.chunks(4096) {
buf.as_mut()[..chunk.len()].copy_from_slice(chunk);
writer.write(offset, buf.as_ref()).unwrap();
offset += chunk.len() as u32;
}
updater.update(&mut flash).await.unwrap();
updater.mark_updated(magic.as_mut()).unwrap();
led.set_low();
cortex_m::peripheral::SCB::sys_reset();
}

View File

@ -1,6 +1,6 @@
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
# replace your chip as listed in `probe-run --list-chips`
runner = "probe-run --chip STM32L072CZTx"
# replace your chip as listed in `probe-rs chip list`
runner = "probe-rs run --chip STM32L072CZTx"
[build]
target = "thumbv6m-none-eabi"

View File

@ -2,21 +2,22 @@
edition = "2021"
name = "embassy-boot-stm32l0-examples"
version = "0.1.0"
license = "MIT OR Apache-2.0"
[dependencies]
embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-32768hz"] }
embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l072cz", "time-driver-any", "exti", "memory-x"] }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
defmt = { version = "0.3", optional = true }
defmt-rtt = { version = "0.3", optional = true }
defmt-rtt = { version = "0.4", optional = true }
panic-reset = { version = "0.1.1" }
embedded-hal = { version = "0.2.6" }
cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
cortex-m-rt = "0.7.0"
[features]
@ -25,3 +26,4 @@ defmt = [
"embassy-stm32/defmt",
"embassy-boot-stm32/defmt",
]
skip-include = []

View File

@ -4,22 +4,26 @@
#[cfg(feature = "defmt-rtt")]
use defmt_rtt::*;
use embassy_boot_stm32::FirmwareUpdater;
use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig};
use embassy_embedded_hal::adapter::BlockingAsync;
use embassy_executor::Spawner;
use embassy_stm32::exti::ExtiInput;
use embassy_stm32::flash::Flash;
use embassy_stm32::flash::{Flash, WRITE_SIZE};
use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
use embassy_sync::mutex::Mutex;
use embassy_time::{Duration, Timer};
use panic_reset as _;
#[cfg(feature = "skip-include")]
static APP_B: &[u8] = &[0, 1, 2, 3];
#[cfg(not(feature = "skip-include"))]
static APP_B: &[u8] = include_bytes!("../../b.bin");
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(Default::default());
let flash = Flash::unlock(p.FLASH);
let mut flash = BlockingAsync::new(flash);
let flash = Flash::new_blocking(p.FLASH);
let flash = Mutex::new(BlockingAsync::new(flash));
let button = Input::new(p.PB2, Pull::Up);
let mut button = ExtiInput::new(button, p.EXTI2);
@ -28,17 +32,19 @@ async fn main(_spawner: Spawner) {
led.set_high();
let mut updater = FirmwareUpdater::default();
let config = FirmwareUpdaterConfig::from_linkerfile(&flash);
let mut updater = FirmwareUpdater::new(config);
button.wait_for_falling_edge().await;
let mut offset = 0;
let mut magic = AlignedBuffer([0; WRITE_SIZE]);
for chunk in APP_B.chunks(128) {
let mut buf: [u8; 128] = [0; 128];
buf[..chunk.len()].copy_from_slice(chunk);
updater.write_firmware(offset, &buf, &mut flash, 128).await.unwrap();
updater.write_firmware(magic.as_mut(), offset, &buf).await.unwrap();
offset += chunk.len();
}
updater.update(&mut flash).await.unwrap();
updater.mark_updated(magic.as_mut()).await.unwrap();
led.set_low();
Timer::after(Duration::from_secs(1)).await;
cortex_m::peripheral::SCB::sys_reset();

View File

@ -1,6 +1,6 @@
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
# replace your chip as listed in `probe-run --list-chips`
runner = "probe-run --chip STM32L151CBxxA"
# replace your chip as listed in `probe-rs chip list`
runner = "probe-rs run --chip STM32L151CBxxA"
[build]
target = "thumbv7m-none-eabi"

View File

@ -2,21 +2,22 @@
edition = "2021"
name = "embassy-boot-stm32l1-examples"
version = "0.1.0"
license = "MIT OR Apache-2.0"
[dependencies]
embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-32768hz"] }
embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l151cb-a", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
defmt = { version = "0.3", optional = true }
defmt-rtt = { version = "0.3", optional = true }
defmt-rtt = { version = "0.4", optional = true }
panic-reset = { version = "0.1.1" }
embedded-hal = { version = "0.2.6" }
cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
cortex-m-rt = "0.7.0"
[features]
@ -25,3 +26,4 @@ defmt = [
"embassy-stm32/defmt",
"embassy-boot-stm32/defmt",
]
skip-include = []

View File

@ -4,22 +4,26 @@
#[cfg(feature = "defmt-rtt")]
use defmt_rtt::*;
use embassy_boot_stm32::FirmwareUpdater;
use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig};
use embassy_embedded_hal::adapter::BlockingAsync;
use embassy_executor::Spawner;
use embassy_stm32::exti::ExtiInput;
use embassy_stm32::flash::Flash;
use embassy_stm32::flash::{Flash, WRITE_SIZE};
use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
use embassy_sync::mutex::Mutex;
use embassy_time::{Duration, Timer};
use panic_reset as _;
#[cfg(feature = "skip-include")]
static APP_B: &[u8] = &[0, 1, 2, 3];
#[cfg(not(feature = "skip-include"))]
static APP_B: &[u8] = include_bytes!("../../b.bin");
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(Default::default());
let flash = Flash::unlock(p.FLASH);
let mut flash = BlockingAsync::new(flash);
let flash = Flash::new_blocking(p.FLASH);
let flash = Mutex::new(BlockingAsync::new(flash));
let button = Input::new(p.PB2, Pull::Up);
let mut button = ExtiInput::new(button, p.EXTI2);
@ -28,17 +32,19 @@ async fn main(_spawner: Spawner) {
led.set_high();
let mut updater = FirmwareUpdater::default();
let config = FirmwareUpdaterConfig::from_linkerfile(&flash);
let mut updater = FirmwareUpdater::new(config);
button.wait_for_falling_edge().await;
let mut magic = AlignedBuffer([0; WRITE_SIZE]);
let mut offset = 0;
for chunk in APP_B.chunks(128) {
let mut buf: [u8; 128] = [0; 128];
buf[..chunk.len()].copy_from_slice(chunk);
updater.write_firmware(offset, &buf, &mut flash, 128).await.unwrap();
updater.write_firmware(magic.as_mut(), offset, &buf).await.unwrap();
offset += chunk.len();
}
updater.update(&mut flash).await.unwrap();
updater.mark_updated(magic.as_mut()).await.unwrap();
led.set_low();
Timer::after(Duration::from_secs(1)).await;
cortex_m::peripheral::SCB::sys_reset();

View File

@ -1,6 +1,6 @@
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
# replace your chip as listed in `probe-run --list-chips`
runner = "probe-run --chip STM32L475VG"
# replace your chip as listed in `probe-rs chip list`
runner = "probe-rs run --chip STM32L475VG"
[build]
target = "thumbv7em-none-eabihf"

View File

@ -2,21 +2,22 @@
edition = "2021"
name = "embassy-boot-stm32l4-examples"
version = "0.1.0"
license = "MIT OR Apache-2.0"
[dependencies]
embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-32768hz"] }
embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l475vg", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
defmt = { version = "0.3", optional = true }
defmt-rtt = { version = "0.3", optional = true }
defmt-rtt = { version = "0.4", optional = true }
panic-reset = { version = "0.1.1" }
embedded-hal = { version = "0.2.6" }
cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
cortex-m-rt = "0.7.0"
[features]
@ -25,3 +26,4 @@ defmt = [
"embassy-stm32/defmt",
"embassy-boot-stm32/defmt",
]
skip-include = []

View File

@ -4,21 +4,25 @@
#[cfg(feature = "defmt-rtt")]
use defmt_rtt::*;
use embassy_boot_stm32::FirmwareUpdater;
use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig};
use embassy_embedded_hal::adapter::BlockingAsync;
use embassy_executor::Spawner;
use embassy_stm32::exti::ExtiInput;
use embassy_stm32::flash::Flash;
use embassy_stm32::flash::{Flash, WRITE_SIZE};
use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
use embassy_sync::mutex::Mutex;
use panic_reset as _;
#[cfg(feature = "skip-include")]
static APP_B: &[u8] = &[0, 1, 2, 3];
#[cfg(not(feature = "skip-include"))]
static APP_B: &[u8] = include_bytes!("../../b.bin");
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(Default::default());
let flash = Flash::unlock(p.FLASH);
let mut flash = BlockingAsync::new(flash);
let flash = Flash::new_blocking(p.FLASH);
let flash = Mutex::new(BlockingAsync::new(flash));
let button = Input::new(p.PC13, Pull::Up);
let mut button = ExtiInput::new(button, p.EXTI13);
@ -26,16 +30,18 @@ async fn main(_spawner: Spawner) {
let mut led = Output::new(p.PB14, Level::Low, Speed::Low);
led.set_high();
let mut updater = FirmwareUpdater::default();
let config = FirmwareUpdaterConfig::from_linkerfile(&flash);
let mut updater = FirmwareUpdater::new(config);
button.wait_for_falling_edge().await;
let mut magic = AlignedBuffer([0; WRITE_SIZE]);
let mut offset = 0;
for chunk in APP_B.chunks(2048) {
let mut buf: [u8; 2048] = [0; 2048];
buf[..chunk.len()].copy_from_slice(chunk);
updater.write_firmware(offset, &buf, &mut flash, 2048).await.unwrap();
updater.write_firmware(magic.as_mut(), offset, &buf).await.unwrap();
offset += chunk.len();
}
updater.update(&mut flash).await.unwrap();
updater.mark_updated(magic.as_mut()).await.unwrap();
led.set_low();
cortex_m::peripheral::SCB::sys_reset();
}

View File

@ -1,6 +1,6 @@
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
# replace your chip as listed in `probe-run --list-chips`
runner = "probe-run --chip STM32WLE5JCIx"
# replace your chip as listed in `probe-rs chip list`
runner = "probe-rs run --chip STM32WLE5JCIx"
[build]
target = "thumbv7em-none-eabihf"

View File

@ -2,21 +2,22 @@
edition = "2021"
name = "embassy-boot-stm32wl-examples"
version = "0.1.0"
license = "MIT OR Apache-2.0"
[dependencies]
embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-32768hz"] }
embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32wl55jc-cm4", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
defmt = { version = "0.3", optional = true }
defmt-rtt = { version = "0.3", optional = true }
defmt-rtt = { version = "0.4", optional = true }
panic-reset = { version = "0.1.1" }
embedded-hal = { version = "0.2.6" }
cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
cortex-m-rt = "0.7.0"
[features]
@ -25,3 +26,4 @@ defmt = [
"embassy-stm32/defmt",
"embassy-boot-stm32/defmt",
]
skip-include = []

View File

@ -4,21 +4,25 @@
#[cfg(feature = "defmt-rtt")]
use defmt_rtt::*;
use embassy_boot_stm32::FirmwareUpdater;
use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig};
use embassy_embedded_hal::adapter::BlockingAsync;
use embassy_executor::Spawner;
use embassy_stm32::exti::ExtiInput;
use embassy_stm32::flash::Flash;
use embassy_stm32::flash::{Flash, WRITE_SIZE};
use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
use embassy_sync::mutex::Mutex;
use panic_reset as _;
#[cfg(feature = "skip-include")]
static APP_B: &[u8] = &[0, 1, 2, 3];
#[cfg(not(feature = "skip-include"))]
static APP_B: &[u8] = include_bytes!("../../b.bin");
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(Default::default());
let flash = Flash::unlock(p.FLASH);
let mut flash = BlockingAsync::new(flash);
let flash = Flash::new_blocking(p.FLASH);
let flash = Mutex::new(BlockingAsync::new(flash));
let button = Input::new(p.PA0, Pull::Up);
let mut button = ExtiInput::new(button, p.EXTI0);
@ -26,18 +30,20 @@ async fn main(_spawner: Spawner) {
let mut led = Output::new(p.PB9, Level::Low, Speed::Low);
led.set_high();
let mut updater = FirmwareUpdater::default();
let config = FirmwareUpdaterConfig::from_linkerfile(&flash);
let mut updater = FirmwareUpdater::new(config);
button.wait_for_falling_edge().await;
//defmt::info!("Starting update");
let mut magic = AlignedBuffer([0; WRITE_SIZE]);
let mut offset = 0;
for chunk in APP_B.chunks(2048) {
let mut buf: [u8; 2048] = [0; 2048];
buf[..chunk.len()].copy_from_slice(chunk);
// defmt::info!("Writing chunk at 0x{:x}", offset);
updater.write_firmware(offset, &buf, &mut flash, 2048).await.unwrap();
updater.write_firmware(magic.as_mut(), offset, &buf).await.unwrap();
offset += chunk.len();
}
updater.update(&mut flash).await.unwrap();
updater.mark_updated(magic.as_mut()).await.unwrap();
//defmt::info!("Marked as updated");
led.set_low();
cortex_m::peripheral::SCB::sys_reset();

View File

@ -4,7 +4,7 @@ build-std-features = ["panic_immediate_abort"]
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
#runner = "./fruitrunner"
runner = "probe-run --chip nrf52840_xxAA"
runner = "probe-rs run --chip nrf52840_xxAA"
rustflags = [
# Code-size optimizations.

View File

@ -3,14 +3,16 @@ edition = "2021"
name = "nrf-bootloader-example"
version = "0.1.0"
description = "Bootloader for nRF chips"
license = "MIT OR Apache-2.0"
[dependencies]
defmt = { version = "0.3", optional = true }
defmt-rtt = { version = "0.3", optional = true }
defmt-rtt = { version = "0.4", optional = true }
embassy-nrf = { path = "../../../../embassy-nrf", default-features = false, features = ["nightly"] }
embassy-boot-nrf = { path = "../../../../embassy-boot/nrf", default-features = false }
cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
embassy-nrf = { path = "../../../../embassy-nrf", features = ["nightly"] }
embassy-boot-nrf = { path = "../../../../embassy-boot/nrf" }
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
embassy-sync = { path = "../../../../embassy-sync" }
cortex-m-rt = { version = "0.7" }
cfg-if = "1.0.0"

View File

@ -5,7 +5,7 @@ MEMORY
BOOTLOADER_STATE : ORIGIN = 0x00006000, LENGTH = 4K
ACTIVE : ORIGIN = 0x00007000, LENGTH = 64K
DFU : ORIGIN = 0x00017000, LENGTH = 68K
RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 32K
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
}
__bootloader_state_start = ORIGIN(BOOTLOADER_STATE);

View File

@ -5,7 +5,7 @@ MEMORY
BOOTLOADER_STATE : ORIGIN = 0x00006000, LENGTH = 4K
ACTIVE : ORIGIN = 0x00007000, LENGTH = 64K
DFU : ORIGIN = 0x00017000, LENGTH = 68K
RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 32K
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
}
__bootloader_state_start = ORIGIN(BOOTLOADER_STATE);

View File

@ -1,11 +1,15 @@
#![no_std]
#![no_main]
use core::cell::RefCell;
use cortex_m_rt::{entry, exception};
#[cfg(feature = "defmt")]
use defmt_rtt as _;
use embassy_boot_nrf::*;
use embassy_nrf::nvmc::Nvmc;
use embassy_nrf::wdt;
use embassy_sync::blocking_mutex::Mutex;
#[entry]
fn main() -> ! {
@ -19,13 +23,21 @@ fn main() -> ! {
}
*/
let mut bl = BootLoader::default();
let start = bl.prepare(&mut SingleFlashProvider::new(&mut WatchdogFlash::start(
Nvmc::new(p.NVMC),
p.WDT,
5,
)));
unsafe { bl.load(start) }
let mut wdt_config = wdt::Config::default();
wdt_config.timeout_ticks = 32768 * 5; // timeout seconds
wdt_config.run_during_sleep = true;
wdt_config.run_during_debug_halt = false;
let flash = WatchdogFlash::start(Nvmc::new(p.NVMC), p.WDT, wdt_config);
let flash = Mutex::new(RefCell::new(flash));
let config = BootLoaderConfig::from_linkerfile_blocking(&flash);
let active_offset = config.active.offset();
let mut bl: BootLoader<_, _, _> = BootLoader::new(config);
bl.prepare();
unsafe { bl.load(active_offset) }
}
#[no_mangle]

View File

@ -0,0 +1,8 @@
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
runner = "probe-rs run --chip RP2040"
[build]
target = "thumbv6m-none-eabi"
[env]
DEFMT_LOG = "trace"

View File

@ -0,0 +1,33 @@
[package]
edition = "2021"
name = "rp-bootloader-example"
version = "0.1.0"
description = "Example bootloader for RP2040 chips"
license = "MIT OR Apache-2.0"
[dependencies]
defmt = { version = "0.3", optional = true }
defmt-rtt = { version = "0.4", optional = true }
embassy-rp = { path = "../../../../embassy-rp", features = ["nightly"] }
embassy-boot-rp = { path = "../../../../embassy-boot/rp" }
embassy-sync = { path = "../../../../embassy-sync" }
embassy-time = { path = "../../../../embassy-time", features = ["nightly"] }
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
cortex-m-rt = { version = "0.7" }
embedded-storage = "0.3.0"
embedded-storage-async = "0.4.0"
cfg-if = "1.0.0"
[features]
defmt = [
"dep:defmt",
"embassy-boot-rp/defmt",
"embassy-rp/defmt",
]
debug = ["defmt-rtt", "defmt"]
[profile.release]
debug = true
opt-level = 's'

View File

@ -0,0 +1,17 @@
# Bootloader for RP2040
The bootloader uses `embassy-boot` to interact with the flash.
# Usage
Flashing the bootloader
```
cargo flash --release --chip RP2040
```
To debug, use `cargo run` and enable the debug feature flag
``` rust
cargo run --release --features debug
```

View File

@ -0,0 +1,28 @@
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=-Tlink-rp.x");
if env::var("CARGO_FEATURE_DEFMT").is_ok() {
println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
}
}

View File

@ -0,0 +1,19 @@
MEMORY
{
/* NOTE 1 K = 1 KiBi = 1024 bytes */
BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
FLASH : ORIGIN = 0x10000100, LENGTH = 24K
BOOTLOADER_STATE : ORIGIN = 0x10006000, LENGTH = 4K
ACTIVE : ORIGIN = 0x10007000, LENGTH = 512K
DFU : ORIGIN = 0x10087000, LENGTH = 516K
RAM : ORIGIN = 0x20000000, LENGTH = 256K
}
__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(BOOT2);
__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - ORIGIN(BOOT2);
__bootloader_active_start = ORIGIN(ACTIVE) - ORIGIN(BOOT2);
__bootloader_active_end = ORIGIN(ACTIVE) + LENGTH(ACTIVE) - ORIGIN(BOOT2);
__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(BOOT2);
__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(BOOT2);

View File

@ -0,0 +1,56 @@
#![no_std]
#![no_main]
use core::cell::RefCell;
use cortex_m_rt::{entry, exception};
#[cfg(feature = "defmt")]
use defmt_rtt as _;
use embassy_boot_rp::*;
use embassy_sync::blocking_mutex::Mutex;
use embassy_time::Duration;
const FLASH_SIZE: usize = 2 * 1024 * 1024;
#[entry]
fn main() -> ! {
let p = embassy_rp::init(Default::default());
// Uncomment this if you are debugging the bootloader with debugger/RTT attached,
// as it prevents a hard fault when accessing flash 'too early' after boot.
/*
for i in 0..10000000 {
cortex_m::asm::nop();
}
*/
let flash = WatchdogFlash::<FLASH_SIZE>::start(p.FLASH, p.WATCHDOG, Duration::from_secs(8));
let flash = Mutex::new(RefCell::new(flash));
let config = BootLoaderConfig::from_linkerfile_blocking(&flash);
let active_offset = config.active.offset();
let mut bl: BootLoader<_, _, _> = BootLoader::new(config);
bl.prepare();
unsafe { bl.load(embassy_rp::flash::FLASH_BASE as u32 + active_offset) }
}
#[no_mangle]
#[cfg_attr(target_os = "none", link_section = ".HardFault.user")]
unsafe extern "C" fn HardFault() {
cortex_m::peripheral::SCB::sys_reset();
}
#[exception]
unsafe fn DefaultHandler(_: i16) -> ! {
const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32;
let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16;
panic!("DefaultHandler #{:?}", irqn);
}
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
cortex_m::asm::udf();
}

View File

@ -3,17 +3,19 @@ edition = "2021"
name = "stm32-bootloader-example"
version = "0.1.0"
description = "Example bootloader for STM32 chips"
license = "MIT OR Apache-2.0"
[dependencies]
defmt = { version = "0.3", optional = true }
defmt-rtt = { version = "0.3", optional = true }
defmt-rtt = { version = "0.4", optional = true }
embassy-stm32 = { path = "../../../../embassy-stm32", default-features = false, features = ["nightly"] }
embassy-boot-stm32 = { path = "../../../../embassy-boot/stm32", default-features = false }
cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
embassy-stm32 = { path = "../../../../embassy-stm32", features = ["nightly"] }
embassy-boot-stm32 = { path = "../../../../embassy-boot/stm32" }
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
embassy-sync = { path = "../../../../embassy-sync" }
cortex-m-rt = { version = "0.7" }
embedded-storage = "0.3.0"
embedded-storage-async = "0.3.0"
embedded-storage-async = "0.4.0"
cfg-if = "1.0.0"
[features]

View File

@ -1,11 +1,14 @@
#![no_std]
#![no_main]
use core::cell::RefCell;
use cortex_m_rt::{entry, exception};
#[cfg(feature = "defmt")]
use defmt_rtt as _;
use embassy_boot_stm32::*;
use embassy_stm32::flash::{Flash, ERASE_SIZE};
use embassy_stm32::flash::{Flash, BANK1_REGION};
use embassy_sync::blocking_mutex::Mutex;
#[entry]
fn main() -> ! {
@ -19,11 +22,16 @@ fn main() -> ! {
}
*/
let mut bl: BootLoader<ERASE_SIZE> = BootLoader::default();
let mut flash = Flash::unlock(p.FLASH);
let start = bl.prepare(&mut SingleFlashProvider::new(&mut flash));
core::mem::drop(flash);
unsafe { bl.load(start) }
let layout = Flash::new_blocking(p.FLASH).into_blocking_regions();
let flash = Mutex::new(RefCell::new(layout.bank1_region));
let config = BootLoaderConfig::from_linkerfile_blocking(&flash);
let active_offset = config.active.offset();
let mut bl: BootLoader<_, _, _, 2048> = BootLoader::new(config);
bl.prepare();
unsafe { bl.load(BANK1_REGION.base + active_offset) }
}
#[no_mangle]

View File

@ -1,6 +1,6 @@
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
# replace nRF82840_xxAA with your chip as listed in `probe-run --list-chips`
runner = "probe-run --chip nRF52840_xxAA"
# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list`
runner = "probe-rs run --chip nRF52840_xxAA"
[build]
target = "thumbv7em-none-eabi"

View File

@ -2,6 +2,7 @@
edition = "2021"
name = "embassy-nrf-rtos-trace-examples"
version = "0.1.0"
license = "MIT OR Apache-2.0"
[features]
default = ["log", "nightly"]
@ -15,12 +16,12 @@ log = [
]
[dependencies]
embassy-sync = { version = "0.1.0", path = "../../embassy-sync" }
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features=["rtos-trace", "rtos-trace-interrupt", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../embassy-time" }
embassy-sync = { version = "0.2.0", path = "../../embassy-sync" }
embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "rtos-trace-interrupt", "integrated-timers"] }
embassy-time = { version = "0.1.2", path = "../../embassy-time" }
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
cortex-m-rt = "0.7.0"
panic-probe = { version = "0.3" }
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }

View File

@ -2,6 +2,7 @@
#![no_main]
#![feature(type_alias_impl_trait)]
use core::future::poll_fn;
use core::task::Poll;
use embassy_executor::Spawner;
@ -46,7 +47,7 @@ async fn run2() {
#[embassy_executor::task]
async fn run3() {
futures::future::poll_fn(|cx| {
poll_fn(|cx| {
cx.waker().wake_by_ref();
Poll::<()>::Pending
})

View File

@ -1,26 +0,0 @@
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use defmt::info;
use embassy_executor::Spawner;
use embassy_nrf::interrupt;
use embassy_nrf::timer::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 t = Timer::new_awaitable(p.TIMER0, interrupt::take!(TIMER0));
// default frequency is 1MHz, so this triggers every second
t.cc(0).write(1_000_000);
// clear the timer value on cc[0] compare match
t.cc(0).short_compare_clear();
t.start();
loop {
// wait for compare match
t.cc(0).wait().await;
info!("hardware timer tick");
}
}

View File

@ -1,46 +0,0 @@
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use defmt::info;
use embassy_executor::Spawner;
use embassy_nrf::interrupt;
use embassy_nrf::pdm::{Config, Channels, Pdm};
use embassy_time::{Duration, Timer};
use fixed::types::I7F1;
use num_integer::Roots;
use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::main]
async fn main(_p: Spawner) {
let mut p = embassy_nrf::init(Default::default());
let mut config = Config::default();
// Pins are correct for the onboard microphone on the Feather nRF52840 Sense.
config.channels = Channels::Mono;
config.gain_left = I7F1::from_bits(5); // 2.5 dB
let mut pdm = Pdm::new(p.PDM, interrupt::take!(PDM), &mut p.P0_00, &mut p.P0_01, config);
loop {
for gain in [I7F1::from_num(-20), I7F1::from_num(0), I7F1::from_num(20)] {
pdm.set_gain(gain, gain);
info!("Gain = {} dB", defmt::Debug2Format(&gain));
for _ in 0..10 {
let mut buf = [0; 1500];
pdm.sample(5, &mut buf).await;
let mean = (buf.iter().map(|v| i32::from(*v)).sum::<i32>() / buf.len() as i32) as i16;
info!(
"{} samples, min {=i16}, max {=i16}, mean {=i16}, AC RMS {=i16}",
buf.len(),
buf.iter().min().unwrap(),
buf.iter().max().unwrap(),
mean,
(
buf.iter().map(|v| i32::from(*v - mean).pow(2)).fold(0i32, |a,b| a.saturating_add(b))
/ buf.len() as i32).sqrt() as i16,
);
info!("samples = {}", &buf);
Timer::after(Duration::from_millis(100)).await;
}
}
}
}

View File

@ -1,275 +0,0 @@
#![no_std]
#![no_main]
#![feature(generic_associated_types)]
#![feature(type_alias_impl_trait)]
use core::mem;
use core::sync::atomic::{AtomicBool, Ordering};
use core::task::Waker;
use defmt::*;
use embassy_executor::Spawner;
use embassy_net::tcp::TcpSocket;
use embassy_net::{PacketBox, PacketBoxExt, PacketBuf, Stack, StackResources};
use embassy_nrf::rng::Rng;
use embassy_nrf::usb::{Driver, PowerUsb};
use embassy_nrf::{interrupt, pac, peripherals};
use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
use embassy_sync::channel::Channel;
use embassy_usb::{Builder, Config, UsbDevice};
use embassy_usb_ncm::{CdcNcmClass, Receiver, Sender, State};
use embedded_io::asynch::{Read, Write};
use static_cell::StaticCell;
use {defmt_rtt as _, panic_probe as _};
type MyDriver = Driver<'static, peripherals::USBD, PowerUsb>;
macro_rules! singleton {
($val:expr) => {{
type T = impl Sized;
static STATIC_CELL: StaticCell<T> = StaticCell::new();
STATIC_CELL.init_with(move || $val)
}};
}
#[embassy_executor::task]
async fn usb_task(mut device: UsbDevice<'static, MyDriver>) -> ! {
device.run().await
}
#[embassy_executor::task]
async fn usb_ncm_rx_task(mut class: Receiver<'static, MyDriver>) {
loop {
warn!("WAITING for connection");
LINK_UP.store(false, Ordering::Relaxed);
class.wait_connection().await.unwrap();
warn!("Connected");
LINK_UP.store(true, Ordering::Relaxed);
loop {
let mut p = unwrap!(PacketBox::new(embassy_net::Packet::new()));
let n = match class.read_packet(&mut p[..]).await {
Ok(n) => n,
Err(e) => {
warn!("error reading packet: {:?}", e);
break;
}
};
let buf = p.slice(0..n);
if RX_CHANNEL.try_send(buf).is_err() {
warn!("Failed pushing rx'd packet to channel.");
}
}
}
}
#[embassy_executor::task]
async fn usb_ncm_tx_task(mut class: Sender<'static, MyDriver>) {
loop {
let pkt = TX_CHANNEL.recv().await;
if let Err(e) = class.write_packet(&pkt[..]).await {
warn!("Failed to TX packet: {:?}", e);
}
}
}
#[embassy_executor::task]
async fn net_task(stack: &'static Stack<Device>) -> ! {
stack.run().await
}
#[embassy_executor::main]
async fn main(spawner: Spawner) {
let p = embassy_nrf::init(Default::default());
let clock: pac::CLOCK = unsafe { mem::transmute(()) };
info!("Enabling ext hfosc...");
clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
while clock.events_hfclkstarted.read().bits() != 1 {}
// Create the driver, from the HAL.
let irq = interrupt::take!(USBD);
let power_irq = interrupt::take!(POWER_CLOCK);
let driver = Driver::new(p.USBD, irq, PowerUsb::new(power_irq));
// Create embassy-usb Config
let mut config = Config::new(0xc0de, 0xcafe);
config.manufacturer = Some("Embassy");
config.product = Some("USB-Ethernet example");
config.serial_number = Some("12345678");
config.max_power = 100;
config.max_packet_size_0 = 64;
// Required for Windows support.
config.composite_with_iads = true;
config.device_class = 0xEF;
config.device_sub_class = 0x02;
config.device_protocol = 0x01;
struct Resources {
device_descriptor: [u8; 256],
config_descriptor: [u8; 256],
bos_descriptor: [u8; 256],
control_buf: [u8; 128],
serial_state: State<'static>,
}
let res: &mut Resources = singleton!(Resources {
device_descriptor: [0; 256],
config_descriptor: [0; 256],
bos_descriptor: [0; 256],
control_buf: [0; 128],
serial_state: State::new(),
});
// Create embassy-usb DeviceBuilder using the driver and config.
let mut builder = Builder::new(
driver,
config,
&mut res.device_descriptor,
&mut res.config_descriptor,
&mut res.bos_descriptor,
&mut res.control_buf,
None,
);
// WARNINGS for Android ethernet tethering:
// - On Pixel 4a, it refused to work on Android 11, worked on Android 12.
// - if the host's MAC address has the "locally-administered" bit set (bit 1 of first byte),
// it doesn't work! The "Ethernet tethering" option in settings doesn't get enabled.
// This is due to regex spaghetti: https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-mainline-12.0.0_r84/core/res/res/values/config.xml#417
// and this nonsense in the linux kernel: https://github.com/torvalds/linux/blob/c00c5e1d157bec0ef0b0b59aa5482eb8dc7e8e49/drivers/net/usb/usbnet.c#L1751-L1757
// Our MAC addr.
let our_mac_addr = [0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC];
// Host's MAC addr. This is the MAC the host "thinks" its USB-to-ethernet adapter has.
let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88];
// Create classes on the builder.
let class = CdcNcmClass::new(&mut builder, &mut res.serial_state, host_mac_addr, 64);
// Build the builder.
let usb = builder.build();
unwrap!(spawner.spawn(usb_task(usb)));
let (tx, rx) = class.split();
unwrap!(spawner.spawn(usb_ncm_rx_task(rx)));
unwrap!(spawner.spawn(usb_ncm_tx_task(tx)));
let config = embassy_net::ConfigStrategy::Dhcp;
//let config = embassy_net::ConfigStrategy::Static(embassy_net::Config {
// address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
// dns_servers: Vec::new(),
// gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
//});
// Generate random seed
let mut rng = Rng::new(p.RNG, interrupt::take!(RNG));
let mut seed = [0; 8];
rng.blocking_fill_bytes(&mut seed);
let seed = u64::from_le_bytes(seed);
// Init network stack
let device = Device { mac_addr: our_mac_addr };
let stack = &*singleton!(Stack::new(
device,
config,
singleton!(StackResources::<1, 2, 8>::new()),
seed
));
unwrap!(spawner.spawn(net_task(stack)));
// And now we can use it!
let mut rx_buffer = [0; 4096];
let mut tx_buffer = [0; 4096];
let mut buf = [0; 4096];
loop {
let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
socket.set_timeout(Some(embassy_net::SmolDuration::from_secs(10)));
info!("Listening on TCP:1234...");
if let Err(e) = socket.accept(1234).await {
warn!("accept error: {:?}", e);
continue;
}
info!("Received connection from {:?}", socket.remote_endpoint());
loop {
let n = match socket.read(&mut buf).await {
Ok(0) => {
warn!("read EOF");
break;
}
Ok(n) => n,
Err(e) => {
warn!("read error: {:?}", e);
break;
}
};
info!("rxd {:02x}", &buf[..n]);
match socket.write_all(&buf[..n]).await {
Ok(()) => {}
Err(e) => {
warn!("write error: {:?}", e);
break;
}
};
}
}
}
static TX_CHANNEL: Channel<ThreadModeRawMutex, PacketBuf, 8> = Channel::new();
static RX_CHANNEL: Channel<ThreadModeRawMutex, PacketBuf, 8> = Channel::new();
static LINK_UP: AtomicBool = AtomicBool::new(false);
struct Device {
mac_addr: [u8; 6],
}
impl embassy_net::Device for Device {
fn register_waker(&mut self, waker: &Waker) {
// loopy loopy wakey wakey
waker.wake_by_ref()
}
fn link_state(&mut self) -> embassy_net::LinkState {
match LINK_UP.load(Ordering::Relaxed) {
true => embassy_net::LinkState::Up,
false => embassy_net::LinkState::Down,
}
}
fn capabilities(&self) -> embassy_net::DeviceCapabilities {
let mut caps = embassy_net::DeviceCapabilities::default();
caps.max_transmission_unit = 1514; // 1500 IP + 14 ethernet header
caps.medium = embassy_net::Medium::Ethernet;
caps
}
fn is_transmit_ready(&mut self) -> bool {
true
}
fn transmit(&mut self, pkt: PacketBuf) {
if TX_CHANNEL.try_send(pkt).is_err() {
warn!("TX failed")
}
}
fn receive<'a>(&mut self) -> Option<PacketBuf> {
RX_CHANNEL.try_recv().ok()
}
fn ethernet_address(&self) -> [u8; 6] {
self.mac_addr
}
}

View File

@ -1,6 +1,6 @@
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
# replace nRF82840_xxAA with your chip as listed in `probe-run --list-chips`
runner = "probe-run --chip nRF52840_xxAA"
# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list`
runner = "probe-rs run --chip nRF52840_xxAA"
[build]
target = "thumbv7em-none-eabi"

View File

@ -0,0 +1,21 @@
[package]
edition = "2021"
name = "embassy-nrf52840-rtic-examples"
version = "0.1.0"
license = "MIT OR Apache-2.0"
[dependencies]
rtic = { version = "2", features = ["thumbv7-backend"] }
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime", "generic-queue"] }
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nightly", "unstable-traits", "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
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.0"
panic-probe = { version = "0.3", features = ["print-defmt"] }
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }

View 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");
}

View File

@ -0,0 +1,43 @@
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use {defmt_rtt as _, panic_probe as _};
#[rtic::app(device = embassy_nrf, peripherals = false, dispatchers = [SWI0_EGU0, SWI1_EGU1])]
mod app {
use defmt::info;
use embassy_nrf::gpio::{Level, Output, OutputDrive};
use embassy_nrf::peripherals;
use embassy_time::{Duration, Timer};
#[shared]
struct Shared {}
#[local]
struct Local {}
#[init]
fn init(_: init::Context) -> (Shared, Local) {
info!("Hello World!");
let p = embassy_nrf::init(Default::default());
blink::spawn(p.P0_13).map_err(|_| ()).unwrap();
(Shared {}, Local {})
}
#[task(priority = 1)]
async fn blink(_cx: blink::Context, pin: peripherals::P0_13) {
let mut led = Output::new(pin, Level::Low, OutputDrive::Standard);
loop {
info!("off!");
led.set_high();
Timer::after(Duration::from_millis(300)).await;
info!("on!");
led.set_low();
Timer::after(Duration::from_millis(300)).await;
}
}
}

View 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 nRF52840_xxAA"
[build]
target = "thumbv7em-none-eabi"
[env]
DEFMT_LOG = "trace"

View File

@ -0,0 +1,61 @@
[package]
edition = "2021"
name = "embassy-nrf52840-examples"
version = "0.1.0"
license = "MIT OR Apache-2.0"
[features]
default = ["nightly"]
nightly = [
"embedded-hal-async",
"embassy-executor/nightly",
"embassy-nrf/nightly",
"embassy-net/nightly",
"embassy-net-esp-hosted",
"embassy-nrf/unstable-traits",
"embassy-time/nightly",
"embassy-time/unstable-traits",
"static_cell/nightly",
"embassy-usb",
"embedded-io/async",
"embassy-net",
"embassy-lora",
"lora-phy",
"lorawan-device",
"lorawan",
]
[dependencies]
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"], optional = true }
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt", "msos-descriptor",], optional = true }
embedded-io = "0.4.0"
embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["time", "defmt"], optional = true }
lora-phy = { version = "1", optional = true }
lorawan-device = { version = "0.10.0", default-features = false, features = ["async", "external-lora-phy"], optional = true }
lorawan = { version = "0.7.3", default-features = false, features = ["default-crypto"], optional = true }
embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"], optional = true }
defmt = "0.3"
defmt-rtt = "0.4"
fixed = "1.10.0"
static_cell = "1.1"
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
cortex-m-rt = "0.7.0"
panic-probe = { version = "0.3", features = ["print-defmt"] }
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
rand = { version = "0.8.4", default-features = false }
embedded-storage = "0.3.0"
usbd-hid = "0.6.0"
serde = { version = "1.0.136", default-features = false }
embedded-hal-async = { version = "0.2.0-alpha.2", optional = true }
num-integer = { version = "0.1.45", default-features = false }
microfft = "0.5.0"
[patch.crates-io]
lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "ad289428fd44b02788e2fa2116445cc8f640a265" }

View 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");
}

View File

@ -0,0 +1,7 @@
MEMORY
{
/* NOTE 1 K = 1 KiBi = 1024 bytes */
/* These values correspond to the NRF52840 with Softdevices S140 7.0.1 */
FLASH : ORIGIN = 0x00000000, LENGTH = 1024K
RAM : ORIGIN = 0x20000000, LENGTH = 256K
}

View File

@ -4,12 +4,15 @@
use defmt::*;
use embassy_executor::Spawner;
use embassy_nrf::buffered_uarte::{BufferedUarte, State};
use embassy_nrf::{interrupt, uarte};
use embedded_io::asynch::{BufRead, Write};
use futures::pin_mut;
use embassy_nrf::buffered_uarte::{self, BufferedUarte};
use embassy_nrf::{bind_interrupts, peripherals, uarte};
use embedded_io::asynch::Write;
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
UARTE0_UART0 => buffered_uarte::InterruptHandler<peripherals::UARTE0>;
});
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_nrf::init(Default::default());
@ -20,25 +23,19 @@ async fn main(_spawner: Spawner) {
let mut tx_buffer = [0u8; 4096];
let mut rx_buffer = [0u8; 4096];
let irq = interrupt::take!(UARTE0_UART0);
let mut state = State::new();
// Please note - important to have hardware flow control (https://github.com/embassy-rs/embassy/issues/536)
let u = BufferedUarte::new(
&mut state,
let mut u = BufferedUarte::new(
p.UARTE0,
p.TIMER0,
p.PPI_CH0,
p.PPI_CH1,
irq,
p.PPI_GROUP0,
Irqs,
p.P0_08,
p.P0_06,
p.P0_07,
p.P0_05,
config,
&mut rx_buffer,
&mut tx_buffer,
);
pin_mut!(u);
info!("uarte initialized!");

View File

@ -2,6 +2,7 @@
#![no_main]
#![feature(type_alias_impl_trait)]
use core::future::poll_fn;
use core::task::Poll;
use defmt::{info, unwrap};
@ -26,7 +27,7 @@ async fn run2() {
#[embassy_executor::task]
async fn run3() {
futures::future::poll_fn(|cx| {
poll_fn(|cx| {
cx.waker().wake_by_ref();
Poll::<()>::Pending
})

View File

@ -0,0 +1,116 @@
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use core::f32::consts::PI;
use defmt::{error, info};
use embassy_executor::Spawner;
use embassy_nrf::i2s::{self, Channels, Config, MasterClock, MultiBuffering, Sample as _, SampleWidth, I2S};
use embassy_nrf::{bind_interrupts, peripherals};
use {defmt_rtt as _, panic_probe as _};
type Sample = i16;
const NUM_BUFFERS: usize = 2;
const NUM_SAMPLES: usize = 4;
bind_interrupts!(struct Irqs {
I2S => i2s::InterruptHandler<peripherals::I2S>;
});
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_nrf::init(Default::default());
let master_clock: MasterClock = i2s::ExactSampleRate::_50000.into();
let sample_rate = master_clock.sample_rate();
info!("Sample rate: {}", sample_rate);
let mut config = Config::default();
config.sample_width = SampleWidth::_16bit;
config.channels = Channels::MonoLeft;
let buffers_out = MultiBuffering::<Sample, NUM_BUFFERS, NUM_SAMPLES>::new();
let buffers_in = MultiBuffering::<Sample, NUM_BUFFERS, NUM_SAMPLES>::new();
let mut full_duplex_stream = I2S::new_master(p.I2S, Irqs, p.P0_25, p.P0_26, p.P0_27, master_clock, config)
.full_duplex(p.P0_29, p.P0_28, buffers_out, buffers_in);
let mut modulator = SineOsc::new();
modulator.set_frequency(8.0, 1.0 / sample_rate as f32);
modulator.set_amplitude(1.0);
full_duplex_stream.start().await.expect("I2S Start");
loop {
let (buff_out, buff_in) = full_duplex_stream.buffers();
for i in 0..NUM_SAMPLES {
let modulation = (Sample::SCALE as f32 * bipolar_to_unipolar(modulator.generate())) as Sample;
buff_out[i] = buff_in[i] * modulation;
}
if let Err(err) = full_duplex_stream.send_and_receive().await {
error!("{}", err);
}
}
}
struct SineOsc {
amplitude: f32,
modulo: f32,
phase_inc: f32,
}
impl SineOsc {
const B: f32 = 4.0 / PI;
const C: f32 = -4.0 / (PI * PI);
const P: f32 = 0.225;
pub fn new() -> Self {
Self {
amplitude: 1.0,
modulo: 0.0,
phase_inc: 0.0,
}
}
pub fn set_frequency(&mut self, freq: f32, inv_sample_rate: f32) {
self.phase_inc = freq * inv_sample_rate;
}
pub fn set_amplitude(&mut self, amplitude: f32) {
self.amplitude = amplitude;
}
pub fn generate(&mut self) -> f32 {
let signal = self.parabolic_sin(self.modulo);
self.modulo += self.phase_inc;
if self.modulo < 0.0 {
self.modulo += 1.0;
} else if self.modulo > 1.0 {
self.modulo -= 1.0;
}
signal * self.amplitude
}
fn parabolic_sin(&mut self, modulo: f32) -> f32 {
let angle = PI - modulo * 2.0 * PI;
let y = Self::B * angle + Self::C * angle * abs(angle);
Self::P * (y * abs(y) - y) + y
}
}
#[inline]
fn abs(value: f32) -> f32 {
if value < 0.0 {
-value
} else {
value
}
}
#[inline]
fn bipolar_to_unipolar(value: f32) -> f32 {
(value + 1.0) / 2.0
}

View File

@ -0,0 +1,118 @@
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use defmt::{debug, error, info};
use embassy_executor::Spawner;
use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S};
use embassy_nrf::pwm::{Prescaler, SimplePwm};
use embassy_nrf::{bind_interrupts, peripherals};
use {defmt_rtt as _, panic_probe as _};
type Sample = i16;
const NUM_SAMPLES: usize = 500;
bind_interrupts!(struct Irqs {
I2S => i2s::InterruptHandler<peripherals::I2S>;
});
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_nrf::init(Default::default());
let master_clock: MasterClock = i2s::ExactSampleRate::_50000.into();
let sample_rate = master_clock.sample_rate();
info!("Sample rate: {}", sample_rate);
let mut config = Config::default();
config.sample_width = SampleWidth::_16bit;
config.channels = Channels::MonoLeft;
let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new();
let mut input_stream =
I2S::new_master(p.I2S, Irqs, p.P0_25, p.P0_26, p.P0_27, master_clock, config).input(p.P0_29, buffers);
// Configure the PWM to use the pins corresponding to the RGB leds
let mut pwm = SimplePwm::new_3ch(p.PWM0, p.P0_23, p.P0_22, p.P0_24);
pwm.set_prescaler(Prescaler::Div1);
pwm.set_max_duty(255);
let mut rms_online = RmsOnline::<NUM_SAMPLES>::default();
input_stream.start().await.expect("I2S Start");
loop {
let rms = rms_online.process(input_stream.buffer());
let rgb = rgb_from_rms(rms);
debug!("RMS: {}, RGB: {:?}", rms, rgb);
for i in 0..3 {
pwm.set_duty(i, rgb[i].into());
}
if let Err(err) = input_stream.receive().await {
error!("{}", err);
}
}
}
/// RMS from 0.0 until 0.75 will give green with a proportional intensity
/// RMS from 0.75 until 0.9 will give a blend between orange and red proportionally to the intensity
/// RMS above 0.9 will give a red with a proportional intensity
fn rgb_from_rms(rms: f32) -> [u8; 3] {
if rms < 0.75 {
let intensity = rms / 0.75;
[0, (intensity * 165.0) as u8, 0]
} else if rms < 0.9 {
let intensity = (rms - 0.75) / 0.15;
[200, 165 - (165.0 * intensity) as u8, 0]
} else {
let intensity = (rms - 0.9) / 0.1;
[200 + (55.0 * intensity) as u8, 0, 0]
}
}
pub struct RmsOnline<const N: usize> {
pub squares: [f32; N],
pub head: usize,
}
impl<const N: usize> Default for RmsOnline<N> {
fn default() -> Self {
RmsOnline {
squares: [0.0; N],
head: 0,
}
}
}
impl<const N: usize> RmsOnline<N> {
pub fn reset(&mut self) {
self.squares = [0.0; N];
self.head = 0;
}
pub fn process(&mut self, buf: &[Sample]) -> f32 {
buf.iter()
.for_each(|sample| self.push(*sample as f32 / Sample::SCALE as f32));
let sum_of_squares = self.squares.iter().fold(0.0, |acc, v| acc + *v);
Self::approx_sqrt(sum_of_squares / N as f32)
}
pub fn push(&mut self, signal: f32) {
let square = signal * signal;
self.squares[self.head] = square;
self.head = (self.head + 1) % N;
}
/// Approximated sqrt taken from [micromath]
///
/// [micromath]: https://docs.rs/micromath/latest/src/micromath/float/sqrt.rs.html#11-17
///
fn approx_sqrt(value: f32) -> f32 {
f32::from_bits((value.to_bits() + 0x3f80_0000) >> 1)
}
}

View File

@ -0,0 +1,154 @@
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use core::f32::consts::PI;
use defmt::{error, info};
use embassy_executor::Spawner;
use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S};
use embassy_nrf::{bind_interrupts, peripherals};
use {defmt_rtt as _, panic_probe as _};
type Sample = i16;
const NUM_SAMPLES: usize = 50;
bind_interrupts!(struct Irqs {
I2S => i2s::InterruptHandler<peripherals::I2S>;
});
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_nrf::init(Default::default());
let master_clock: MasterClock = i2s::ExactSampleRate::_50000.into();
let sample_rate = master_clock.sample_rate();
info!("Sample rate: {}", sample_rate);
let mut config = Config::default();
config.sample_width = SampleWidth::_16bit;
config.channels = Channels::MonoLeft;
let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new();
let mut output_stream =
I2S::new_master(p.I2S, Irqs, p.P0_25, p.P0_26, p.P0_27, master_clock, config).output(p.P0_28, buffers);
let mut waveform = Waveform::new(1.0 / sample_rate as f32);
waveform.process(output_stream.buffer());
output_stream.start().await.expect("I2S Start");
loop {
waveform.process(output_stream.buffer());
if let Err(err) = output_stream.send().await {
error!("{}", err);
}
}
}
struct Waveform {
inv_sample_rate: f32,
carrier: SineOsc,
freq_mod: SineOsc,
amp_mod: SineOsc,
}
impl Waveform {
fn new(inv_sample_rate: f32) -> Self {
let mut carrier = SineOsc::new();
carrier.set_frequency(110.0, inv_sample_rate);
let mut freq_mod = SineOsc::new();
freq_mod.set_frequency(1.0, inv_sample_rate);
freq_mod.set_amplitude(1.0);
let mut amp_mod = SineOsc::new();
amp_mod.set_frequency(16.0, inv_sample_rate);
amp_mod.set_amplitude(0.5);
Self {
inv_sample_rate,
carrier,
freq_mod,
amp_mod,
}
}
fn process(&mut self, buf: &mut [Sample]) {
for sample in buf.chunks_mut(1) {
let freq_modulation = bipolar_to_unipolar(self.freq_mod.generate());
self.carrier
.set_frequency(110.0 + 440.0 * freq_modulation, self.inv_sample_rate);
let amp_modulation = bipolar_to_unipolar(self.amp_mod.generate());
self.carrier.set_amplitude(amp_modulation);
let signal = self.carrier.generate();
sample[0] = (Sample::SCALE as f32 * signal) as Sample;
}
}
}
struct SineOsc {
amplitude: f32,
modulo: f32,
phase_inc: f32,
}
impl SineOsc {
const B: f32 = 4.0 / PI;
const C: f32 = -4.0 / (PI * PI);
const P: f32 = 0.225;
pub fn new() -> Self {
Self {
amplitude: 1.0,
modulo: 0.0,
phase_inc: 0.0,
}
}
pub fn set_frequency(&mut self, freq: f32, inv_sample_rate: f32) {
self.phase_inc = freq * inv_sample_rate;
}
pub fn set_amplitude(&mut self, amplitude: f32) {
self.amplitude = amplitude;
}
pub fn generate(&mut self) -> f32 {
let signal = self.parabolic_sin(self.modulo);
self.modulo += self.phase_inc;
if self.modulo < 0.0 {
self.modulo += 1.0;
} else if self.modulo > 1.0 {
self.modulo -= 1.0;
}
signal * self.amplitude
}
fn parabolic_sin(&mut self, modulo: f32) -> f32 {
let angle = PI - modulo * 2.0 * PI;
let y = Self::B * angle + Self::C * angle * abs(angle);
Self::P * (y * abs(y) - y) + y
}
}
#[inline]
fn abs(value: f32) -> f32 {
if value < 0.0 {
-value
} else {
value
}
}
#[inline]
fn bipolar_to_unipolar(value: f32) -> f32 {
(value + 1.0) / 2.0
}

View File

@ -0,0 +1,99 @@
//! This example runs on the RAK4631 WisBlock, which has an nRF52840 MCU and Semtech Sx126x radio.
//! Other nrf/sx126x combinations may work with appropriate pin modifications.
//! It demonstrates LORA CAD functionality.
#![no_std]
#![no_main]
#![macro_use]
#![feature(type_alias_impl_trait)]
use defmt::*;
use embassy_executor::Spawner;
use embassy_lora::iv::GenericSx126xInterfaceVariant;
use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull};
use embassy_nrf::{bind_interrupts, peripherals, spim};
use embassy_time::{Delay, Duration, Timer};
use lora_phy::mod_params::*;
use lora_phy::sx1261_2::SX1261_2;
use lora_phy::LoRa;
use {defmt_rtt as _, panic_probe as _};
const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriately for the region
bind_interrupts!(struct Irqs {
SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => spim::InterruptHandler<peripherals::TWISPI1>;
});
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_nrf::init(Default::default());
let mut spi_config = spim::Config::default();
spi_config.frequency = spim::Frequency::M16;
let spim = spim::Spim::new(p.TWISPI1, Irqs, p.P1_11, p.P1_13, p.P1_12, spi_config);
let nss = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard);
let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard);
let dio1 = Input::new(p.P1_15.degrade(), Pull::Down);
let busy = Input::new(p.P1_14.degrade(), Pull::Down);
let rf_switch_rx = Output::new(p.P1_05.degrade(), Level::Low, OutputDrive::Standard);
let rf_switch_tx = Output::new(p.P1_07.degrade(), Level::Low, OutputDrive::Standard);
let iv =
GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, Some(rf_switch_rx), Some(rf_switch_tx)).unwrap();
let mut delay = Delay;
let mut lora = {
match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), false, &mut delay).await {
Ok(l) => l,
Err(err) => {
info!("Radio error = {}", err);
return;
}
}
};
let mut debug_indicator = Output::new(p.P1_03, Level::Low, OutputDrive::Standard);
let mut start_indicator = Output::new(p.P1_04, Level::Low, OutputDrive::Standard);
start_indicator.set_high();
Timer::after(Duration::from_secs(5)).await;
start_indicator.set_low();
let mdltn_params = {
match lora.create_modulation_params(
SpreadingFactor::_10,
Bandwidth::_250KHz,
CodingRate::_4_8,
LORA_FREQUENCY_IN_HZ,
) {
Ok(mp) => mp,
Err(err) => {
info!("Radio error = {}", err);
return;
}
}
};
match lora.prepare_for_cad(&mdltn_params, true).await {
Ok(()) => {}
Err(err) => {
info!("Radio error = {}", err);
return;
}
};
match lora.cad().await {
Ok(cad_activity_detected) => {
if cad_activity_detected {
info!("cad successful with activity detected")
} else {
info!("cad successful without activity detected")
}
debug_indicator.set_high();
Timer::after(Duration::from_secs(5)).await;
debug_indicator.set_low();
}
Err(err) => info!("cad unsuccessful = {}", err),
}
}

View File

@ -0,0 +1,83 @@
//! This example runs on the RAK4631 WisBlock, which has an nRF52840 MCU and Semtech Sx126x radio.
//! Other nrf/sx126x combinations may work with appropriate pin modifications.
//! It demonstrates LoRaWAN join functionality.
#![no_std]
#![no_main]
#![macro_use]
#![feature(type_alias_impl_trait)]
use defmt::*;
use embassy_executor::Spawner;
use embassy_lora::iv::GenericSx126xInterfaceVariant;
use embassy_lora::LoraTimer;
use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull};
use embassy_nrf::rng::Rng;
use embassy_nrf::{bind_interrupts, peripherals, rng, spim};
use embassy_time::Delay;
use lora_phy::mod_params::*;
use lora_phy::sx1261_2::SX1261_2;
use lora_phy::LoRa;
use lorawan::default_crypto::DefaultFactory as Crypto;
use lorawan_device::async_device::lora_radio::LoRaRadio;
use lorawan_device::async_device::{region, Device, JoinMode};
use {defmt_rtt as _, panic_probe as _};
const LORAWAN_REGION: region::Region = region::Region::EU868; // warning: set this appropriately for the region
bind_interrupts!(struct Irqs {
SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => spim::InterruptHandler<peripherals::TWISPI1>;
RNG => rng::InterruptHandler<peripherals::RNG>;
});
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_nrf::init(Default::default());
let mut spi_config = spim::Config::default();
spi_config.frequency = spim::Frequency::M16;
let spim = spim::Spim::new(p.TWISPI1, Irqs, p.P1_11, p.P1_13, p.P1_12, spi_config);
let nss = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard);
let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard);
let dio1 = Input::new(p.P1_15.degrade(), Pull::Down);
let busy = Input::new(p.P1_14.degrade(), Pull::Down);
let rf_switch_rx = Output::new(p.P1_05.degrade(), Level::Low, OutputDrive::Standard);
let rf_switch_tx = Output::new(p.P1_07.degrade(), Level::Low, OutputDrive::Standard);
let iv =
GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, Some(rf_switch_rx), Some(rf_switch_tx)).unwrap();
let mut delay = Delay;
let lora = {
match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), true, &mut delay).await {
Ok(l) => l,
Err(err) => {
info!("Radio error = {}", err);
return;
}
}
};
let radio = LoRaRadio::new(lora);
let region: region::Configuration = region::Configuration::new(LORAWAN_REGION);
let mut device: Device<_, Crypto, _, _> = Device::new(region, radio, LoraTimer::new(), Rng::new(p.RNG, Irqs));
defmt::info!("Joining LoRaWAN network");
// TODO: Adjust the EUI and Keys according to your network credentials
match device
.join(&JoinMode::OTAA {
deveui: [0, 0, 0, 0, 0, 0, 0, 0],
appeui: [0, 0, 0, 0, 0, 0, 0, 0],
appkey: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
})
.await
{
Ok(()) => defmt::info!("LoRaWAN network joined"),
Err(err) => {
info!("Radio error = {}", err);
return;
}
};
}

View File

@ -0,0 +1,121 @@
//! This example runs on the RAK4631 WisBlock, which has an nRF52840 MCU and Semtech Sx126x radio.
//! Other nrf/sx126x combinations may work with appropriate pin modifications.
//! It demonstrates LORA P2P receive functionality in conjunction with the lora_p2p_send example.
#![no_std]
#![no_main]
#![macro_use]
#![feature(type_alias_impl_trait)]
use defmt::*;
use embassy_executor::Spawner;
use embassy_lora::iv::GenericSx126xInterfaceVariant;
use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull};
use embassy_nrf::{bind_interrupts, peripherals, spim};
use embassy_time::{Delay, Duration, Timer};
use lora_phy::mod_params::*;
use lora_phy::sx1261_2::SX1261_2;
use lora_phy::LoRa;
use {defmt_rtt as _, panic_probe as _};
const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriately for the region
bind_interrupts!(struct Irqs {
SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => spim::InterruptHandler<peripherals::TWISPI1>;
});
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_nrf::init(Default::default());
let mut spi_config = spim::Config::default();
spi_config.frequency = spim::Frequency::M16;
let spim = spim::Spim::new(p.TWISPI1, Irqs, p.P1_11, p.P1_13, p.P1_12, spi_config);
let nss = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard);
let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard);
let dio1 = Input::new(p.P1_15.degrade(), Pull::Down);
let busy = Input::new(p.P1_14.degrade(), Pull::Down);
let rf_switch_rx = Output::new(p.P1_05.degrade(), Level::Low, OutputDrive::Standard);
let rf_switch_tx = Output::new(p.P1_07.degrade(), Level::Low, OutputDrive::Standard);
let iv =
GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, Some(rf_switch_rx), Some(rf_switch_tx)).unwrap();
let mut delay = Delay;
let mut lora = {
match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), false, &mut delay).await {
Ok(l) => l,
Err(err) => {
info!("Radio error = {}", err);
return;
}
}
};
let mut debug_indicator = Output::new(p.P1_03, Level::Low, OutputDrive::Standard);
let mut start_indicator = Output::new(p.P1_04, Level::Low, OutputDrive::Standard);
start_indicator.set_high();
Timer::after(Duration::from_secs(5)).await;
start_indicator.set_low();
let mut receiving_buffer = [00u8; 100];
let mdltn_params = {
match lora.create_modulation_params(
SpreadingFactor::_10,
Bandwidth::_250KHz,
CodingRate::_4_8,
LORA_FREQUENCY_IN_HZ,
) {
Ok(mp) => mp,
Err(err) => {
info!("Radio error = {}", err);
return;
}
}
};
let rx_pkt_params = {
match lora.create_rx_packet_params(4, false, receiving_buffer.len() as u8, true, false, &mdltn_params) {
Ok(pp) => pp,
Err(err) => {
info!("Radio error = {}", err);
return;
}
}
};
match lora
.prepare_for_rx(&mdltn_params, &rx_pkt_params, None, true, false, 0, 0x00ffffffu32)
.await
{
Ok(()) => {}
Err(err) => {
info!("Radio error = {}", err);
return;
}
};
loop {
receiving_buffer = [00u8; 100];
match lora.rx(&rx_pkt_params, &mut receiving_buffer).await {
Ok((received_len, _rx_pkt_status)) => {
if (received_len == 3)
&& (receiving_buffer[0] == 0x01u8)
&& (receiving_buffer[1] == 0x02u8)
&& (receiving_buffer[2] == 0x03u8)
{
info!("rx successful");
debug_indicator.set_high();
Timer::after(Duration::from_secs(5)).await;
debug_indicator.set_low();
} else {
info!("rx unknown packet");
}
}
Err(err) => info!("rx unsuccessful = {}", err),
}
}
}

View File

@ -0,0 +1,131 @@
//! This example runs on the RAK4631 WisBlock, which has an nRF52840 MCU and Semtech Sx126x radio.
//! Other nrf/sx126x combinations may work with appropriate pin modifications.
//! It demonstrates LoRa Rx duty cycle functionality in conjunction with the lora_p2p_send example.
#![no_std]
#![no_main]
#![macro_use]
#![feature(type_alias_impl_trait)]
use defmt::*;
use embassy_executor::Spawner;
use embassy_lora::iv::GenericSx126xInterfaceVariant;
use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull};
use embassy_nrf::{bind_interrupts, peripherals, spim};
use embassy_time::{Delay, Duration, Timer};
use lora_phy::mod_params::*;
use lora_phy::sx1261_2::SX1261_2;
use lora_phy::LoRa;
use {defmt_rtt as _, panic_probe as _};
const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriately for the region
bind_interrupts!(struct Irqs {
SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => spim::InterruptHandler<peripherals::TWISPI1>;
});
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_nrf::init(Default::default());
let mut spi_config = spim::Config::default();
spi_config.frequency = spim::Frequency::M16;
let spim = spim::Spim::new(p.TWISPI1, Irqs, p.P1_11, p.P1_13, p.P1_12, spi_config);
let nss = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard);
let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard);
let dio1 = Input::new(p.P1_15.degrade(), Pull::Down);
let busy = Input::new(p.P1_14.degrade(), Pull::Down);
let rf_switch_rx = Output::new(p.P1_05.degrade(), Level::Low, OutputDrive::Standard);
let rf_switch_tx = Output::new(p.P1_07.degrade(), Level::Low, OutputDrive::Standard);
let iv =
GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, Some(rf_switch_rx), Some(rf_switch_tx)).unwrap();
let mut delay = Delay;
let mut lora = {
match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), false, &mut delay).await {
Ok(l) => l,
Err(err) => {
info!("Radio error = {}", err);
return;
}
}
};
let mut debug_indicator = Output::new(p.P1_03, Level::Low, OutputDrive::Standard);
let mut start_indicator = Output::new(p.P1_04, Level::Low, OutputDrive::Standard);
start_indicator.set_high();
Timer::after(Duration::from_secs(5)).await;
start_indicator.set_low();
let mut receiving_buffer = [00u8; 100];
let mdltn_params = {
match lora.create_modulation_params(
SpreadingFactor::_10,
Bandwidth::_250KHz,
CodingRate::_4_8,
LORA_FREQUENCY_IN_HZ,
) {
Ok(mp) => mp,
Err(err) => {
info!("Radio error = {}", err);
return;
}
}
};
let rx_pkt_params = {
match lora.create_rx_packet_params(4, false, receiving_buffer.len() as u8, true, false, &mdltn_params) {
Ok(pp) => pp,
Err(err) => {
info!("Radio error = {}", err);
return;
}
}
};
// See "RM0453 Reference manual STM32WL5x advanced Arm®-based 32-bit MCUs with sub-GHz radio solution" for the best explanation of Rx duty cycle processing.
match lora
.prepare_for_rx(
&mdltn_params,
&rx_pkt_params,
Some(&DutyCycleParams {
rx_time: 300_000, // 300_000 units * 15.625 us/unit = 4.69 s
sleep_time: 200_000, // 200_000 units * 15.625 us/unit = 3.13 s
}),
false,
false,
0,
0,
)
.await
{
Ok(()) => {}
Err(err) => {
info!("Radio error = {}", err);
return;
}
};
receiving_buffer = [00u8; 100];
match lora.rx(&rx_pkt_params, &mut receiving_buffer).await {
Ok((received_len, _rx_pkt_status)) => {
if (received_len == 3)
&& (receiving_buffer[0] == 0x01u8)
&& (receiving_buffer[1] == 0x02u8)
&& (receiving_buffer[2] == 0x03u8)
{
info!("rx successful");
debug_indicator.set_high();
Timer::after(Duration::from_secs(5)).await;
debug_indicator.set_low();
} else {
info!("rx unknown packet")
}
}
Err(err) => info!("rx unsuccessful = {}", err),
}
}

View File

@ -0,0 +1,104 @@
//! This example runs on the RAK4631 WisBlock, which has an nRF52840 MCU and Semtech Sx126x radio.
//! Other nrf/sx126x combinations may work with appropriate pin modifications.
//! It demonstrates LORA P2P send functionality.
#![no_std]
#![no_main]
#![macro_use]
#![feature(type_alias_impl_trait)]
use defmt::*;
use embassy_executor::Spawner;
use embassy_lora::iv::GenericSx126xInterfaceVariant;
use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull};
use embassy_nrf::{bind_interrupts, peripherals, spim};
use embassy_time::Delay;
use lora_phy::mod_params::*;
use lora_phy::sx1261_2::SX1261_2;
use lora_phy::LoRa;
use {defmt_rtt as _, panic_probe as _};
const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriately for the region
bind_interrupts!(struct Irqs {
SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => spim::InterruptHandler<peripherals::TWISPI1>;
});
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_nrf::init(Default::default());
let mut spi_config = spim::Config::default();
spi_config.frequency = spim::Frequency::M16;
let spim = spim::Spim::new(p.TWISPI1, Irqs, p.P1_11, p.P1_13, p.P1_12, spi_config);
let nss = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard);
let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard);
let dio1 = Input::new(p.P1_15.degrade(), Pull::Down);
let busy = Input::new(p.P1_14.degrade(), Pull::Down);
let rf_switch_rx = Output::new(p.P1_05.degrade(), Level::Low, OutputDrive::Standard);
let rf_switch_tx = Output::new(p.P1_07.degrade(), Level::Low, OutputDrive::Standard);
let iv =
GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, Some(rf_switch_rx), Some(rf_switch_tx)).unwrap();
let mut delay = Delay;
let mut lora = {
match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), false, &mut delay).await {
Ok(l) => l,
Err(err) => {
info!("Radio error = {}", err);
return;
}
}
};
let mdltn_params = {
match lora.create_modulation_params(
SpreadingFactor::_10,
Bandwidth::_250KHz,
CodingRate::_4_8,
LORA_FREQUENCY_IN_HZ,
) {
Ok(mp) => mp,
Err(err) => {
info!("Radio error = {}", err);
return;
}
}
};
let mut tx_pkt_params = {
match lora.create_tx_packet_params(4, false, true, false, &mdltn_params) {
Ok(pp) => pp,
Err(err) => {
info!("Radio error = {}", err);
return;
}
}
};
match lora.prepare_for_tx(&mdltn_params, 20, false).await {
Ok(()) => {}
Err(err) => {
info!("Radio error = {}", err);
return;
}
};
let buffer = [0x01u8, 0x02u8, 0x03u8];
match lora.tx(&mdltn_params, &mut tx_pkt_params, &buffer, 0xffffff).await {
Ok(()) => {
info!("TX DONE");
}
Err(err) => {
info!("Radio error = {}", err);
return;
}
};
match lora.sleep(&mut delay).await {
Ok(()) => info!("Sleep successful"),
Err(err) => info!("Sleep unsuccessful = {}", err),
}
}

View File

@ -0,0 +1,49 @@
// This example showcases how to manually create an executor.
// This is what the #[embassy::main] macro does behind the scenes.
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use cortex_m_rt::entry;
use defmt::{info, unwrap};
use embassy_executor::Executor;
use embassy_time::{Duration, Timer};
use static_cell::StaticCell;
use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::task]
async fn run1() {
loop {
info!("BIG INFREQUENT TICK");
Timer::after(Duration::from_ticks(64000)).await;
}
}
#[embassy_executor::task]
async fn run2() {
loop {
info!("tick");
Timer::after(Duration::from_ticks(13000)).await;
}
}
static EXECUTOR: StaticCell<Executor> = StaticCell::new();
#[entry]
fn main() -> ! {
info!("Hello World!");
let _p = embassy_nrf::init(Default::default());
// Create the executor and put it in a StaticCell, because `run` needs `&'static mut Executor`.
let executor = EXECUTOR.init(Executor::new());
// Run it.
// `run` calls the closure then runs the executor forever. It never returns.
executor.run(|spawner| {
// Here we get access to a spawner to spawn the initial tasks.
unwrap!(spawner.spawn(run1()));
unwrap!(spawner.spawn(run2()));
});
}

View File

@ -59,9 +59,9 @@
use cortex_m_rt::entry;
use defmt::{info, unwrap};
use embassy_nrf::executor::{Executor, InterruptExecutor};
use embassy_executor::{Executor, InterruptExecutor};
use embassy_nrf::interrupt;
use embassy_nrf::interrupt::InterruptExt;
use embassy_nrf::interrupt::{InterruptExt, Priority};
use embassy_time::{Duration, Instant, Timer};
use static_cell::StaticCell;
use {defmt_rtt as _, panic_probe as _};
@ -108,10 +108,20 @@ async fn run_low() {
}
}
static EXECUTOR_HIGH: StaticCell<InterruptExecutor<interrupt::SWI1_EGU1>> = StaticCell::new();
static EXECUTOR_MED: StaticCell<InterruptExecutor<interrupt::SWI0_EGU0>> = StaticCell::new();
static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new();
static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new();
static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
#[interrupt]
unsafe fn SWI1_EGU1() {
EXECUTOR_HIGH.on_interrupt()
}
#[interrupt]
unsafe fn SWI0_EGU0() {
EXECUTOR_MED.on_interrupt()
}
#[entry]
fn main() -> ! {
info!("Hello World!");
@ -119,17 +129,13 @@ fn main() -> ! {
let _p = embassy_nrf::init(Default::default());
// High-priority executor: SWI1_EGU1, priority level 6
let irq = interrupt::take!(SWI1_EGU1);
irq.set_priority(interrupt::Priority::P6);
let executor = EXECUTOR_HIGH.init(InterruptExecutor::new(irq));
let spawner = executor.start();
interrupt::SWI1_EGU1.set_priority(Priority::P6);
let spawner = EXECUTOR_HIGH.start(interrupt::SWI1_EGU1);
unwrap!(spawner.spawn(run_high()));
// Medium-priority executor: SWI0_EGU0, priority level 7
let irq = interrupt::take!(SWI0_EGU0);
irq.set_priority(interrupt::Priority::P7);
let executor = EXECUTOR_MED.init(InterruptExecutor::new(irq));
let spawner = executor.start();
interrupt::SWI0_EGU0.set_priority(Priority::P7);
let spawner = EXECUTOR_MED.start(interrupt::SWI0_EGU0);
unwrap!(spawner.spawn(run_med()));
// Low priority executor: runs in thread mode, using WFE/SEV

View File

@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) {
let p = embassy_nrf::init(Default::default());
info!("Hello NVMC!");
// probe-run breaks without this, I'm not sure why.
// probe-rs run breaks without this, I'm not sure why.
Timer::after(Duration::from_secs(1)).await;
let mut f = Nvmc::new(p.NVMC);

View File

@ -0,0 +1,55 @@
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use defmt::info;
use embassy_executor::Spawner;
use embassy_nrf::pdm::{self, Config, Pdm};
use embassy_nrf::{bind_interrupts, peripherals};
use embassy_time::{Duration, Timer};
use fixed::types::I7F1;
use num_integer::Roots;
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
PDM => pdm::InterruptHandler<peripherals::PDM>;
});
#[embassy_executor::main]
async fn main(_p: Spawner) {
let p = embassy_nrf::init(Default::default());
let config = Config::default();
let mut pdm = Pdm::new(p.PDM, Irqs, p.P0_01, p.P0_00, config);
loop {
for gain in [I7F1::from_num(-20), I7F1::from_num(0), I7F1::from_num(20)] {
pdm.set_gain(gain, gain);
info!("Gain = {} dB", defmt::Debug2Format(&gain));
pdm.start().await;
// wait some time till the microphon settled
Timer::after(Duration::from_millis(1000)).await;
const SAMPLES: usize = 2048;
let mut buf = [0i16; SAMPLES];
pdm.sample(&mut buf).await.unwrap();
let mean = (buf.iter().map(|v| i32::from(*v)).sum::<i32>() / buf.len() as i32) as i16;
info!(
"{} samples, min {=i16}, max {=i16}, mean {=i16}, AC RMS {=i16}",
buf.len(),
buf.iter().min().unwrap(),
buf.iter().max().unwrap(),
mean,
(
buf.iter().map(|v| i32::from(*v - mean).pow(2)).fold(0i32, |a,b| a.saturating_add(b))
/ buf.len() as i32).sqrt() as i16,
);
info!("samples: {:?}", &buf);
pdm.stop().await;
Timer::after(Duration::from_millis(100)).await;
}
}
}

View File

@ -5,8 +5,8 @@
use defmt::info;
use core::cmp::Ordering;
use embassy_executor::Spawner;
use embassy_nrf::interrupt;
use embassy_nrf::pdm::{Config, Channels, Pdm, SamplerState, Frequency, Ratio};
use embassy_nrf::{bind_interrupts, peripherals};
use embassy_nrf::pdm::{self, Config, OperationMode, Pdm, SamplerState, Frequency, Ratio};
use fixed::types::I7F1;
use num_integer::Roots;
use microfft::real::rfft_1024;
@ -14,6 +14,10 @@ use {defmt_rtt as _, panic_probe as _};
// Demonstrates both continuous sampling and scanning multiple channels driven by a PPI linked timer
bind_interrupts!(struct Irqs {
PDM => pdm::InterruptHandler<peripherals::PDM>;
});
#[embassy_executor::main]
async fn main(_p: Spawner) {
let mut p = embassy_nrf::init(Default::default());
@ -21,9 +25,9 @@ async fn main(_p: Spawner) {
// Pins are correct for the onboard microphone on the Feather nRF52840 Sense.
config.frequency = Frequency::_1280K; // 16 kHz sample rate
config.ratio = Ratio::RATIO80;
config.channels = Channels::Mono;
config.operation_mode = OperationMode::Mono;
config.gain_left = I7F1::from_bits(5); // 2.5 dB
let mut pdm = Pdm::new(p.PDM, interrupt::take!(PDM), &mut p.P0_00, &mut p.P0_01, config);
let mut pdm = Pdm::new(p.PDM, Irqs, &mut p.P0_00, &mut p.P0_01, config);
let mut bufs = [[0; 1024]; 2];
@ -54,7 +58,7 @@ async fn main(_p: Spawner) {
SamplerState::Sampled
},
)
.await;
.await.unwrap();
}
fn fft_peak_freq(input: &[i16; 1024]) -> (usize, u32) {

View File

@ -74,9 +74,9 @@ async fn fast_logger(mut messages: Subscriber<'static, ThreadModeRawMutex, Messa
}
/// A logger task that awaits the messages, but also does some other work.
/// Because of this, depeding on how the messages were published, the subscriber might miss some messages
/// Because of this, depending on how the messages were published, the subscriber might miss some messages.
///
/// This takes the dynamic `DynSubscriber`. This is not as performant as the generic version, but let's you ignore some of the generics
/// This takes the dynamic `DynSubscriber`. This is not as performant as the generic version, but let's you ignore some of the generics.
#[embassy_executor::task]
async fn slow_logger(mut messages: DynSubscriber<'static, Message>) {
loop {

View File

@ -4,16 +4,19 @@
use defmt::info;
use embassy_executor::Spawner;
use embassy_nrf::interrupt;
use embassy_nrf::qdec::{self, Qdec};
use embassy_nrf::{bind_interrupts, peripherals};
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
QDEC => qdec::InterruptHandler<peripherals::QDEC>;
});
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_nrf::init(Default::default());
let irq = interrupt::take!(QDEC);
let config = qdec::Config::default();
let mut rotary_enc = Qdec::new(p.QDEC, irq, p.P0_31, p.P0_30, config);
let mut rotary_enc = Qdec::new(p.QDEC, Irqs, p.P0_31, p.P0_30, config);
info!("Turn rotary encoder!");
let mut value = 0;

View File

@ -4,7 +4,8 @@
use defmt::{assert_eq, info, unwrap};
use embassy_executor::Spawner;
use embassy_nrf::{interrupt, qspi};
use embassy_nrf::qspi::Frequency;
use embassy_nrf::{bind_interrupts, peripherals, qspi};
use {defmt_rtt as _, panic_probe as _};
const PAGE_SIZE: usize = 4096;
@ -14,18 +15,23 @@ const PAGE_SIZE: usize = 4096;
#[repr(C, align(4))]
struct AlignedBuf([u8; 4096]);
bind_interrupts!(struct Irqs {
QSPI => qspi::InterruptHandler<peripherals::QSPI>;
});
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_nrf::init(Default::default());
// Config for the MX25R64 present in the nRF52840 DK
let mut config = qspi::Config::default();
config.capacity = 8 * 1024 * 1024; // 8 MB
config.frequency = Frequency::M32;
config.read_opcode = qspi::ReadOpcode::READ4IO;
config.write_opcode = qspi::WriteOpcode::PP4IO;
config.write_page_size = qspi::WritePageSize::_256BYTES;
let irq = interrupt::take!(QSPI);
let mut q: qspi::Qspi<_, 67108864> = qspi::Qspi::new(
p.QSPI, irq, p.P0_19, p.P0_17, p.P0_20, p.P0_21, p.P0_22, p.P0_23, config,
let mut q = qspi::Qspi::new(
p.QSPI, Irqs, p.P0_19, p.P0_17, p.P0_20, p.P0_21, p.P0_22, p.P0_23, config,
);
let mut id = [1; 3];
@ -52,23 +58,23 @@ async fn main(_spawner: Spawner) {
for i in 0..8 {
info!("page {:?}: erasing... ", i);
unwrap!(q.erase(i * PAGE_SIZE).await);
unwrap!(q.erase(i * PAGE_SIZE as u32).await);
for j in 0..PAGE_SIZE {
buf.0[j] = pattern((j + i * PAGE_SIZE) as u32);
buf.0[j] = pattern((j as u32 + i * PAGE_SIZE as u32) as u32);
}
info!("programming...");
unwrap!(q.write(i * PAGE_SIZE, &buf.0).await);
unwrap!(q.write(i * PAGE_SIZE as u32, &buf.0).await);
}
for i in 0..8 {
info!("page {:?}: reading... ", i);
unwrap!(q.read(i * PAGE_SIZE, &mut buf.0).await);
unwrap!(q.read(i * PAGE_SIZE as u32, &mut buf.0).await);
info!("verifying...");
for j in 0..PAGE_SIZE {
assert_eq!(buf.0[j], pattern((j + i * PAGE_SIZE) as u32));
assert_eq!(buf.0[j], pattern((j as u32 + i * PAGE_SIZE as u32) as u32));
}
}

View File

@ -6,7 +6,8 @@ use core::mem;
use defmt::{info, unwrap};
use embassy_executor::Spawner;
use embassy_nrf::{interrupt, qspi};
use embassy_nrf::qspi::Frequency;
use embassy_nrf::{bind_interrupts, peripherals, qspi};
use embassy_time::{Duration, Timer};
use {defmt_rtt as _, panic_probe as _};
@ -15,14 +16,19 @@ use {defmt_rtt as _, panic_probe as _};
#[repr(C, align(4))]
struct AlignedBuf([u8; 64]);
bind_interrupts!(struct Irqs {
QSPI => qspi::InterruptHandler<peripherals::QSPI>;
});
#[embassy_executor::main]
async fn main(_p: Spawner) {
let mut p = embassy_nrf::init(Default::default());
let mut irq = interrupt::take!(QSPI);
loop {
// Config for the MX25R64 present in the nRF52840 DK
let mut config = qspi::Config::default();
config.capacity = 8 * 1024 * 1024; // 8 MB
config.frequency = Frequency::M32;
config.read_opcode = qspi::ReadOpcode::READ4IO;
config.write_opcode = qspi::WriteOpcode::PP4IO;
config.write_page_size = qspi::WritePageSize::_256BYTES;
@ -31,9 +37,9 @@ async fn main(_p: Spawner) {
exit_time: 3, // tRDP = 35uS
});
let mut q: qspi::Qspi<_, 67108864> = qspi::Qspi::new(
let mut q = qspi::Qspi::new(
&mut p.QSPI,
&mut irq,
Irqs,
&mut p.P0_19,
&mut p.P0_17,
&mut p.P0_20,

Some files were not shown because too many files have changed in this diff Show More