Reputation: 969
I'm trying to work on a nrf52-dk
board and trying to blink a light and get SPI working at the same time.
I could have one or the other working at a time, but not both at once.
I'm pretty sure that nrf52810_hal::pac::Peripherals::take()
shouldn't be called more than once, as its data would change all references, but it gets moved when I specify pins.
I'm unsure how I'd be able to make it work without passing in without using up the variable.
In the following example, the "PERIPHERALS are null" is always written out and the code panics because of the statements that are following it.
I do need to have the PERIPHERALS being "static mut", as I need them in another "thread", because it's an interrupt-called function, to which I'm unable to pass data.
#![no_main]
#![no_std]
#[allow(unused_extern_crates)]
use panic_halt as _;
use asm_delay::AsmDelay;
use cortex_m_rt::entry;
use cortex_m_semihosting::hprint;
use hal::gpio::Level;
use hal::pac::interrupt;
use nrf52810_hal as hal;
use nrf52810_hal::prelude::*;
use nrf52810_pac as nrf;
use nrf52810_pac::{Interrupt, NVIC};
static mut PERIPHERALS: Option<nrf::Peripherals> = None;
#[entry]
unsafe fn main() -> ! {
let p = hal::pac::Peripherals::take().unwrap();
let port0 = hal::gpio::p0::Parts::new(p.P0);
let spiclk = port0.p0_25.into_push_pull_output(Level::Low).degrade();
let spimosi = port0.p0_24.into_push_pull_output(Level::Low).degrade();
let spimiso = port0.p0_23.into_floating_input().degrade();
let pins = hal::spim::Pins {
sck: spiclk,
miso: Some(spimiso),
mosi: Some(spimosi),
};
let spi = hal::Spim::new(
p.SPIM0,
pins,
hal::spim::Frequency::K500,
hal::spim::MODE_0,
0,
);
let reference_data = "Hello World!".as_bytes();
let mut eh_spi = embedded_hal_spy::new(spi, |_| {});
use embedded_hal::blocking::spi::Write;
match eh_spi.write(reference_data) {
Ok(_) => {}
Err(_) => {}
}
PERIPHERALS = nrf::Peripherals::take();
if PERIPHERALS.is_none() {
hprint!("PERIPHERALS are null!").unwrap();
}
NVIC::unmask(Interrupt::SWI0_EGU0);
let mut d = AsmDelay::new(asm_delay::bitrate::U32BitrateExt::mhz(74));
PERIPHERALS
.as_ref()
.unwrap()
.P0
.dir
.write(|w| w.pin20().output());
PERIPHERALS
.as_ref()
.unwrap()
.P0
.out
.write(|w| w.pin20().low());
loop {
NVIC::pend(Interrupt::SWI0_EGU0);
d.delay_ms(100u32);
}
}
#[interrupt]
fn SWI0_EGU0() {
static mut LED_STATE: bool = false;
flip_led(LED_STATE);
*LED_STATE = !*LED_STATE;
}
fn flip_led(led_state: &mut bool) {
match led_state {
true => unsafe {
PERIPHERALS
.as_ref()
.unwrap()
.P0
.out
.write(|w| w.pin20().low());
},
false => unsafe {
PERIPHERALS
.as_ref()
.unwrap()
.P0
.out
.write(|w| w.pin20().high());
},
}
}
Upvotes: 2
Views: 1095
Reputation: 51
Do you actually need to access all of Peripherals
from your interrupt context? Probably not, you probably need to access only specific peripherals there. You can move those out of the Peripherals
struct and into a static
. Then you'll have the peripherals you need in your main
as local variables there, and everything else in a static
.
But there's an even better solution, in my opinion: Use RTIC. It's designed to handle that exact use case. It allows you to specify exactly which resources you need in which context, and will make those resources available there. You can even safely share resources between different contexts. It will automatically protect them with mutexes, as required.
I can't recommend RTIC highly enough. For me, the only reason not to use it would be, if my program doesn't have any interrupt handlers.
Upvotes: 1