diff options
Diffstat (limited to 'examples/nrf/src')
| -rw-r--r-- | examples/nrf/src/bin/blinky.rs | 28 | ||||
| -rw-r--r-- | examples/nrf/src/bin/buffered_uart.rs | 68 | ||||
| -rw-r--r-- | examples/nrf/src/bin/executor_fairness_test.rs | 47 | ||||
| -rw-r--r-- | examples/nrf/src/bin/gpiote_channel.rs | 72 | ||||
| -rw-r--r-- | examples/nrf/src/bin/gpiote_port.rs | 43 | ||||
| -rw-r--r-- | examples/nrf/src/bin/multiprio.rs | 162 | ||||
| -rw-r--r-- | examples/nrf/src/bin/ppi.rs | 87 | ||||
| -rw-r--r-- | examples/nrf/src/bin/pwm.rs | 104 | ||||
| -rw-r--r-- | examples/nrf/src/bin/qspi.rs | 84 | ||||
| -rw-r--r-- | examples/nrf/src/bin/qspi_lowpower.rs | 85 | ||||
| -rw-r--r-- | examples/nrf/src/bin/raw_spawn.rs | 65 | ||||
| -rw-r--r-- | examples/nrf/src/bin/spim.rs | 76 | ||||
| -rw-r--r-- | examples/nrf/src/bin/timer.rs | 37 | ||||
| -rw-r--r-- | examples/nrf/src/bin/twim.rs | 35 | ||||
| -rw-r--r-- | examples/nrf/src/bin/twim_lowpower.rs | 54 | ||||
| -rw-r--r-- | examples/nrf/src/bin/uart.rs | 43 | ||||
| -rw-r--r-- | examples/nrf/src/bin/uart_idle.rs | 46 | ||||
| -rw-r--r-- | examples/nrf/src/example_common.rs | 17 |
18 files changed, 1153 insertions, 0 deletions
diff --git a/examples/nrf/src/bin/blinky.rs b/examples/nrf/src/bin/blinky.rs new file mode 100644 index 000000000..8f12cfda9 --- /dev/null +++ b/examples/nrf/src/bin/blinky.rs | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(min_type_alias_impl_trait)] | ||
| 4 | #![feature(impl_trait_in_bindings)] | ||
| 5 | #![feature(type_alias_impl_trait)] | ||
| 6 | #![allow(incomplete_features)] | ||
| 7 | |||
| 8 | #[path = "../example_common.rs"] | ||
| 9 | mod example_common; | ||
| 10 | |||
| 11 | use defmt::panic; | ||
| 12 | use embassy::executor::Spawner; | ||
| 13 | use embassy::time::{Duration, Timer}; | ||
| 14 | use embassy_nrf::gpio::{Level, Output, OutputDrive}; | ||
| 15 | use embassy_nrf::Peripherals; | ||
| 16 | use embedded_hal::digital::v2::OutputPin; | ||
| 17 | |||
| 18 | #[embassy::main] | ||
| 19 | async fn main(_spawner: Spawner, p: Peripherals) { | ||
| 20 | let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard); | ||
| 21 | |||
| 22 | loop { | ||
| 23 | led.set_high().unwrap(); | ||
| 24 | Timer::after(Duration::from_millis(300)).await; | ||
| 25 | led.set_low().unwrap(); | ||
| 26 | Timer::after(Duration::from_millis(300)).await; | ||
| 27 | } | ||
| 28 | } | ||
diff --git a/examples/nrf/src/bin/buffered_uart.rs b/examples/nrf/src/bin/buffered_uart.rs new file mode 100644 index 000000000..c800e64fc --- /dev/null +++ b/examples/nrf/src/bin/buffered_uart.rs | |||
| @@ -0,0 +1,68 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(min_type_alias_impl_trait)] | ||
| 4 | #![feature(impl_trait_in_bindings)] | ||
| 5 | #![feature(type_alias_impl_trait)] | ||
| 6 | #![allow(incomplete_features)] | ||
| 7 | |||
| 8 | #[path = "../example_common.rs"] | ||
| 9 | mod example_common; | ||
| 10 | |||
| 11 | use defmt::panic; | ||
| 12 | use embassy::executor::Spawner; | ||
| 13 | use embassy::io::{AsyncBufReadExt, AsyncWriteExt}; | ||
| 14 | use embassy_nrf::gpio::NoPin; | ||
| 15 | use embassy_nrf::{buffered_uarte::BufferedUarte, interrupt, uarte, Peripherals}; | ||
| 16 | use example_common::*; | ||
| 17 | use futures::pin_mut; | ||
| 18 | |||
| 19 | #[embassy::main] | ||
| 20 | async fn main(_spawner: Spawner, p: Peripherals) { | ||
| 21 | let mut config = uarte::Config::default(); | ||
| 22 | config.parity = uarte::Parity::EXCLUDED; | ||
| 23 | config.baudrate = uarte::Baudrate::BAUD115200; | ||
| 24 | |||
| 25 | let mut tx_buffer = [0u8; 4096]; | ||
| 26 | let mut rx_buffer = [0u8; 4096]; | ||
| 27 | |||
| 28 | let irq = interrupt::take!(UARTE0_UART0); | ||
| 29 | let u = unsafe { | ||
| 30 | BufferedUarte::new( | ||
| 31 | p.UARTE0, | ||
| 32 | p.TIMER0, | ||
| 33 | p.PPI_CH0, | ||
| 34 | p.PPI_CH1, | ||
| 35 | irq, | ||
| 36 | p.P0_08, | ||
| 37 | p.P0_06, | ||
| 38 | NoPin, | ||
| 39 | NoPin, | ||
| 40 | config, | ||
| 41 | &mut rx_buffer, | ||
| 42 | &mut tx_buffer, | ||
| 43 | ) | ||
| 44 | }; | ||
| 45 | pin_mut!(u); | ||
| 46 | |||
| 47 | info!("uarte initialized!"); | ||
| 48 | |||
| 49 | unwrap!(u.write_all(b"Hello!\r\n").await); | ||
| 50 | info!("wrote hello in uart!"); | ||
| 51 | |||
| 52 | // Simple demo, reading 8-char chunks and echoing them back reversed. | ||
| 53 | loop { | ||
| 54 | info!("reading..."); | ||
| 55 | let mut buf = [0u8; 8]; | ||
| 56 | unwrap!(u.read_exact(&mut buf).await); | ||
| 57 | info!("read done, got {}", buf); | ||
| 58 | |||
| 59 | // Reverse buf | ||
| 60 | for i in 0..4 { | ||
| 61 | buf.swap(i, 7 - i); | ||
| 62 | } | ||
| 63 | |||
| 64 | info!("writing..."); | ||
| 65 | unwrap!(u.write_all(&buf).await); | ||
| 66 | info!("write done"); | ||
| 67 | } | ||
| 68 | } | ||
diff --git a/examples/nrf/src/bin/executor_fairness_test.rs b/examples/nrf/src/bin/executor_fairness_test.rs new file mode 100644 index 000000000..797be4335 --- /dev/null +++ b/examples/nrf/src/bin/executor_fairness_test.rs | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(min_type_alias_impl_trait)] | ||
| 4 | #![feature(impl_trait_in_bindings)] | ||
| 5 | #![feature(type_alias_impl_trait)] | ||
| 6 | #![allow(incomplete_features)] | ||
| 7 | |||
| 8 | #[path = "../example_common.rs"] | ||
| 9 | mod example_common; | ||
| 10 | use example_common::*; | ||
| 11 | |||
| 12 | use core::task::Poll; | ||
| 13 | use defmt::panic; | ||
| 14 | use embassy::executor::Spawner; | ||
| 15 | use embassy::time::{Duration, Instant, Timer}; | ||
| 16 | use embassy_nrf::{interrupt, Peripherals}; | ||
| 17 | |||
| 18 | #[embassy::task] | ||
| 19 | async fn run1() { | ||
| 20 | loop { | ||
| 21 | info!("DING DONG"); | ||
| 22 | Timer::after(Duration::from_ticks(16000)).await; | ||
| 23 | } | ||
| 24 | } | ||
| 25 | |||
| 26 | #[embassy::task] | ||
| 27 | async fn run2() { | ||
| 28 | loop { | ||
| 29 | Timer::at(Instant::from_ticks(0)).await; | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
| 33 | #[embassy::task] | ||
| 34 | async fn run3() { | ||
| 35 | futures::future::poll_fn(|cx| { | ||
| 36 | cx.waker().wake_by_ref(); | ||
| 37 | Poll::<()>::Pending | ||
| 38 | }) | ||
| 39 | .await; | ||
| 40 | } | ||
| 41 | |||
| 42 | #[embassy::main] | ||
| 43 | async fn main(spawner: Spawner, _p: Peripherals) { | ||
| 44 | unwrap!(spawner.spawn(run1())); | ||
| 45 | unwrap!(spawner.spawn(run2())); | ||
| 46 | unwrap!(spawner.spawn(run3())); | ||
| 47 | } | ||
diff --git a/examples/nrf/src/bin/gpiote_channel.rs b/examples/nrf/src/bin/gpiote_channel.rs new file mode 100644 index 000000000..9800aed98 --- /dev/null +++ b/examples/nrf/src/bin/gpiote_channel.rs | |||
| @@ -0,0 +1,72 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(min_type_alias_impl_trait)] | ||
| 4 | #![feature(impl_trait_in_bindings)] | ||
| 5 | #![feature(type_alias_impl_trait)] | ||
| 6 | #![allow(incomplete_features)] | ||
| 7 | |||
| 8 | #[path = "../example_common.rs"] | ||
| 9 | mod example_common; | ||
| 10 | use example_common::*; | ||
| 11 | |||
| 12 | use defmt::panic; | ||
| 13 | use embassy::executor::Spawner; | ||
| 14 | use embassy_nrf::gpio::{Input, Pull}; | ||
| 15 | use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity}; | ||
| 16 | use embassy_nrf::{interrupt, Peripherals}; | ||
| 17 | |||
| 18 | #[embassy::main] | ||
| 19 | async fn main(_spawner: Spawner, p: Peripherals) { | ||
| 20 | info!("Starting!"); | ||
| 21 | |||
| 22 | let ch1 = InputChannel::new( | ||
| 23 | p.GPIOTE_CH0, | ||
| 24 | Input::new(p.P0_11, Pull::Up), | ||
| 25 | InputChannelPolarity::HiToLo, | ||
| 26 | ); | ||
| 27 | let ch2 = InputChannel::new( | ||
| 28 | p.GPIOTE_CH1, | ||
| 29 | Input::new(p.P0_12, Pull::Up), | ||
| 30 | InputChannelPolarity::LoToHi, | ||
| 31 | ); | ||
| 32 | let ch3 = InputChannel::new( | ||
| 33 | p.GPIOTE_CH2, | ||
| 34 | Input::new(p.P0_24, Pull::Up), | ||
| 35 | InputChannelPolarity::Toggle, | ||
| 36 | ); | ||
| 37 | let ch4 = InputChannel::new( | ||
| 38 | p.GPIOTE_CH3, | ||
| 39 | Input::new(p.P0_25, Pull::Up), | ||
| 40 | InputChannelPolarity::Toggle, | ||
| 41 | ); | ||
| 42 | |||
| 43 | let button1 = async { | ||
| 44 | loop { | ||
| 45 | ch1.wait().await; | ||
| 46 | info!("Button 1 pressed") | ||
| 47 | } | ||
| 48 | }; | ||
| 49 | |||
| 50 | let button2 = async { | ||
| 51 | loop { | ||
| 52 | ch2.wait().await; | ||
| 53 | info!("Button 2 released") | ||
| 54 | } | ||
| 55 | }; | ||
| 56 | |||
| 57 | let button3 = async { | ||
| 58 | loop { | ||
| 59 | ch3.wait().await; | ||
| 60 | info!("Button 3 toggled") | ||
| 61 | } | ||
| 62 | }; | ||
| 63 | |||
| 64 | let button4 = async { | ||
| 65 | loop { | ||
| 66 | ch4.wait().await; | ||
| 67 | info!("Button 4 toggled") | ||
| 68 | } | ||
| 69 | }; | ||
| 70 | |||
| 71 | futures::join!(button1, button2, button3, button4); | ||
| 72 | } | ||
diff --git a/examples/nrf/src/bin/gpiote_port.rs b/examples/nrf/src/bin/gpiote_port.rs new file mode 100644 index 000000000..4a7951cd3 --- /dev/null +++ b/examples/nrf/src/bin/gpiote_port.rs | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(min_type_alias_impl_trait)] | ||
| 4 | #![feature(impl_trait_in_bindings)] | ||
| 5 | #![feature(type_alias_impl_trait)] | ||
| 6 | #![allow(incomplete_features)] | ||
| 7 | |||
| 8 | #[path = "../example_common.rs"] | ||
| 9 | mod example_common; | ||
| 10 | |||
| 11 | use defmt::panic; | ||
| 12 | use embassy::executor::Spawner; | ||
| 13 | use embassy::traits::gpio::{WaitForHigh, WaitForLow}; | ||
| 14 | use embassy_nrf::gpio::{AnyPin, Input, Pin as _, Pull}; | ||
| 15 | use embassy_nrf::gpiote::PortInput; | ||
| 16 | use embassy_nrf::interrupt; | ||
| 17 | use embassy_nrf::Peripherals; | ||
| 18 | use example_common::*; | ||
| 19 | |||
| 20 | #[embassy::task(pool_size = 4)] | ||
| 21 | async fn button_task(n: usize, mut pin: PortInput<'static, AnyPin>) { | ||
| 22 | loop { | ||
| 23 | pin.wait_for_low().await; | ||
| 24 | info!("Button {:?} pressed!", n); | ||
| 25 | pin.wait_for_high().await; | ||
| 26 | info!("Button {:?} released!", n); | ||
| 27 | } | ||
| 28 | } | ||
| 29 | |||
| 30 | #[embassy::main] | ||
| 31 | async fn main(spawner: Spawner, p: Peripherals) { | ||
| 32 | info!("Starting!"); | ||
| 33 | |||
| 34 | let btn1 = PortInput::new(Input::new(p.P0_11.degrade(), Pull::Up)); | ||
| 35 | let btn2 = PortInput::new(Input::new(p.P0_12.degrade(), Pull::Up)); | ||
| 36 | let btn3 = PortInput::new(Input::new(p.P0_24.degrade(), Pull::Up)); | ||
| 37 | let btn4 = PortInput::new(Input::new(p.P0_25.degrade(), Pull::Up)); | ||
| 38 | |||
| 39 | spawner.spawn(button_task(1, btn1)).unwrap(); | ||
| 40 | spawner.spawn(button_task(2, btn2)).unwrap(); | ||
| 41 | spawner.spawn(button_task(3, btn3)).unwrap(); | ||
| 42 | spawner.spawn(button_task(4, btn4)).unwrap(); | ||
| 43 | } | ||
diff --git a/examples/nrf/src/bin/multiprio.rs b/examples/nrf/src/bin/multiprio.rs new file mode 100644 index 000000000..79fa029b3 --- /dev/null +++ b/examples/nrf/src/bin/multiprio.rs | |||
| @@ -0,0 +1,162 @@ | |||
| 1 | //! This example showcases how to create multiple Executor instances to run tasks at | ||
| 2 | //! different priority levels. | ||
| 3 | //! | ||
| 4 | //! Low priority executor runs in thread mode (not interrupt), and uses `sev` for signaling | ||
| 5 | //! there's work in the queue, and `wfe` for waiting for work. | ||
| 6 | //! | ||
| 7 | //! Medium and high priority executors run in two interrupts with different priorities. | ||
| 8 | //! Signaling work is done by pending the interrupt. No "waiting" needs to be done explicitly, since | ||
| 9 | //! when there's work the interrupt will trigger and run the executor. | ||
| 10 | //! | ||
| 11 | //! Sample output below. Note that high priority ticks can interrupt everything else, and | ||
| 12 | //! medium priority computations can interrupt low priority computations, making them to appear | ||
| 13 | //! to take significantly longer time. | ||
| 14 | //! | ||
| 15 | //! ```not_rust | ||
| 16 | //! [med] Starting long computation | ||
| 17 | //! [med] done in 992 ms | ||
| 18 | //! [high] tick! | ||
| 19 | //! [low] Starting long computation | ||
| 20 | //! [med] Starting long computation | ||
| 21 | //! [high] tick! | ||
| 22 | //! [high] tick! | ||
| 23 | //! [med] done in 993 ms | ||
| 24 | //! [med] Starting long computation | ||
| 25 | //! [high] tick! | ||
| 26 | //! [high] tick! | ||
| 27 | //! [med] done in 993 ms | ||
| 28 | //! [low] done in 3972 ms | ||
| 29 | //! [med] Starting long computation | ||
| 30 | //! [high] tick! | ||
| 31 | //! [high] tick! | ||
| 32 | //! [med] done in 993 ms | ||
| 33 | //! ``` | ||
| 34 | //! | ||
| 35 | //! For comparison, try changing the code so all 3 tasks get spawned on the low priority executor. | ||
| 36 | //! You will get an output like the following. Note that no computation is ever interrupted. | ||
| 37 | //! | ||
| 38 | //! ```not_rust | ||
| 39 | //! [high] tick! | ||
| 40 | //! [med] Starting long computation | ||
| 41 | //! [med] done in 496 ms | ||
| 42 | //! [low] Starting long computation | ||
| 43 | //! [low] done in 992 ms | ||
| 44 | //! [med] Starting long computation | ||
| 45 | //! [med] done in 496 ms | ||
| 46 | //! [high] tick! | ||
| 47 | //! [low] Starting long computation | ||
| 48 | //! [low] done in 992 ms | ||
| 49 | //! [high] tick! | ||
| 50 | //! [med] Starting long computation | ||
| 51 | //! [med] done in 496 ms | ||
| 52 | //! [high] tick! | ||
| 53 | //! ``` | ||
| 54 | //! | ||
| 55 | |||
| 56 | #![no_std] | ||
| 57 | #![no_main] | ||
| 58 | #![feature(min_type_alias_impl_trait)] | ||
| 59 | #![feature(impl_trait_in_bindings)] | ||
| 60 | #![feature(type_alias_impl_trait)] | ||
| 61 | #![allow(incomplete_features)] | ||
| 62 | |||
| 63 | #[path = "../example_common.rs"] | ||
| 64 | mod example_common; | ||
| 65 | use example_common::*; | ||
| 66 | |||
| 67 | use cortex_m_rt::entry; | ||
| 68 | use defmt::panic; | ||
| 69 | use embassy::executor::{Executor, InterruptExecutor}; | ||
| 70 | use embassy::interrupt::InterruptExt; | ||
| 71 | use embassy::time::{Duration, Instant, Timer}; | ||
| 72 | use embassy::util::Forever; | ||
| 73 | use embassy_nrf::{interrupt, peripherals, rtc}; | ||
| 74 | |||
| 75 | #[embassy::task] | ||
| 76 | async fn run_high() { | ||
| 77 | loop { | ||
| 78 | info!(" [high] tick!"); | ||
| 79 | Timer::after(Duration::from_ticks(27374)).await; | ||
| 80 | } | ||
| 81 | } | ||
| 82 | |||
| 83 | #[embassy::task] | ||
| 84 | async fn run_med() { | ||
| 85 | loop { | ||
| 86 | let start = Instant::now(); | ||
| 87 | info!(" [med] Starting long computation"); | ||
| 88 | |||
| 89 | // Spin-wait to simulate a long CPU computation | ||
| 90 | cortex_m::asm::delay(32_000_000); // ~1 second | ||
| 91 | |||
| 92 | let end = Instant::now(); | ||
| 93 | let ms = end.duration_since(start).as_ticks() / 33; | ||
| 94 | info!(" [med] done in {} ms", ms); | ||
| 95 | |||
| 96 | Timer::after(Duration::from_ticks(23421)).await; | ||
| 97 | } | ||
| 98 | } | ||
| 99 | |||
| 100 | #[embassy::task] | ||
| 101 | async fn run_low() { | ||
| 102 | loop { | ||
| 103 | let start = Instant::now(); | ||
| 104 | info!("[low] Starting long computation"); | ||
| 105 | |||
| 106 | // Spin-wait to simulate a long CPU computation | ||
| 107 | cortex_m::asm::delay(64_000_000); // ~2 seconds | ||
| 108 | |||
| 109 | let end = Instant::now(); | ||
| 110 | let ms = end.duration_since(start).as_ticks() / 33; | ||
| 111 | info!("[low] done in {} ms", ms); | ||
| 112 | |||
| 113 | Timer::after(Duration::from_ticks(32983)).await; | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | static RTC: Forever<rtc::RTC<peripherals::RTC1>> = Forever::new(); | ||
| 118 | static ALARM_HIGH: Forever<rtc::Alarm<peripherals::RTC1>> = Forever::new(); | ||
| 119 | static EXECUTOR_HIGH: Forever<InterruptExecutor<interrupt::SWI1_EGU1>> = Forever::new(); | ||
| 120 | static ALARM_MED: Forever<rtc::Alarm<peripherals::RTC1>> = Forever::new(); | ||
| 121 | static EXECUTOR_MED: Forever<InterruptExecutor<interrupt::SWI0_EGU0>> = Forever::new(); | ||
| 122 | static ALARM_LOW: Forever<rtc::Alarm<peripherals::RTC1>> = Forever::new(); | ||
| 123 | static EXECUTOR_LOW: Forever<Executor> = Forever::new(); | ||
| 124 | |||
| 125 | #[entry] | ||
| 126 | fn main() -> ! { | ||
| 127 | info!("Hello World!"); | ||
| 128 | |||
| 129 | let p = embassy_nrf::init(Default::default()); | ||
| 130 | |||
| 131 | let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1))); | ||
| 132 | rtc.start(); | ||
| 133 | unsafe { embassy::time::set_clock(rtc) }; | ||
| 134 | |||
| 135 | // High-priority executor: SWI1_EGU1, priority level 6 | ||
| 136 | let irq = interrupt::take!(SWI1_EGU1); | ||
| 137 | irq.set_priority(interrupt::Priority::P6); | ||
| 138 | let alarm = ALARM_HIGH.put(rtc.alarm2()); | ||
| 139 | let executor = EXECUTOR_HIGH.put(InterruptExecutor::new(irq)); | ||
| 140 | executor.set_alarm(alarm); | ||
| 141 | executor.start(|spawner| { | ||
| 142 | unwrap!(spawner.spawn(run_high())); | ||
| 143 | }); | ||
| 144 | |||
| 145 | // Medium-priority executor: SWI0_EGU0, priority level 7 | ||
| 146 | let irq = interrupt::take!(SWI0_EGU0); | ||
| 147 | irq.set_priority(interrupt::Priority::P7); | ||
| 148 | let alarm = ALARM_MED.put(rtc.alarm1()); | ||
| 149 | let executor = EXECUTOR_MED.put(InterruptExecutor::new(irq)); | ||
| 150 | executor.set_alarm(alarm); | ||
| 151 | executor.start(|spawner| { | ||
| 152 | unwrap!(spawner.spawn(run_med())); | ||
| 153 | }); | ||
| 154 | |||
| 155 | // Low priority executor: runs in thread mode, using WFE/SEV | ||
| 156 | let alarm = ALARM_LOW.put(rtc.alarm0()); | ||
| 157 | let executor = EXECUTOR_LOW.put(Executor::new()); | ||
| 158 | executor.set_alarm(alarm); | ||
| 159 | executor.run(|spawner| { | ||
| 160 | unwrap!(spawner.spawn(run_low())); | ||
| 161 | }); | ||
| 162 | } | ||
diff --git a/examples/nrf/src/bin/ppi.rs b/examples/nrf/src/bin/ppi.rs new file mode 100644 index 000000000..717604b9e --- /dev/null +++ b/examples/nrf/src/bin/ppi.rs | |||
| @@ -0,0 +1,87 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(min_type_alias_impl_trait)] | ||
| 4 | #![feature(impl_trait_in_bindings)] | ||
| 5 | #![feature(type_alias_impl_trait)] | ||
| 6 | #![allow(incomplete_features)] | ||
| 7 | |||
| 8 | #[path = "../example_common.rs"] | ||
| 9 | mod example_common; | ||
| 10 | use example_common::*; | ||
| 11 | |||
| 12 | use core::future::pending; | ||
| 13 | use defmt::panic; | ||
| 14 | use embassy::executor::Spawner; | ||
| 15 | use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; | ||
| 16 | use embassy_nrf::gpiote::{self, InputChannel, InputChannelPolarity}; | ||
| 17 | use embassy_nrf::ppi::Ppi; | ||
| 18 | use embassy_nrf::{interrupt, Peripherals}; | ||
| 19 | use gpiote::{OutputChannel, OutputChannelPolarity}; | ||
| 20 | |||
| 21 | #[embassy::main] | ||
| 22 | async fn main(_spawner: Spawner, p: Peripherals) { | ||
| 23 | info!("Starting!"); | ||
| 24 | |||
| 25 | let button1 = InputChannel::new( | ||
| 26 | p.GPIOTE_CH0, | ||
| 27 | Input::new(p.P0_11, Pull::Up), | ||
| 28 | InputChannelPolarity::HiToLo, | ||
| 29 | ); | ||
| 30 | let button2 = InputChannel::new( | ||
| 31 | p.GPIOTE_CH1, | ||
| 32 | Input::new(p.P0_12, Pull::Up), | ||
| 33 | InputChannelPolarity::HiToLo, | ||
| 34 | ); | ||
| 35 | let button3 = InputChannel::new( | ||
| 36 | p.GPIOTE_CH2, | ||
| 37 | Input::new(p.P0_24, Pull::Up), | ||
| 38 | InputChannelPolarity::HiToLo, | ||
| 39 | ); | ||
| 40 | let button4 = InputChannel::new( | ||
| 41 | p.GPIOTE_CH3, | ||
| 42 | Input::new(p.P0_25, Pull::Up), | ||
| 43 | InputChannelPolarity::HiToLo, | ||
| 44 | ); | ||
| 45 | |||
| 46 | let led1 = OutputChannel::new( | ||
| 47 | p.GPIOTE_CH4, | ||
| 48 | Output::new(p.P0_13, Level::Low, OutputDrive::Standard), | ||
| 49 | OutputChannelPolarity::Toggle, | ||
| 50 | ); | ||
| 51 | |||
| 52 | let led2 = OutputChannel::new( | ||
| 53 | p.GPIOTE_CH5, | ||
| 54 | Output::new(p.P0_14, Level::Low, OutputDrive::Standard), | ||
| 55 | OutputChannelPolarity::Toggle, | ||
| 56 | ); | ||
| 57 | |||
| 58 | let mut ppi = Ppi::new(p.PPI_CH0); | ||
| 59 | ppi.set_event(button1.event_in()); | ||
| 60 | ppi.set_task(led1.task_out()); | ||
| 61 | ppi.enable(); | ||
| 62 | |||
| 63 | let mut ppi = Ppi::new(p.PPI_CH1); | ||
| 64 | ppi.set_event(button2.event_in()); | ||
| 65 | ppi.set_task(led1.task_clr()); | ||
| 66 | ppi.enable(); | ||
| 67 | |||
| 68 | let mut ppi = Ppi::new(p.PPI_CH2); | ||
| 69 | ppi.set_event(button3.event_in()); | ||
| 70 | ppi.set_task(led1.task_set()); | ||
| 71 | ppi.enable(); | ||
| 72 | |||
| 73 | let mut ppi = Ppi::new(p.PPI_CH3); | ||
| 74 | ppi.set_event(button4.event_in()); | ||
| 75 | ppi.set_task(led1.task_out()); | ||
| 76 | ppi.set_fork_task(led2.task_out()); | ||
| 77 | ppi.enable(); | ||
| 78 | |||
| 79 | info!("PPI setup!"); | ||
| 80 | info!("Press button 1 to toggle LED 1"); | ||
| 81 | info!("Press button 2 to turn on LED 1"); | ||
| 82 | info!("Press button 3 to turn off LED 1"); | ||
| 83 | info!("Press button 4 to toggle LEDs 1 and 2"); | ||
| 84 | |||
| 85 | // Block forever so the above drivers don't get dropped | ||
| 86 | pending::<()>().await; | ||
| 87 | } | ||
diff --git a/examples/nrf/src/bin/pwm.rs b/examples/nrf/src/bin/pwm.rs new file mode 100644 index 000000000..d2874a29b --- /dev/null +++ b/examples/nrf/src/bin/pwm.rs | |||
| @@ -0,0 +1,104 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(min_type_alias_impl_trait)] | ||
| 4 | #![feature(impl_trait_in_bindings)] | ||
| 5 | #![feature(type_alias_impl_trait)] | ||
| 6 | #![allow(incomplete_features)] | ||
| 7 | |||
| 8 | #[path = "../example_common.rs"] | ||
| 9 | mod example_common; | ||
| 10 | use defmt::{panic, *}; | ||
| 11 | use embassy::executor::Spawner; | ||
| 12 | use embassy::time::{Duration, Timer}; | ||
| 13 | use embassy_nrf::pwm::{Prescaler, Pwm}; | ||
| 14 | use embassy_nrf::{interrupt, Peripherals}; | ||
| 15 | |||
| 16 | // for i in range(1024): print(int((math.sin(i/512*math.pi)*0.4+0.5)**2*32767), ', ', end='') | ||
| 17 | static DUTY: [u16; 1024] = [ | ||
| 18 | 8191, 8272, 8353, 8434, 8516, 8598, 8681, 8764, 8847, 8931, 9015, 9099, 9184, 9269, 9354, 9440, | ||
| 19 | 9526, 9613, 9700, 9787, 9874, 9962, 10050, 10139, 10227, 10316, 10406, 10495, 10585, 10675, | ||
| 20 | 10766, 10857, 10948, 11039, 11131, 11223, 11315, 11407, 11500, 11592, 11685, 11779, 11872, | ||
| 21 | 11966, 12060, 12154, 12248, 12343, 12438, 12533, 12628, 12723, 12818, 12914, 13010, 13106, | ||
| 22 | 13202, 13298, 13394, 13491, 13587, 13684, 13781, 13878, 13975, 14072, 14169, 14266, 14364, | ||
| 23 | 14461, 14558, 14656, 14754, 14851, 14949, 15046, 15144, 15242, 15339, 15437, 15535, 15632, | ||
| 24 | 15730, 15828, 15925, 16023, 16120, 16218, 16315, 16412, 16510, 16607, 16704, 16801, 16898, | ||
| 25 | 16995, 17091, 17188, 17284, 17380, 17477, 17572, 17668, 17764, 17859, 17955, 18050, 18145, | ||
| 26 | 18239, 18334, 18428, 18522, 18616, 18710, 18803, 18896, 18989, 19082, 19174, 19266, 19358, | ||
| 27 | 19449, 19540, 19631, 19722, 19812, 19902, 19991, 20081, 20169, 20258, 20346, 20434, 20521, | ||
| 28 | 20608, 20695, 20781, 20867, 20952, 21037, 21122, 21206, 21290, 21373, 21456, 21538, 21620, | ||
| 29 | 21701, 21782, 21863, 21943, 22022, 22101, 22179, 22257, 22335, 22412, 22488, 22564, 22639, | ||
| 30 | 22714, 22788, 22861, 22934, 23007, 23079, 23150, 23220, 23290, 23360, 23429, 23497, 23564, | ||
| 31 | 23631, 23698, 23763, 23828, 23892, 23956, 24019, 24081, 24143, 24204, 24264, 24324, 24383, | ||
| 32 | 24441, 24499, 24555, 24611, 24667, 24721, 24775, 24828, 24881, 24933, 24983, 25034, 25083, | ||
| 33 | 25132, 25180, 25227, 25273, 25319, 25363, 25407, 25451, 25493, 25535, 25575, 25615, 25655, | ||
| 34 | 25693, 25731, 25767, 25803, 25838, 25873, 25906, 25939, 25971, 26002, 26032, 26061, 26089, | ||
| 35 | 26117, 26144, 26170, 26195, 26219, 26242, 26264, 26286, 26307, 26327, 26346, 26364, 26381, | ||
| 36 | 26397, 26413, 26427, 26441, 26454, 26466, 26477, 26487, 26496, 26505, 26512, 26519, 26525, | ||
| 37 | 26530, 26534, 26537, 26539, 26540, 26541, 26540, 26539, 26537, 26534, 26530, 26525, 26519, | ||
| 38 | 26512, 26505, 26496, 26487, 26477, 26466, 26454, 26441, 26427, 26413, 26397, 26381, 26364, | ||
| 39 | 26346, 26327, 26307, 26286, 26264, 26242, 26219, 26195, 26170, 26144, 26117, 26089, 26061, | ||
| 40 | 26032, 26002, 25971, 25939, 25906, 25873, 25838, 25803, 25767, 25731, 25693, 25655, 25615, | ||
| 41 | 25575, 25535, 25493, 25451, 25407, 25363, 25319, 25273, 25227, 25180, 25132, 25083, 25034, | ||
| 42 | 24983, 24933, 24881, 24828, 24775, 24721, 24667, 24611, 24555, 24499, 24441, 24383, 24324, | ||
| 43 | 24264, 24204, 24143, 24081, 24019, 23956, 23892, 23828, 23763, 23698, 23631, 23564, 23497, | ||
| 44 | 23429, 23360, 23290, 23220, 23150, 23079, 23007, 22934, 22861, 22788, 22714, 22639, 22564, | ||
| 45 | 22488, 22412, 22335, 22257, 22179, 22101, 22022, 21943, 21863, 21782, 21701, 21620, 21538, | ||
| 46 | 21456, 21373, 21290, 21206, 21122, 21037, 20952, 20867, 20781, 20695, 20608, 20521, 20434, | ||
| 47 | 20346, 20258, 20169, 20081, 19991, 19902, 19812, 19722, 19631, 19540, 19449, 19358, 19266, | ||
| 48 | 19174, 19082, 18989, 18896, 18803, 18710, 18616, 18522, 18428, 18334, 18239, 18145, 18050, | ||
| 49 | 17955, 17859, 17764, 17668, 17572, 17477, 17380, 17284, 17188, 17091, 16995, 16898, 16801, | ||
| 50 | 16704, 16607, 16510, 16412, 16315, 16218, 16120, 16023, 15925, 15828, 15730, 15632, 15535, | ||
| 51 | 15437, 15339, 15242, 15144, 15046, 14949, 14851, 14754, 14656, 14558, 14461, 14364, 14266, | ||
| 52 | 14169, 14072, 13975, 13878, 13781, 13684, 13587, 13491, 13394, 13298, 13202, 13106, 13010, | ||
| 53 | 12914, 12818, 12723, 12628, 12533, 12438, 12343, 12248, 12154, 12060, 11966, 11872, 11779, | ||
| 54 | 11685, 11592, 11500, 11407, 11315, 11223, 11131, 11039, 10948, 10857, 10766, 10675, 10585, | ||
| 55 | 10495, 10406, 10316, 10227, 10139, 10050, 9962, 9874, 9787, 9700, 9613, 9526, 9440, 9354, 9269, | ||
| 56 | 9184, 9099, 9015, 8931, 8847, 8764, 8681, 8598, 8516, 8434, 8353, 8272, 8191, 8111, 8031, 7952, | ||
| 57 | 7873, 7794, 7716, 7638, 7561, 7484, 7407, 7331, 7255, 7180, 7105, 7031, 6957, 6883, 6810, 6738, | ||
| 58 | 6665, 6594, 6522, 6451, 6381, 6311, 6241, 6172, 6104, 6036, 5968, 5901, 5834, 5767, 5702, 5636, | ||
| 59 | 5571, 5507, 5443, 5379, 5316, 5253, 5191, 5130, 5068, 5008, 4947, 4888, 4828, 4769, 4711, 4653, | ||
| 60 | 4596, 4539, 4482, 4426, 4371, 4316, 4261, 4207, 4153, 4100, 4047, 3995, 3943, 3892, 3841, 3791, | ||
| 61 | 3741, 3691, 3642, 3594, 3546, 3498, 3451, 3404, 3358, 3312, 3267, 3222, 3178, 3134, 3090, 3047, | ||
| 62 | 3005, 2962, 2921, 2879, 2839, 2798, 2758, 2719, 2680, 2641, 2603, 2565, 2528, 2491, 2454, 2418, | ||
| 63 | 2382, 2347, 2312, 2278, 2244, 2210, 2177, 2144, 2112, 2080, 2048, 2017, 1986, 1956, 1926, 1896, | ||
| 64 | 1867, 1838, 1810, 1781, 1754, 1726, 1699, 1673, 1646, 1620, 1595, 1570, 1545, 1520, 1496, 1472, | ||
| 65 | 1449, 1426, 1403, 1380, 1358, 1336, 1315, 1294, 1273, 1252, 1232, 1212, 1192, 1173, 1154, 1135, | ||
| 66 | 1117, 1099, 1081, 1063, 1046, 1029, 1012, 996, 980, 964, 948, 933, 918, 903, 888, 874, 860, | ||
| 67 | 846, 833, 819, 806, 793, 781, 768, 756, 744, 733, 721, 710, 699, 688, 677, 667, 657, 647, 637, | ||
| 68 | 627, 618, 609, 599, 591, 582, 574, 565, 557, 549, 541, 534, 526, 519, 512, 505, 498, 492, 485, | ||
| 69 | 479, 473, 467, 461, 455, 450, 444, 439, 434, 429, 424, 419, 415, 410, 406, 402, 398, 394, 390, | ||
| 70 | 386, 383, 379, 376, 373, 370, 367, 364, 361, 359, 356, 354, 351, 349, 347, 345, 343, 342, 340, | ||
| 71 | 338, 337, 336, 334, 333, 332, 331, 330, 330, 329, 328, 328, 328, 327, 327, 327, 327, 327, 328, | ||
| 72 | 328, 328, 329, 330, 330, 331, 332, 333, 334, 336, 337, 338, 340, 342, 343, 345, 347, 349, 351, | ||
| 73 | 354, 356, 359, 361, 364, 367, 370, 373, 376, 379, 383, 386, 390, 394, 398, 402, 406, 410, 415, | ||
| 74 | 419, 424, 429, 434, 439, 444, 450, 455, 461, 467, 473, 479, 485, 492, 498, 505, 512, 519, 526, | ||
| 75 | 534, 541, 549, 557, 565, 574, 582, 591, 599, 609, 618, 627, 637, 647, 657, 667, 677, 688, 699, | ||
| 76 | 710, 721, 733, 744, 756, 768, 781, 793, 806, 819, 833, 846, 860, 874, 888, 903, 918, 933, 948, | ||
| 77 | 964, 980, 996, 1012, 1029, 1046, 1063, 1081, 1099, 1117, 1135, 1154, 1173, 1192, 1212, 1232, | ||
| 78 | 1252, 1273, 1294, 1315, 1336, 1358, 1380, 1403, 1426, 1449, 1472, 1496, 1520, 1545, 1570, 1595, | ||
| 79 | 1620, 1646, 1673, 1699, 1726, 1754, 1781, 1810, 1838, 1867, 1896, 1926, 1956, 1986, 2017, 2048, | ||
| 80 | 2080, 2112, 2144, 2177, 2210, 2244, 2278, 2312, 2347, 2382, 2418, 2454, 2491, 2528, 2565, 2603, | ||
| 81 | 2641, 2680, 2719, 2758, 2798, 2839, 2879, 2921, 2962, 3005, 3047, 3090, 3134, 3178, 3222, 3267, | ||
| 82 | 3312, 3358, 3404, 3451, 3498, 3546, 3594, 3642, 3691, 3741, 3791, 3841, 3892, 3943, 3995, 4047, | ||
| 83 | 4100, 4153, 4207, 4261, 4316, 4371, 4426, 4482, 4539, 4596, 4653, 4711, 4769, 4828, 4888, 4947, | ||
| 84 | 5008, 5068, 5130, 5191, 5253, 5316, 5379, 5443, 5507, 5571, 5636, 5702, 5767, 5834, 5901, 5968, | ||
| 85 | 6036, 6104, 6172, 6241, 6311, 6381, 6451, 6522, 6594, 6665, 6738, 6810, 6883, 6957, 7031, 7105, | ||
| 86 | 7180, 7255, 7331, 7407, 7484, 7561, 7638, 7716, 7794, 7873, 7952, 8031, 8111, | ||
| 87 | ]; | ||
| 88 | |||
| 89 | #[embassy::main] | ||
| 90 | async fn main(_spawner: Spawner, p: Peripherals) { | ||
| 91 | let pwm = Pwm::new(p.PWM0, p.P0_13, p.P0_14, p.P0_16, p.P0_15); | ||
| 92 | pwm.set_prescaler(Prescaler::Div1); | ||
| 93 | info!("pwm initialized!"); | ||
| 94 | |||
| 95 | let mut i = 0; | ||
| 96 | loop { | ||
| 97 | i += 1; | ||
| 98 | pwm.set_duty(0, DUTY[i % 1024]); | ||
| 99 | pwm.set_duty(1, DUTY[(i + 256) % 1024]); | ||
| 100 | pwm.set_duty(2, DUTY[(i + 512) % 1024]); | ||
| 101 | pwm.set_duty(3, DUTY[(i + 768) % 1024]); | ||
| 102 | Timer::after(Duration::from_millis(3)).await; | ||
| 103 | } | ||
| 104 | } | ||
diff --git a/examples/nrf/src/bin/qspi.rs b/examples/nrf/src/bin/qspi.rs new file mode 100644 index 000000000..6e49887a4 --- /dev/null +++ b/examples/nrf/src/bin/qspi.rs | |||
| @@ -0,0 +1,84 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(min_type_alias_impl_trait)] | ||
| 4 | #![feature(impl_trait_in_bindings)] | ||
| 5 | #![feature(type_alias_impl_trait)] | ||
| 6 | #![allow(incomplete_features)] | ||
| 7 | |||
| 8 | #[path = "../example_common.rs"] | ||
| 9 | mod example_common; | ||
| 10 | |||
| 11 | use defmt::{assert_eq, panic}; | ||
| 12 | use embassy::executor::Spawner; | ||
| 13 | use embassy::traits::flash::Flash; | ||
| 14 | use embassy_nrf::Peripherals; | ||
| 15 | use embassy_nrf::{interrupt, qspi}; | ||
| 16 | use example_common::*; | ||
| 17 | |||
| 18 | const PAGE_SIZE: usize = 4096; | ||
| 19 | |||
| 20 | // Workaround for alignment requirements. | ||
| 21 | // Nicer API will probably come in the future. | ||
| 22 | #[repr(C, align(4))] | ||
| 23 | struct AlignedBuf([u8; 4096]); | ||
| 24 | |||
| 25 | #[embassy::main] | ||
| 26 | async fn main(_spawner: Spawner, p: Peripherals) { | ||
| 27 | // Config for the MX25R64 present in the nRF52840 DK | ||
| 28 | let mut config = qspi::Config::default(); | ||
| 29 | config.read_opcode = qspi::ReadOpcode::READ4IO; | ||
| 30 | config.write_opcode = qspi::WriteOpcode::PP4IO; | ||
| 31 | config.write_page_size = qspi::WritePageSize::_256BYTES; | ||
| 32 | |||
| 33 | let irq = interrupt::take!(QSPI); | ||
| 34 | let mut q = qspi::Qspi::new( | ||
| 35 | p.QSPI, irq, p.P0_19, p.P0_17, p.P0_20, p.P0_21, p.P0_22, p.P0_23, config, | ||
| 36 | ) | ||
| 37 | .await; | ||
| 38 | |||
| 39 | let mut id = [1; 3]; | ||
| 40 | q.custom_instruction(0x9F, &[], &mut id).await.unwrap(); | ||
| 41 | info!("id: {}", id); | ||
| 42 | |||
| 43 | // Read status register | ||
| 44 | let mut status = [4; 1]; | ||
| 45 | q.custom_instruction(0x05, &[], &mut status).await.unwrap(); | ||
| 46 | |||
| 47 | info!("status: {:?}", status[0]); | ||
| 48 | |||
| 49 | if status[0] & 0x40 == 0 { | ||
| 50 | status[0] |= 0x40; | ||
| 51 | |||
| 52 | q.custom_instruction(0x01, &status, &mut []).await.unwrap(); | ||
| 53 | |||
| 54 | info!("enabled quad in status"); | ||
| 55 | } | ||
| 56 | |||
| 57 | let mut buf = AlignedBuf([0u8; PAGE_SIZE]); | ||
| 58 | |||
| 59 | let pattern = |a: u32| (a ^ (a >> 8) ^ (a >> 16) ^ (a >> 24)) as u8; | ||
| 60 | |||
| 61 | for i in 0..8 { | ||
| 62 | info!("page {:?}: erasing... ", i); | ||
| 63 | q.erase(i * PAGE_SIZE).await.unwrap(); | ||
| 64 | |||
| 65 | for j in 0..PAGE_SIZE { | ||
| 66 | buf.0[j] = pattern((j + i * PAGE_SIZE) as u32); | ||
| 67 | } | ||
| 68 | |||
| 69 | info!("programming..."); | ||
| 70 | q.write(i * PAGE_SIZE, &buf.0).await.unwrap(); | ||
| 71 | } | ||
| 72 | |||
| 73 | for i in 0..8 { | ||
| 74 | info!("page {:?}: reading... ", i); | ||
| 75 | q.read(i * PAGE_SIZE, &mut buf.0).await.unwrap(); | ||
| 76 | |||
| 77 | info!("verifying..."); | ||
| 78 | for j in 0..PAGE_SIZE { | ||
| 79 | assert_eq!(buf.0[j], pattern((j + i * PAGE_SIZE) as u32)); | ||
| 80 | } | ||
| 81 | } | ||
| 82 | |||
| 83 | info!("done!") | ||
| 84 | } | ||
diff --git a/examples/nrf/src/bin/qspi_lowpower.rs b/examples/nrf/src/bin/qspi_lowpower.rs new file mode 100644 index 000000000..ece3243b6 --- /dev/null +++ b/examples/nrf/src/bin/qspi_lowpower.rs | |||
| @@ -0,0 +1,85 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(min_type_alias_impl_trait)] | ||
| 4 | #![feature(impl_trait_in_bindings)] | ||
| 5 | #![feature(type_alias_impl_trait)] | ||
| 6 | #![allow(incomplete_features)] | ||
| 7 | |||
| 8 | #[path = "../example_common.rs"] | ||
| 9 | mod example_common; | ||
| 10 | |||
| 11 | use core::mem; | ||
| 12 | use defmt::panic; | ||
| 13 | use embassy::executor::Spawner; | ||
| 14 | use embassy::time::{Duration, Timer}; | ||
| 15 | use embassy::traits::flash::Flash; | ||
| 16 | use embassy_nrf::Peripherals; | ||
| 17 | use embassy_nrf::{interrupt, qspi}; | ||
| 18 | use example_common::*; | ||
| 19 | |||
| 20 | // Workaround for alignment requirements. | ||
| 21 | // Nicer API will probably come in the future. | ||
| 22 | #[repr(C, align(4))] | ||
| 23 | struct AlignedBuf([u8; 64]); | ||
| 24 | |||
| 25 | #[embassy::main] | ||
| 26 | async fn main(_spawner: Spawner, mut p: Peripherals) { | ||
| 27 | let mut irq = interrupt::take!(QSPI); | ||
| 28 | |||
| 29 | loop { | ||
| 30 | // Config for the MX25R64 present in the nRF52840 DK | ||
| 31 | let mut config = qspi::Config::default(); | ||
| 32 | config.read_opcode = qspi::ReadOpcode::READ4IO; | ||
| 33 | config.write_opcode = qspi::WriteOpcode::PP4IO; | ||
| 34 | config.write_page_size = qspi::WritePageSize::_256BYTES; | ||
| 35 | config.deep_power_down = Some(qspi::DeepPowerDownConfig { | ||
| 36 | enter_time: 3, // tDP = 30uS | ||
| 37 | exit_time: 3, // tRDP = 35uS | ||
| 38 | }); | ||
| 39 | |||
| 40 | let mut q = qspi::Qspi::new( | ||
| 41 | &mut p.QSPI, | ||
| 42 | &mut irq, | ||
| 43 | &mut p.P0_19, | ||
| 44 | &mut p.P0_17, | ||
| 45 | &mut p.P0_20, | ||
| 46 | &mut p.P0_21, | ||
| 47 | &mut p.P0_22, | ||
| 48 | &mut p.P0_23, | ||
| 49 | config, | ||
| 50 | ) | ||
| 51 | .await; | ||
| 52 | |||
| 53 | let mut id = [1; 3]; | ||
| 54 | q.custom_instruction(0x9F, &[], &mut id).await.unwrap(); | ||
| 55 | info!("id: {}", id); | ||
| 56 | |||
| 57 | // Read status register | ||
| 58 | let mut status = [4; 1]; | ||
| 59 | q.custom_instruction(0x05, &[], &mut status).await.unwrap(); | ||
| 60 | |||
| 61 | info!("status: {:?}", status[0]); | ||
| 62 | |||
| 63 | if status[0] & 0x40 == 0 { | ||
| 64 | status[0] |= 0x40; | ||
| 65 | |||
| 66 | q.custom_instruction(0x01, &status, &mut []).await.unwrap(); | ||
| 67 | |||
| 68 | info!("enabled quad in status"); | ||
| 69 | } | ||
| 70 | |||
| 71 | let mut buf = AlignedBuf([0u8; 64]); | ||
| 72 | |||
| 73 | info!("reading..."); | ||
| 74 | q.read(0, &mut buf.0).await.unwrap(); | ||
| 75 | info!("read: {=[u8]:x}", buf.0); | ||
| 76 | |||
| 77 | // Drop the QSPI instance. This disables the peripehral and deconfigures the pins. | ||
| 78 | // This clears the borrow on the singletons, so they can now be used again. | ||
| 79 | mem::drop(q); | ||
| 80 | |||
| 81 | // Sleep for 1 second. The executor ensures the core sleeps with a WFE when it has nothing to do. | ||
| 82 | // During this sleep, the nRF chip should only use ~3uA | ||
| 83 | Timer::after(Duration::from_secs(1)).await; | ||
| 84 | } | ||
| 85 | } | ||
diff --git a/examples/nrf/src/bin/raw_spawn.rs b/examples/nrf/src/bin/raw_spawn.rs new file mode 100644 index 000000000..78de7b100 --- /dev/null +++ b/examples/nrf/src/bin/raw_spawn.rs | |||
| @@ -0,0 +1,65 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | #[path = "../example_common.rs"] | ||
| 5 | mod example_common; | ||
| 6 | use example_common::*; | ||
| 7 | |||
| 8 | use core::mem; | ||
| 9 | use cortex_m_rt::entry; | ||
| 10 | use defmt::panic; | ||
| 11 | use embassy::executor::raw::Task; | ||
| 12 | use embassy::executor::Executor; | ||
| 13 | use embassy::time::{Duration, Timer}; | ||
| 14 | use embassy::util::Forever; | ||
| 15 | use embassy_nrf::peripherals; | ||
| 16 | use embassy_nrf::{interrupt, rtc}; | ||
| 17 | |||
| 18 | async fn run1() { | ||
| 19 | loop { | ||
| 20 | info!("BIG INFREQUENT TICK"); | ||
| 21 | Timer::after(Duration::from_ticks(64000)).await; | ||
| 22 | } | ||
| 23 | } | ||
| 24 | |||
| 25 | async fn run2() { | ||
| 26 | loop { | ||
| 27 | info!("tick"); | ||
| 28 | Timer::after(Duration::from_ticks(13000)).await; | ||
| 29 | } | ||
| 30 | } | ||
| 31 | |||
| 32 | static RTC: Forever<rtc::RTC<peripherals::RTC1>> = Forever::new(); | ||
| 33 | static ALARM: Forever<rtc::Alarm<peripherals::RTC1>> = Forever::new(); | ||
| 34 | static EXECUTOR: Forever<Executor> = Forever::new(); | ||
| 35 | |||
| 36 | #[entry] | ||
| 37 | fn main() -> ! { | ||
| 38 | info!("Hello World!"); | ||
| 39 | |||
| 40 | let p = embassy_nrf::init(Default::default()); | ||
| 41 | |||
| 42 | let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1))); | ||
| 43 | rtc.start(); | ||
| 44 | unsafe { embassy::time::set_clock(rtc) }; | ||
| 45 | |||
| 46 | let alarm = ALARM.put(rtc.alarm0()); | ||
| 47 | let executor = EXECUTOR.put(Executor::new()); | ||
| 48 | executor.set_alarm(alarm); | ||
| 49 | |||
| 50 | let run1_task = Task::new(); | ||
| 51 | let run2_task = Task::new(); | ||
| 52 | |||
| 53 | // Safety: these variables do live forever if main never returns. | ||
| 54 | let run1_task = unsafe { make_static(&run1_task) }; | ||
| 55 | let run2_task = unsafe { make_static(&run2_task) }; | ||
| 56 | |||
| 57 | executor.run(|spawner| { | ||
| 58 | unwrap!(spawner.spawn(run1_task.spawn(|| run1()))); | ||
| 59 | unwrap!(spawner.spawn(run2_task.spawn(|| run2()))); | ||
| 60 | }); | ||
| 61 | } | ||
| 62 | |||
| 63 | unsafe fn make_static<T>(t: &T) -> &'static T { | ||
| 64 | mem::transmute(t) | ||
| 65 | } | ||
diff --git a/examples/nrf/src/bin/spim.rs b/examples/nrf/src/bin/spim.rs new file mode 100644 index 000000000..c42cc6015 --- /dev/null +++ b/examples/nrf/src/bin/spim.rs | |||
| @@ -0,0 +1,76 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(min_type_alias_impl_trait)] | ||
| 4 | #![feature(impl_trait_in_bindings)] | ||
| 5 | #![feature(type_alias_impl_trait)] | ||
| 6 | #![allow(incomplete_features)] | ||
| 7 | |||
| 8 | #[path = "../example_common.rs"] | ||
| 9 | mod example_common; | ||
| 10 | |||
| 11 | use defmt::panic; | ||
| 12 | use embassy::executor::Spawner; | ||
| 13 | use embassy_nrf::gpio::{Level, Output, OutputDrive}; | ||
| 14 | use embassy_nrf::Peripherals; | ||
| 15 | use embassy_nrf::{interrupt, spim}; | ||
| 16 | use embassy_traits::spi::FullDuplex; | ||
| 17 | use embedded_hal::digital::v2::*; | ||
| 18 | use example_common::*; | ||
| 19 | |||
| 20 | #[embassy::main] | ||
| 21 | async fn main(_spawner: Spawner, p: Peripherals) { | ||
| 22 | info!("running!"); | ||
| 23 | |||
| 24 | let mut config = spim::Config::default(); | ||
| 25 | config.frequency = spim::Frequency::M16; | ||
| 26 | |||
| 27 | let irq = interrupt::take!(SPIM3); | ||
| 28 | let mut spim = spim::Spim::new(p.SPI3, irq, p.P0_29, p.P0_28, p.P0_30, config); | ||
| 29 | |||
| 30 | let mut ncs = Output::new(p.P0_31, Level::High, OutputDrive::Standard); | ||
| 31 | |||
| 32 | // Example on how to talk to an ENC28J60 chip | ||
| 33 | |||
| 34 | // softreset | ||
| 35 | cortex_m::asm::delay(10); | ||
| 36 | ncs.set_low().unwrap(); | ||
| 37 | cortex_m::asm::delay(5); | ||
| 38 | let tx = [0xFF]; | ||
| 39 | unwrap!(spim.read_write(&mut [], &tx).await); | ||
| 40 | cortex_m::asm::delay(10); | ||
| 41 | ncs.set_high().unwrap(); | ||
| 42 | |||
| 43 | cortex_m::asm::delay(100000); | ||
| 44 | |||
| 45 | let mut rx = [0; 2]; | ||
| 46 | |||
| 47 | // read ESTAT | ||
| 48 | cortex_m::asm::delay(5000); | ||
| 49 | ncs.set_low().unwrap(); | ||
| 50 | cortex_m::asm::delay(5000); | ||
| 51 | let tx = [0b000_11101, 0]; | ||
| 52 | unwrap!(spim.read_write(&mut rx, &tx).await); | ||
| 53 | cortex_m::asm::delay(5000); | ||
| 54 | ncs.set_high().unwrap(); | ||
| 55 | info!("estat: {=[?]}", rx); | ||
| 56 | |||
| 57 | // Switch to bank 3 | ||
| 58 | cortex_m::asm::delay(10); | ||
| 59 | ncs.set_low().unwrap(); | ||
| 60 | cortex_m::asm::delay(5); | ||
| 61 | let tx = [0b100_11111, 0b11]; | ||
| 62 | unwrap!(spim.read_write(&mut rx, &tx).await); | ||
| 63 | cortex_m::asm::delay(10); | ||
| 64 | ncs.set_high().unwrap(); | ||
| 65 | |||
| 66 | // read EREVID | ||
| 67 | cortex_m::asm::delay(10); | ||
| 68 | ncs.set_low().unwrap(); | ||
| 69 | cortex_m::asm::delay(5); | ||
| 70 | let tx = [0b000_10010, 0]; | ||
| 71 | unwrap!(spim.read_write(&mut rx, &tx).await); | ||
| 72 | cortex_m::asm::delay(10); | ||
| 73 | ncs.set_high().unwrap(); | ||
| 74 | |||
| 75 | info!("erevid: {=[?]}", rx); | ||
| 76 | } | ||
diff --git a/examples/nrf/src/bin/timer.rs b/examples/nrf/src/bin/timer.rs new file mode 100644 index 000000000..43f6d76ce --- /dev/null +++ b/examples/nrf/src/bin/timer.rs | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(min_type_alias_impl_trait)] | ||
| 4 | #![feature(impl_trait_in_bindings)] | ||
| 5 | #![feature(type_alias_impl_trait)] | ||
| 6 | #![allow(incomplete_features)] | ||
| 7 | |||
| 8 | #[path = "../example_common.rs"] | ||
| 9 | mod example_common; | ||
| 10 | use embassy_nrf::Peripherals; | ||
| 11 | use example_common::*; | ||
| 12 | |||
| 13 | use defmt::panic; | ||
| 14 | use embassy::executor::Spawner; | ||
| 15 | use embassy::time::{Duration, Timer}; | ||
| 16 | |||
| 17 | #[embassy::task] | ||
| 18 | async fn run1() { | ||
| 19 | loop { | ||
| 20 | info!("BIG INFREQUENT TICK"); | ||
| 21 | Timer::after(Duration::from_ticks(64000)).await; | ||
| 22 | } | ||
| 23 | } | ||
| 24 | |||
| 25 | #[embassy::task] | ||
| 26 | async fn run2() { | ||
| 27 | loop { | ||
| 28 | info!("tick"); | ||
| 29 | Timer::after(Duration::from_ticks(13000)).await; | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
| 33 | #[embassy::main] | ||
| 34 | async fn main(spawner: Spawner, _p: Peripherals) { | ||
| 35 | unwrap!(spawner.spawn(run1())); | ||
| 36 | unwrap!(spawner.spawn(run2())); | ||
| 37 | } | ||
diff --git a/examples/nrf/src/bin/twim.rs b/examples/nrf/src/bin/twim.rs new file mode 100644 index 000000000..537cea160 --- /dev/null +++ b/examples/nrf/src/bin/twim.rs | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | //! Example on how to read a 24C/24LC i2c eeprom. | ||
| 2 | //! | ||
| 3 | //! Connect SDA to P0.03, SCL to P0.04 | ||
| 4 | |||
| 5 | #![no_std] | ||
| 6 | #![no_main] | ||
| 7 | #![feature(min_type_alias_impl_trait)] | ||
| 8 | #![feature(impl_trait_in_bindings)] | ||
| 9 | #![feature(type_alias_impl_trait)] | ||
| 10 | #![allow(incomplete_features)] | ||
| 11 | |||
| 12 | #[path = "../example_common.rs"] | ||
| 13 | mod example_common; | ||
| 14 | |||
| 15 | use defmt::{panic, *}; | ||
| 16 | use embassy::executor::Spawner; | ||
| 17 | use embassy_nrf::twim::{self, Twim}; | ||
| 18 | use embassy_nrf::{interrupt, Peripherals}; | ||
| 19 | |||
| 20 | const ADDRESS: u8 = 0x50; | ||
| 21 | |||
| 22 | #[embassy::main] | ||
| 23 | async fn main(_spawner: Spawner, p: Peripherals) { | ||
| 24 | info!("Initializing TWI..."); | ||
| 25 | let config = twim::Config::default(); | ||
| 26 | let irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||
| 27 | let mut twi = Twim::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config); | ||
| 28 | |||
| 29 | info!("Reading..."); | ||
| 30 | |||
| 31 | let mut buf = [0u8; 16]; | ||
| 32 | twi.write_then_read(ADDRESS, &mut [0x00], &mut buf).unwrap(); | ||
| 33 | |||
| 34 | info!("Read: {=[u8]:x}", buf); | ||
| 35 | } | ||
diff --git a/examples/nrf/src/bin/twim_lowpower.rs b/examples/nrf/src/bin/twim_lowpower.rs new file mode 100644 index 000000000..1cd66a18e --- /dev/null +++ b/examples/nrf/src/bin/twim_lowpower.rs | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | //! Example on how to read a 24C/24LC i2c eeprom with low power consumption. | ||
| 2 | //! The eeprom is read every 1 second, while ensuring lowest possible power while | ||
| 3 | //! sleeping between reads. | ||
| 4 | //! | ||
| 5 | //! Connect SDA to P0.03, SCL to P0.04 | ||
| 6 | |||
| 7 | #![no_std] | ||
| 8 | #![no_main] | ||
| 9 | #![feature(min_type_alias_impl_trait)] | ||
| 10 | #![feature(impl_trait_in_bindings)] | ||
| 11 | #![feature(type_alias_impl_trait)] | ||
| 12 | #![allow(incomplete_features)] | ||
| 13 | |||
| 14 | #[path = "../example_common.rs"] | ||
| 15 | mod example_common; | ||
| 16 | |||
| 17 | use core::mem; | ||
| 18 | |||
| 19 | use defmt::{panic, *}; | ||
| 20 | use embassy::executor::Spawner; | ||
| 21 | use embassy::time::{Duration, Timer}; | ||
| 22 | use embassy_nrf::twim::{self, Twim}; | ||
| 23 | use embassy_nrf::{interrupt, Peripherals}; | ||
| 24 | |||
| 25 | const ADDRESS: u8 = 0x50; | ||
| 26 | |||
| 27 | #[embassy::main] | ||
| 28 | async fn main(_spawner: Spawner, mut p: Peripherals) { | ||
| 29 | info!("Started!"); | ||
| 30 | let mut irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||
| 31 | |||
| 32 | loop { | ||
| 33 | info!("Initializing TWI..."); | ||
| 34 | let config = twim::Config::default(); | ||
| 35 | |||
| 36 | // Create the TWIM instance with borrowed singletons, so they're not consumed. | ||
| 37 | let mut twi = Twim::new(&mut p.TWISPI0, &mut irq, &mut p.P0_03, &mut p.P0_04, config); | ||
| 38 | |||
| 39 | info!("Reading..."); | ||
| 40 | |||
| 41 | let mut buf = [0u8; 16]; | ||
| 42 | twi.write_then_read(ADDRESS, &mut [0x00], &mut buf).unwrap(); | ||
| 43 | |||
| 44 | info!("Read: {=[u8]:x}", buf); | ||
| 45 | |||
| 46 | // Drop the TWIM instance. This disables the peripehral and deconfigures the pins. | ||
| 47 | // This clears the borrow on the singletons, so they can now be used again. | ||
| 48 | mem::drop(twi); | ||
| 49 | |||
| 50 | // Sleep for 1 second. The executor ensures the core sleeps with a WFE when it has nothing to do. | ||
| 51 | // During this sleep, the nRF chip should only use ~3uA | ||
| 52 | Timer::after(Duration::from_secs(1)).await; | ||
| 53 | } | ||
| 54 | } | ||
diff --git a/examples/nrf/src/bin/uart.rs b/examples/nrf/src/bin/uart.rs new file mode 100644 index 000000000..e65e2fe51 --- /dev/null +++ b/examples/nrf/src/bin/uart.rs | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(min_type_alias_impl_trait)] | ||
| 4 | #![feature(impl_trait_in_bindings)] | ||
| 5 | #![feature(type_alias_impl_trait)] | ||
| 6 | #![allow(incomplete_features)] | ||
| 7 | |||
| 8 | #[path = "../example_common.rs"] | ||
| 9 | mod example_common; | ||
| 10 | use example_common::*; | ||
| 11 | |||
| 12 | use defmt::panic; | ||
| 13 | use embassy::executor::Spawner; | ||
| 14 | use embassy::traits::uart::{Read, Write}; | ||
| 15 | use embassy_nrf::gpio::NoPin; | ||
| 16 | use embassy_nrf::{interrupt, uarte, Peripherals}; | ||
| 17 | |||
| 18 | #[embassy::main] | ||
| 19 | async fn main(_spawner: Spawner, p: Peripherals) { | ||
| 20 | let mut config = uarte::Config::default(); | ||
| 21 | config.parity = uarte::Parity::EXCLUDED; | ||
| 22 | config.baudrate = uarte::Baudrate::BAUD115200; | ||
| 23 | |||
| 24 | let irq = interrupt::take!(UARTE0_UART0); | ||
| 25 | let mut uart = | ||
| 26 | unsafe { uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, NoPin, NoPin, config) }; | ||
| 27 | |||
| 28 | info!("uarte initialized!"); | ||
| 29 | |||
| 30 | // Message must be in SRAM | ||
| 31 | let mut buf = [0; 8]; | ||
| 32 | buf.copy_from_slice(b"Hello!\r\n"); | ||
| 33 | |||
| 34 | unwrap!(uart.write(&buf).await); | ||
| 35 | info!("wrote hello in uart!"); | ||
| 36 | |||
| 37 | loop { | ||
| 38 | info!("reading..."); | ||
| 39 | unwrap!(uart.read(&mut buf).await); | ||
| 40 | info!("writing..."); | ||
| 41 | unwrap!(uart.write(&buf).await); | ||
| 42 | } | ||
| 43 | } | ||
diff --git a/examples/nrf/src/bin/uart_idle.rs b/examples/nrf/src/bin/uart_idle.rs new file mode 100644 index 000000000..dc2c73433 --- /dev/null +++ b/examples/nrf/src/bin/uart_idle.rs | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(min_type_alias_impl_trait)] | ||
| 4 | #![feature(impl_trait_in_bindings)] | ||
| 5 | #![feature(type_alias_impl_trait)] | ||
| 6 | #![allow(incomplete_features)] | ||
| 7 | |||
| 8 | #[path = "../example_common.rs"] | ||
| 9 | mod example_common; | ||
| 10 | use embassy_traits::uart::ReadUntilIdle; | ||
| 11 | use example_common::*; | ||
| 12 | |||
| 13 | use defmt::panic; | ||
| 14 | use embassy::executor::Spawner; | ||
| 15 | use embassy::traits::uart::Write; | ||
| 16 | use embassy_nrf::gpio::NoPin; | ||
| 17 | use embassy_nrf::{interrupt, uarte, Peripherals}; | ||
| 18 | |||
| 19 | #[embassy::main] | ||
| 20 | async fn main(_spawner: Spawner, p: Peripherals) { | ||
| 21 | let mut config = uarte::Config::default(); | ||
| 22 | config.parity = uarte::Parity::EXCLUDED; | ||
| 23 | config.baudrate = uarte::Baudrate::BAUD115200; | ||
| 24 | |||
| 25 | let irq = interrupt::take!(UARTE0_UART0); | ||
| 26 | let mut uart = unsafe { | ||
| 27 | uarte::UarteWithIdle::new( | ||
| 28 | p.UARTE0, p.TIMER0, p.PPI_CH0, p.PPI_CH1, irq, p.P0_08, p.P0_06, NoPin, NoPin, config, | ||
| 29 | ) | ||
| 30 | }; | ||
| 31 | |||
| 32 | info!("uarte initialized!"); | ||
| 33 | |||
| 34 | // Message must be in SRAM | ||
| 35 | let mut buf = [0; 8]; | ||
| 36 | buf.copy_from_slice(b"Hello!\r\n"); | ||
| 37 | |||
| 38 | unwrap!(uart.write(&buf).await); | ||
| 39 | info!("wrote hello in uart!"); | ||
| 40 | |||
| 41 | loop { | ||
| 42 | info!("reading..."); | ||
| 43 | let n = unwrap!(uart.read_until_idle(&mut buf).await); | ||
| 44 | info!("got {} bytes", n); | ||
| 45 | } | ||
| 46 | } | ||
diff --git a/examples/nrf/src/example_common.rs b/examples/nrf/src/example_common.rs new file mode 100644 index 000000000..54d633837 --- /dev/null +++ b/examples/nrf/src/example_common.rs | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | #![macro_use] | ||
| 2 | |||
| 3 | use defmt_rtt as _; // global logger | ||
| 4 | use panic_probe as _; | ||
| 5 | |||
| 6 | pub use defmt::*; | ||
| 7 | |||
| 8 | use core::sync::atomic::{AtomicUsize, Ordering}; | ||
| 9 | |||
| 10 | defmt::timestamp! {"{=u64}", { | ||
| 11 | static COUNT: AtomicUsize = AtomicUsize::new(0); | ||
| 12 | // NOTE(no-CAS) `timestamps` runs with interrupts disabled | ||
| 13 | let n = COUNT.load(Ordering::Relaxed); | ||
| 14 | COUNT.store(n + 1, Ordering::Relaxed); | ||
| 15 | n as u64 | ||
| 16 | } | ||
| 17 | } | ||
