diff --git a/Cargo.toml b/Cargo.toml
index a59ec3c55228fd654298c0aee3a036fcce4bf1d4..cb5119677829fe63e56fa76e46aef40fd2adc8a1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "tudelft-quadrupel"
-version = "1.0.1"
+version = "2.0.0"
edition = "2021"
authors = [
"Anne Stijns <anstijns@gmail.com>",
diff --git a/src/barometer.rs b/src/barometer.rs
index a79cd3e63ee67e86352f483113612dd6eaf52661..a0752246e29a68ab4571516ee101f1015db4d3fe 100644
--- a/src/barometer.rs
+++ b/src/barometer.rs
@@ -4,7 +4,6 @@ use crate::time::Instant;
use crate::twi::TWI;
use core::time::Duration;
use embedded_hal::prelude::_embedded_hal_blocking_i2c_WriteRead;
-use nrf51_hal::Twi;
const MS5611_ADDR: u8 = 0b0111_0111;
const REG_READ: u8 = 0x0;
@@ -76,31 +75,35 @@ struct Ms5611 {
static BAROMETER: Mutex<OnceCell<Ms5611>> = Mutex::new(OnceCell::uninitialized());
pub(crate) fn initialize() {
- let twi: &mut Twi<_> = &mut TWI.lock();
-
- let mut prom = [0; 8];
- let mut data = [0u8; 2];
- for c in 0..8 {
- twi.write_read(MS5611_ADDR, &[REG_PROM + 2 * c], &mut data)
- .unwrap();
- prom[c as usize] = u16::from_be_bytes(data);
- }
+ TWI.modify(|twi| {
+ let mut prom = [0; 8];
+ let mut data = [0u8; 2];
+ for c in 0..8 {
+ twi.write_read(MS5611_ADDR, &[REG_PROM + 2 * c], &mut data)
+ .unwrap();
+ prom[c as usize] = u16::from_be_bytes(data);
+ }
- BAROMETER.lock().initialize(Ms5611 {
- pressure_sensitivity: prom[1],
- pressure_offset: prom[2],
- temp_coef_pressure_sensitivity: prom[3],
- temp_coef_pressure_offset: prom[4],
- temp_ref: prom[5],
- over_sampling_ratio: OverSamplingRatio::Opt4096,
- loop_state: Ms5611LoopState::Reset,
- most_recent_pressure: 0,
+ BAROMETER.modify(|baro| {
+ baro.initialize(Ms5611 {
+ pressure_sensitivity: prom[1],
+ pressure_offset: prom[2],
+ temp_coef_pressure_sensitivity: prom[3],
+ temp_coef_pressure_offset: prom[4],
+ temp_ref: prom[5],
+ over_sampling_ratio: OverSamplingRatio::Opt4096,
+ loop_state: Ms5611LoopState::Reset,
+ most_recent_pressure: 0,
+ })
+ })
});
}
fn update() {
- let baro: &mut Ms5611 = &mut BAROMETER.lock();
- let twi: &mut Twi<_> = &mut TWI.lock();
+ // Safety: The TWI and BAROMETER mutexes are not accessed in an interrupt
+ let twi = unsafe { TWI.no_critical_section_lock_mut() };
+ let baro = unsafe { BAROMETER.no_critical_section_lock_mut() };
+
let now = Instant::now();
match baro.loop_state {
@@ -175,5 +178,8 @@ fn update() {
/// This function will never block, instead it will return an old value if no new value is available.
pub fn read_pressure() -> u32 {
update();
- BAROMETER.lock().most_recent_pressure
+
+ // Safety: The BAROMETER mutexes is not accessed in an interrupt
+ let baro = unsafe { BAROMETER.no_critical_section_lock_mut() };
+ baro.most_recent_pressure
}
diff --git a/src/battery.rs b/src/battery.rs
index d0b0332ea0744aa6ef4dd06701bd2c7570424122..b0a0ac24e4877574c38b0df5f58bbcf00a8660cc 100644
--- a/src/battery.rs
+++ b/src/battery.rs
@@ -31,9 +31,11 @@ pub(crate) fn initialize(adc: nrf51_pac::ADC, nvic: &mut NVIC) {
nvic.set_priority(Interrupt::ADC, 3);
}
- ADC_STATE.lock().initialize(Adc {
- adc,
- last_result: 0,
+ ADC_STATE.modify(|a| {
+ a.initialize(Adc {
+ adc,
+ last_result: 0,
+ })
});
// Safety: The initialize function is not called inside of an interrupt-free section.
@@ -44,21 +46,22 @@ pub(crate) fn initialize(adc: nrf51_pac::ADC, nvic: &mut NVIC) {
#[interrupt]
unsafe fn ADC() {
- let adc = &mut **ADC_STATE.lock();
- adc.adc.events_end.reset();
- // Battery voltage = (result*1.2*3/255*2) = RESULT*0.007058824
- adc.last_result = adc.adc.result.read().result().bits() * 7;
+ ADC_STATE.modify(|adc| {
+ adc.adc.events_end.reset();
+ // Battery voltage = (result*1.2*3/255*2) = RESULT*0.007058824
+ adc.last_result = adc.adc.result.read().result().bits() * 7;
+ })
}
/// Returns the battery voltage in 10^-2 volt.
/// This function will never block, instead it will return an old value if no new value is available.
pub fn read_battery() -> u16 {
- let adc = &mut **ADC_STATE.lock();
+ ADC_STATE.modify(|adc| {
+ if !adc.adc.busy.read().busy().bit() {
+ //For some reason, there is no field inside this register, so we set it to 1 manually.
+ adc.adc.tasks_start.write(|w| unsafe { w.bits(1) });
+ }
- if !adc.adc.busy.read().busy().bit() {
- //For some reason, there is no field inside this register, so we set it to 1 manually.
- adc.adc.tasks_start.write(|w| unsafe { w.bits(1) });
- }
-
- adc.last_result
+ adc.last_result
+ })
}
diff --git a/src/flash.rs b/src/flash.rs
index 9bc4ce28a58cbf3e4e3e08fa3aa8cf1b79351e75..cd91da15fe7d621dc46f76ba424ce2ea870ba07d 100644
--- a/src/flash.rs
+++ b/src/flash.rs
@@ -76,13 +76,15 @@ pub(crate) fn initialize(
let pin_hold = pin_hold.into_push_pull_output(Level::High);
let pin_cs = pin_cs.into_push_pull_output(Level::High);
- let mut spi_flash = FLASH.lock();
- spi_flash.initialize(SpiFlash {
- spi,
- _pin_wp: pin_wp,
- _pin_hold: pin_hold,
- pin_cs,
+ FLASH.modify(|spi_flash| {
+ spi_flash.initialize(SpiFlash {
+ spi,
+ _pin_wp: pin_wp,
+ _pin_hold: pin_hold,
+ pin_cs,
+ });
});
+
flash_enable_wsr()?;
flash_set_wrsr()?;
flash_chip_erase()?;
@@ -94,7 +96,8 @@ pub(crate) fn initialize(
fn spi_master_tx(tx_data: &[u8]) -> Result<(), FlashError> {
assert_ne!(tx_data.len(), 0);
- let mut guard = FLASH.lock();
+ // Safety: The FLASH mutex is not accessed in an interrupt
+ let guard = unsafe { FLASH.no_critical_section_lock_mut() };
// Enable slave
guard.pin_cs.set_low()?;
@@ -108,14 +111,15 @@ fn spi_master_tx(tx_data: &[u8]) -> Result<(), FlashError> {
// Disable slave
guard.pin_cs.set_high()?;
-
Ok(())
}
/// Transmit data over SPI. Optimized to read bytes from the flash memory.
fn spi_master_tx_rx_fast_read(tx_data: [u8; 4], rx_data: &mut [u8]) -> Result<(), FlashError> {
assert_ne!(rx_data.len(), 0);
- let mut guard = FLASH.lock();
+
+ // Safety: The FLASH mutex is not accessed in an interrupt
+ let guard = unsafe { FLASH.no_critical_section_lock_mut() };
// Enable slave
guard.pin_cs.set_low()?;
@@ -144,7 +148,9 @@ fn spi_master_tx_rx_fast_write(tx_data: [u8; 4], bytes: &[u8]) -> Result<(), Fla
let address: u32 =
u32::from(tx_data[3]) + (u32::from(tx_data[2]) << 8) + (u32::from(tx_data[1]) << 16);
- let mut guard = FLASH.lock();
+ // Safety: The FLASH mutex is not accessed in an interrupt
+ let guard = unsafe { FLASH.no_critical_section_lock_mut() };
+
// Enable slave
guard.pin_cs.set_low()?;
diff --git a/src/initialize.rs b/src/initialize.rs
index 2df63a36976d13a0fda317932c38bd22febc06bc..429d28d4193b20643772effadcc6dfddc9bbce61 100644
--- a/src/initialize.rs
+++ b/src/initialize.rs
@@ -32,9 +32,10 @@ pub fn initialize(heap_memory: &'static mut [MaybeUninit<u8>], debug: bool) {
assembly_delay(2_500_000);
// keep this guard around until the end of the function (so interrupts stay off)
- let mut guard = INITIALIZED.lock();
- assert!(!(*guard), "ALREADY INITIALIZED");
- *guard = true;
+ INITIALIZED.modify(|guard| {
+ assert!(!(*guard), "ALREADY INITIALIZED");
+ *guard = true;
+ });
// unwrap: will never panic because this function can only be called once (see the guard above)
let mut nrf51_peripherals = Peripherals::take().unwrap();
diff --git a/src/led.rs b/src/led.rs
index 5c2d2fb7b98487842bd35fbaad6e1668bcb94fcb..94110244362fe8b58e69464d6ccfb2bac304ef31 100644
--- a/src/led.rs
+++ b/src/led.rs
@@ -36,7 +36,7 @@ impl Led {
// inline comments from the `nrf_51` crate on `set_high`.
//
// NOTE: single writes on ARM are always atomic so this makes sense.
- let leds = unsafe { LEDS.no_critical_section_lock() };
+ let leds = unsafe { LEDS.no_critical_section_lock_mut() };
// ignore the error here. Its type is `Void` and is impossible
// to construct (and thus impossible to actually happen)
@@ -55,7 +55,7 @@ impl Led {
// inline comments from the `nrf_51` crate on `set_low`.
//
// NOTE: single writes on ARM are always atomic so this makes sense.
- let leds = unsafe { LEDS.no_critical_section_lock() };
+ let leds = unsafe { LEDS.no_critical_section_lock_mut() };
// ignore the error here. Its type is `Void` and is impossible
// to construct (and thus impossible to actually happen)
@@ -74,7 +74,7 @@ impl Led {
// inline comments from the `nrf_51` crate on `is_set_high`.
//
// NOTE: single writes on ARM are always atomic so this makes sense.
- let leds = unsafe { LEDS.no_critical_section_lock() };
+ let leds = unsafe { LEDS.no_critical_section_lock_mut() };
let res = match self {
Red => leds.led_red.is_set_high(),
@@ -135,10 +135,12 @@ pub(crate) fn initialize(
led_green: P0_28<Disconnected>,
led_blue: P0_30<Disconnected>,
) {
- LEDS.lock().initialize(Leds {
- led_red: led_red.into_push_pull_output(Level::High),
- led_yellow: led_yellow.into_push_pull_output(Level::High),
- led_green: led_green.into_push_pull_output(Level::High),
- led_blue: led_blue.into_push_pull_output(Level::High),
+ LEDS.modify(|leds| {
+ leds.initialize(Leds {
+ led_red: led_red.into_push_pull_output(Level::High),
+ led_yellow: led_yellow.into_push_pull_output(Level::High),
+ led_green: led_green.into_push_pull_output(Level::High),
+ led_blue: led_blue.into_push_pull_output(Level::High),
+ })
});
}
diff --git a/src/lib.rs b/src/lib.rs
index 28da01a29e7938c2803f94a02ce139d5a242056e..d02fbaca8fdfb3f67205b791112d365ab0524c07 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -54,8 +54,8 @@ pub mod flash;
/// Initialize all the drivers
pub mod initialize;
-/// Utilities to control the leds on the board.
-///
+/// Utilities to control the leds on the board.
+///
/// Note that in the template,
/// some leds have already been assigned meaning:
///
diff --git a/src/motor.rs b/src/motor.rs
index 4540949a1a2d105edccaa3daa869c53c1fe73f42..fc1c7dc97772b761aa8ec1ad52b29cf316635f91 100644
--- a/src/motor.rs
+++ b/src/motor.rs
@@ -28,14 +28,12 @@ static MOTORS: Mutex<OnceCell<Motors>> = Mutex::new(OnceCell::uninitialized());
/// - For old drones (carbon fiber), 800 is a reasonable maximum.
/// - For new drones (aluminium frame), 1000 is a reasonable maximum.
pub fn set_motor_max(max: u16) {
- let mut guard = MOTORS.lock();
- guard.motor_max = max;
+ MOTORS.modify(|motors| motors.motor_max = max);
}
/// This gets the maximum motor value that the motor driver will cap the motor values at. This is 400 by default.
pub fn get_motor_max() -> u16 {
- let guard = MOTORS.lock();
- guard.motor_max
+ MOTORS.modify(|motors| motors.motor_max)
}
/// Get the current motor values. This is an array of four values:
@@ -44,7 +42,7 @@ pub fn get_motor_max() -> u16 {
/// - 2: The back motor
/// - 3: The left motor
pub fn get_motors() -> [u16; 4] {
- MOTORS.lock().motor_values
+ MOTORS.modify(|motors| motors.motor_values)
}
/// Set the motor values. This will cap the motor values to the value set by `set_motor_max`. The motor values are an array of four values:
@@ -53,8 +51,9 @@ pub fn get_motors() -> [u16; 4] {
/// - 2: The back motor
/// - 3: The left motor
pub fn set_motors(val: [u16; 4]) {
- let mut guard = MOTORS.lock();
- guard.motor_values = val.map(|v| v.min(guard.motor_max));
+ MOTORS.modify(|guard| {
+ guard.motor_values = val.map(|v| v.min(guard.motor_max));
+ });
}
#[allow(clippy::too_many_lines)]
@@ -69,185 +68,186 @@ pub(crate) fn initialize(
// Configure pin20
let pin20 = pin20.into_push_pull_output(Level::Low);
- let mut motors = MOTORS.lock();
- motors.initialize(Motors {
- motor_values: [0; 4],
- motor_max: 400,
- timer1,
- timer2,
- pin20,
- });
+ MOTORS.modify(|motors| {
+ motors.initialize(Motors {
+ motor_values: [0; 4],
+ motor_max: 400,
+ timer1,
+ timer2,
+ pin20,
+ });
- // Configure GPIOTE. GPIOTE is stands for GPIO tasks and events.
- // Safety: Writing the motor pins to the register is the intended behaviour. The pins have been verified to be correct.
- gpiote.config[0].write(|w| unsafe {
- w.mode()
- .task()
- .psel()
- .bits(MOTOR_0_PIN)
- .polarity()
- .toggle()
- .outinit()
- .set_bit()
- });
- gpiote.config[1].write(|w| unsafe {
- w.mode()
- .task()
- .psel()
- .bits(MOTOR_1_PIN)
- .polarity()
- .toggle()
- .outinit()
- .set_bit()
- });
- gpiote.config[2].write(|w| unsafe {
- w.mode()
- .task()
- .psel()
- .bits(MOTOR_2_PIN)
- .polarity()
- .toggle()
- .outinit()
- .set_bit()
- });
- gpiote.config[3].write(|w| unsafe {
- w.mode()
- .task()
- .psel()
- .bits(MOTOR_3_PIN)
- .polarity()
- .toggle()
- .outinit()
- .set_bit()
- });
+ // Configure GPIOTE. GPIOTE is stands for GPIO tasks and events.
+ // Safety: Writing the motor pins to the register is the intended behaviour. The pins have been verified to be correct.
+ gpiote.config[0].write(|w| unsafe {
+ w.mode()
+ .task()
+ .psel()
+ .bits(MOTOR_0_PIN)
+ .polarity()
+ .toggle()
+ .outinit()
+ .set_bit()
+ });
+ gpiote.config[1].write(|w| unsafe {
+ w.mode()
+ .task()
+ .psel()
+ .bits(MOTOR_1_PIN)
+ .polarity()
+ .toggle()
+ .outinit()
+ .set_bit()
+ });
+ gpiote.config[2].write(|w| unsafe {
+ w.mode()
+ .task()
+ .psel()
+ .bits(MOTOR_2_PIN)
+ .polarity()
+ .toggle()
+ .outinit()
+ .set_bit()
+ });
+ gpiote.config[3].write(|w| unsafe {
+ w.mode()
+ .task()
+ .psel()
+ .bits(MOTOR_3_PIN)
+ .polarity()
+ .toggle()
+ .outinit()
+ .set_bit()
+ });
- // Configure timer 2
- motors
- .timer2
- .prescaler
- .write(|w| unsafe { w.prescaler().bits(1) }); //0.125us. Safety: Allowed range of values is 0-9
- motors.timer2.intenset.write(|w| w.compare3().set_bit());
- motors.timer2.cc[0].write(|w| unsafe { w.bits(1000) }); // Safety: Any time is allowed
- motors.timer2.cc[1].write(|w| unsafe { w.bits(1000) }); // Safety: Any time is allowed
- motors.timer2.cc[3].write(|w| unsafe { w.bits(2500) }); // Safety: Any time is allowed
- motors.timer2.shorts.write(|w| w.compare3_clear().set_bit());
- motors.timer2.tasks_clear.write(|w| unsafe { w.bits(1) }); // Safety: Writing 1 to a task-clear register is allowed.
+ // Configure timer 2
+ motors
+ .timer2
+ .prescaler
+ .write(|w| unsafe { w.prescaler().bits(1) }); //0.125us. Safety: Allowed range of values is 0-9
+ motors.timer2.intenset.write(|w| w.compare3().set_bit());
+ motors.timer2.cc[0].write(|w| unsafe { w.bits(1000) }); // Safety: Any time is allowed
+ motors.timer2.cc[1].write(|w| unsafe { w.bits(1000) }); // Safety: Any time is allowed
+ motors.timer2.cc[3].write(|w| unsafe { w.bits(2500) }); // Safety: Any time is allowed
+ motors.timer2.shorts.write(|w| w.compare3_clear().set_bit());
+ motors.timer2.tasks_clear.write(|w| unsafe { w.bits(1) }); // Safety: Writing 1 to a task-clear register is allowed.
- // Configure timer 1
- // Safety: Allowed range of values is 0-9
- motors
- .timer1
- .prescaler
- .write(|w| unsafe { w.prescaler().bits(1) }); //0.125us
- motors.timer1.intenset.write(|w| w.compare3().set_bit());
- motors.timer1.cc[0].write(|w| unsafe { w.bits(1000) }); // Safety: Any time is allowed
- motors.timer1.cc[1].write(|w| unsafe { w.bits(1000) }); // Safety: Any time is allowed
- motors.timer1.cc[3].write(|w| unsafe { w.bits(2500) }); // Safety: Any time is allowed
- motors.timer1.shorts.write(|w| w.compare3_clear().set_bit());
- motors.timer1.tasks_clear.write(|w| unsafe { w.bits(1) }); // Safety: Writing 1 to a task-clear register is allowed.
+ // Configure timer 1
+ // Safety: Allowed range of values is 0-9
+ motors
+ .timer1
+ .prescaler
+ .write(|w| unsafe { w.prescaler().bits(1) }); //0.125us
+ motors.timer1.intenset.write(|w| w.compare3().set_bit());
+ motors.timer1.cc[0].write(|w| unsafe { w.bits(1000) }); // Safety: Any time is allowed
+ motors.timer1.cc[1].write(|w| unsafe { w.bits(1000) }); // Safety: Any time is allowed
+ motors.timer1.cc[3].write(|w| unsafe { w.bits(2500) }); // Safety: Any time is allowed
+ motors.timer1.shorts.write(|w| w.compare3_clear().set_bit());
+ motors.timer1.tasks_clear.write(|w| unsafe { w.bits(1) }); // Safety: Writing 1 to a task-clear register is allowed.
- // Start the timer tasks
- // Safety: Writing 1 to a task-start registers is allowed.
- motors.timer2.tasks_start.write(|w| unsafe { w.bits(1) });
- motors.timer1.tasks_start.write(|w| unsafe { w.bits(1) });
+ // Start the timer tasks
+ // Safety: Writing 1 to a task-start registers is allowed.
+ motors.timer2.tasks_start.write(|w| unsafe { w.bits(1) });
+ motors.timer1.tasks_start.write(|w| unsafe { w.bits(1) });
- // Link motor 0 - gpiote 0
- ppi.ch[0]
- .eep
- .write(|w| unsafe { w.bits(motors.timer1.events_compare[0].as_ptr() as u32) });
- ppi.ch[0]
- .tep
- .write(|w| unsafe { w.bits(gpiote.tasks_out[0].as_ptr() as u32) });
- ppi.ch[1]
- .eep
- .write(|w| unsafe { w.bits(motors.timer1.events_compare[3].as_ptr() as u32) });
- ppi.ch[1]
- .tep
- .write(|w| unsafe { w.bits(gpiote.tasks_out[0].as_ptr() as u32) });
+ // Link motor 0 - gpiote 0
+ ppi.ch[0]
+ .eep
+ .write(|w| unsafe { w.bits(motors.timer1.events_compare[0].as_ptr() as u32) });
+ ppi.ch[0]
+ .tep
+ .write(|w| unsafe { w.bits(gpiote.tasks_out[0].as_ptr() as u32) });
+ ppi.ch[1]
+ .eep
+ .write(|w| unsafe { w.bits(motors.timer1.events_compare[3].as_ptr() as u32) });
+ ppi.ch[1]
+ .tep
+ .write(|w| unsafe { w.bits(gpiote.tasks_out[0].as_ptr() as u32) });
- // Link motor 1 - gpiote 1
- ppi.ch[2]
- .eep
- .write(|w| unsafe { w.bits(motors.timer1.events_compare[1].as_ptr() as u32) });
- ppi.ch[2]
- .tep
- .write(|w| unsafe { w.bits(gpiote.tasks_out[1].as_ptr() as u32) });
- ppi.ch[3]
- .eep
- .write(|w| unsafe { w.bits(motors.timer1.events_compare[3].as_ptr() as u32) });
- ppi.ch[3]
- .tep
- .write(|w| unsafe { w.bits(gpiote.tasks_out[1].as_ptr() as u32) });
+ // Link motor 1 - gpiote 1
+ ppi.ch[2]
+ .eep
+ .write(|w| unsafe { w.bits(motors.timer1.events_compare[1].as_ptr() as u32) });
+ ppi.ch[2]
+ .tep
+ .write(|w| unsafe { w.bits(gpiote.tasks_out[1].as_ptr() as u32) });
+ ppi.ch[3]
+ .eep
+ .write(|w| unsafe { w.bits(motors.timer1.events_compare[3].as_ptr() as u32) });
+ ppi.ch[3]
+ .tep
+ .write(|w| unsafe { w.bits(gpiote.tasks_out[1].as_ptr() as u32) });
- // Link motor 2 - gpiote 2
- ppi.ch[4]
- .eep
- .write(|w| unsafe { w.bits(motors.timer2.events_compare[0].as_ptr() as u32) });
- ppi.ch[4]
- .tep
- .write(|w| unsafe { w.bits(gpiote.tasks_out[2].as_ptr() as u32) });
- ppi.ch[5]
- .eep
- .write(|w| unsafe { w.bits(motors.timer2.events_compare[3].as_ptr() as u32) });
- ppi.ch[5]
- .tep
- .write(|w| unsafe { w.bits(gpiote.tasks_out[2].as_ptr() as u32) });
+ // Link motor 2 - gpiote 2
+ ppi.ch[4]
+ .eep
+ .write(|w| unsafe { w.bits(motors.timer2.events_compare[0].as_ptr() as u32) });
+ ppi.ch[4]
+ .tep
+ .write(|w| unsafe { w.bits(gpiote.tasks_out[2].as_ptr() as u32) });
+ ppi.ch[5]
+ .eep
+ .write(|w| unsafe { w.bits(motors.timer2.events_compare[3].as_ptr() as u32) });
+ ppi.ch[5]
+ .tep
+ .write(|w| unsafe { w.bits(gpiote.tasks_out[2].as_ptr() as u32) });
- // Link motor 3 - gpiote 3
- ppi.ch[6]
- .eep
- .write(|w| unsafe { w.bits(motors.timer2.events_compare[1].as_ptr() as u32) });
- ppi.ch[6]
- .tep
- .write(|w| unsafe { w.bits(gpiote.tasks_out[3].as_ptr() as u32) });
- ppi.ch[7]
- .eep
- .write(|w| unsafe { w.bits(motors.timer2.events_compare[3].as_ptr() as u32) });
- ppi.ch[7]
- .tep
- .write(|w| unsafe { w.bits(gpiote.tasks_out[3].as_ptr() as u32) });
+ // Link motor 3 - gpiote 3
+ ppi.ch[6]
+ .eep
+ .write(|w| unsafe { w.bits(motors.timer2.events_compare[1].as_ptr() as u32) });
+ ppi.ch[6]
+ .tep
+ .write(|w| unsafe { w.bits(gpiote.tasks_out[3].as_ptr() as u32) });
+ ppi.ch[7]
+ .eep
+ .write(|w| unsafe { w.bits(motors.timer2.events_compare[3].as_ptr() as u32) });
+ ppi.ch[7]
+ .tep
+ .write(|w| unsafe { w.bits(gpiote.tasks_out[3].as_ptr() as u32) });
- // Set which channels of PPI are enabled
- ppi.chenset.write(|w| {
- w.ch0()
- .set_bit()
- .ch1()
- .set_bit()
- .ch2()
- .set_bit()
- .ch3()
- .set_bit()
- .ch4()
- .set_bit()
- .ch5()
- .set_bit()
- .ch6()
- .set_bit()
- .ch7()
- .set_bit()
- });
+ // Set which channels of PPI are enabled
+ ppi.chenset.write(|w| {
+ w.ch0()
+ .set_bit()
+ .ch1()
+ .set_bit()
+ .ch2()
+ .set_bit()
+ .ch3()
+ .set_bit()
+ .ch4()
+ .set_bit()
+ .ch5()
+ .set_bit()
+ .ch6()
+ .set_bit()
+ .ch7()
+ .set_bit()
+ });
- // Configure timer interrupts
- // Safety: We are not using priority-based critical sections.
- unsafe {
- nvic.set_priority(Interrupt::TIMER2, 1);
- NVIC::unpend(Interrupt::TIMER2);
- nvic.set_priority(Interrupt::TIMER1, 1);
- NVIC::unpend(Interrupt::TIMER1);
- }
+ // Configure timer interrupts
+ // Safety: We are not using priority-based critical sections.
+ unsafe {
+ nvic.set_priority(Interrupt::TIMER2, 1);
+ NVIC::unpend(Interrupt::TIMER2);
+ nvic.set_priority(Interrupt::TIMER1, 1);
+ NVIC::unpend(Interrupt::TIMER1);
+ }
- // Enable interrupts
- // Safety: We are not using mask-based critical sections.
- unsafe {
- NVIC::unmask(Interrupt::TIMER2);
- NVIC::unmask(Interrupt::TIMER1);
- }
+ // Enable interrupts
+ // Safety: We are not using mask-based critical sections.
+ unsafe {
+ NVIC::unmask(Interrupt::TIMER2);
+ NVIC::unmask(Interrupt::TIMER1);
+ }
+ });
}
#[interrupt]
unsafe fn TIMER2() {
// Safety: interrupts are already turned off here, since we are inside an interrupt
- let motors = unsafe { MOTORS.no_critical_section_lock() };
+ let motors = unsafe { MOTORS.no_critical_section_lock_mut() };
if motors.timer2.events_compare[3].read().bits() != 0 {
motors.timer2.events_compare[3].reset();
//2500 * 0.125
@@ -264,7 +264,7 @@ unsafe fn TIMER2() {
#[interrupt]
unsafe fn TIMER1() {
// Safety: interrupts are already turned off here, since we are inside an interrupt
- let motors = unsafe { MOTORS.no_critical_section_lock() };
+ let motors = unsafe { MOTORS.no_critical_section_lock_mut() };
if motors.timer1.events_compare[3].read().bits() != 0 {
motors.timer1.events_compare[3].reset();
motors.timer1.tasks_capture[2].write(|w| w.bits(1));
diff --git a/src/mpu.rs b/src/mpu.rs
index 6858cb19f4a864a90c139d1fe5300d1b89ec90f2..c935ecb695a25f337d4a9164130d962199a96be5 100644
--- a/src/mpu.rs
+++ b/src/mpu.rs
@@ -34,26 +34,28 @@ struct Mpu {
static MPU: Mutex<OnceCell<Mpu>> = Mutex::new(OnceCell::uninitialized());
pub(crate) fn initialize() {
- let twi: &mut Twi<_> = &mut TWI.lock();
-
- let mut mpu = Mpu6050::new(twi).unwrap();
-
- mpu.initialize_dmp(twi).unwrap();
-
- mpu.set_sample_rate_divider(twi, SAMPLE_RATE_DIVIDER_MPU)
- .unwrap();
- mpu.set_digital_lowpass_filter(twi, DigitalLowPassFilter::Filter5)
- .unwrap();
- MPU.lock().initialize(Mpu {
- mpu,
- dmp_enabled: true,
+ TWI.modify(|twi| {
+ let mut mpu: Mpu6050<Twi<TWI0>> = Mpu6050::new(&mut **twi).unwrap();
+
+ mpu.initialize_dmp(twi).unwrap();
+
+ mpu.set_sample_rate_divider(twi, SAMPLE_RATE_DIVIDER_MPU)
+ .unwrap();
+ mpu.set_digital_lowpass_filter(twi, DigitalLowPassFilter::Filter5)
+ .unwrap();
+ MPU.modify(|m| {
+ m.initialize(Mpu {
+ mpu,
+ dmp_enabled: true,
+ })
+ });
});
}
/// Is the DMP (digital motion processor) of the MPU enabled?
/// It is enabled by default.
pub fn is_dmp_enabled() -> bool {
- MPU.lock().dmp_enabled
+ MPU.modify(|mpu| mpu.dmp_enabled)
}
/// Disable the DMP (digital motion processor) of the MPU
@@ -61,8 +63,9 @@ pub fn is_dmp_enabled() -> bool {
/// # Panics
/// when the global constant `SAMPLE_RATE_DIVIDER_RAW` is wrong (i.e. won't panic under normal conditions)
pub fn disable_dmp() {
- let twi: &mut Twi<_> = &mut TWI.lock();
- let mpu: &mut Mpu = &mut MPU.lock();
+ // Safety: The TWI and MPU mutexes are not accessed in an interrupt
+ let twi = unsafe { TWI.no_critical_section_lock_mut() };
+ let mpu = unsafe { MPU.no_critical_section_lock_mut() };
mpu.mpu
.set_sample_rate_divider(twi, SAMPLE_RATE_DIVIDER_RAW)
@@ -77,8 +80,9 @@ pub fn disable_dmp() {
/// # Errors
/// when the global constant `SAMPLE_RATE_DIVIDER_MPU` is wrong (i.e. will not panic under normal conditions)
pub fn enable_dmp() -> Result<(), Error<Twi<TWI0>>> {
- let twi: &mut Twi<_> = &mut TWI.lock();
- let mpu: &mut Mpu = &mut MPU.lock();
+ // Safety: The TWI and MPU mutexes are not accessed in an interrupt
+ let twi = unsafe { TWI.no_critical_section_lock_mut() };
+ let mpu = unsafe { MPU.no_critical_section_lock_mut() };
mpu.mpu
.set_sample_rate_divider(twi, SAMPLE_RATE_DIVIDER_MPU)?;
@@ -99,8 +103,9 @@ pub fn enable_dmp() -> Result<(), Error<Twi<TWI0>>> {
/// # Errors
/// when a TWI(I2C) operation failed
pub fn read_dmp_bytes() -> nb::Result<Quaternion, Error<Twi<TWI0>>> {
- let twi: &mut Twi<_> = &mut TWI.lock();
- let mpu: &mut Mpu = &mut MPU.lock();
+ // Safety: The TWI and MPU mutexes are not accessed in an interrupt
+ let twi = unsafe { TWI.no_critical_section_lock_mut() };
+ let mpu = unsafe { MPU.no_critical_section_lock_mut() };
assert!(mpu.dmp_enabled);
@@ -127,8 +132,9 @@ pub fn read_dmp_bytes() -> nb::Result<Quaternion, Error<Twi<TWI0>>> {
/// # Errors
/// when a TWI operation failed
pub fn read_raw() -> Result<(Accel, Gyro), Error<Twi<TWI0>>> {
- let twi: &mut Twi<_> = &mut TWI.lock();
- let mpu: &mut Mpu = &mut MPU.lock();
+ // Safety: The TWI and MPU mutexes are not accessed in an interrupt
+ let twi = unsafe { TWI.no_critical_section_lock_mut() };
+ let mpu = unsafe { MPU.no_critical_section_lock_mut() };
let accel = mpu.mpu.accel(twi)?;
let gyro = mpu.mpu.gyro(twi)?;
diff --git a/src/mutex.rs b/src/mutex.rs
index 69f213b44b59d5ab5e2ebd1cf7faab5c2fe2ff02..216732ac64113dbcb4041a515c23fec7e699696f 100644
--- a/src/mutex.rs
+++ b/src/mutex.rs
@@ -1,9 +1,4 @@
use core::cell::UnsafeCell;
-use core::ops::{Deref, DerefMut};
-
-use cortex_m::interrupt::{disable, enable};
-use cortex_m::register::primask;
-use cortex_m::register::primask::Primask;
/// A mutual exclusion primitive useful for protecting shared data. It works by disabling interrupts while the lock is being held.
///
@@ -36,71 +31,40 @@ impl<T> Mutex<T> {
}
}
- /// This function gets a reference to the inner `T` by locking the lock.
- ///
- /// This disables interrupts while the `LockGuard` returned by this function is alive.
- pub fn lock(&self) -> LockGuard<T> {
- let primask = primask::read();
-
- // disable interrupts
- disable();
-
- LockGuard {
- // SAFETY: we disabled interrupts, creating a critical section.
- // that means we can safely mutably access the internals of our
- // UnsafeCell. Note that this is safe until interrupts are turned
- // back on, which happens when users drop the LockGuard. Since the
- // guard is the only way to access &mut T, this means that interrupts
- // are turned on at the moment you can never have access to &mut T anymore
- inner: unsafe { &mut *self.inner.get() },
- primask,
- }
+ /// Locks the mutex in a callback
+ #[inline(always)]
+ pub fn modify<U>(&self, f: impl FnOnce(&mut T) -> U) -> U {
+ cortex_m::interrupt::free(|_| {
+ // Safety: Interrupts are disabled, so the current code is the only one that can be running.
+ // TODO make sure you can't lock the mutex in here
+ f(unsafe { &mut *self.inner.get() })
+ })
}
/// This function gets a reference to the inner `T` _without_ locking the lock.
/// This is inherently unsafe.
///
/// # Safety
- /// This function is only safe if you can guarantee that nothing is
- /// mutating this or holding a lock while this reference exists. That means, you should
- /// generally drop this reference ASAP.
+ /// This function is only safe if you can guarantee that no mutable references to the contents of this lock exist.
///
/// This generally can be used in the following cases:
- /// * You only access this from within interrupts, as interrupts themselves can not be interrupted
- /// * You only access this outside of interrupts, as interrupts don't break the mutex guarantees
- #[allow(clippy::mut_from_ref)]
- pub unsafe fn no_critical_section_lock(&self) -> &mut T {
- &mut *self.inner.get()
+ /// * You only access this mutex from within a single interrupt
+ /// * You only access this mutex outside of interrupts, as interrupts don't break the mutex guarantees
+ pub unsafe fn no_critical_section_lock(&self) -> &T {
+ &*self.inner.get()
}
-}
-
-/// A `LockGuard` is an object that, as long as it is alive, means the corresponding mutex is locked.
-/// The mutex is unlocked when this object is automatically dropped or explicitly dropped using `drop`.
-pub struct LockGuard<'a, T> {
- inner: &'a mut T,
- primask: Primask,
-}
-impl<T> Drop for LockGuard<'_, T> {
- fn drop(&mut self) {
- // If the interrupts were active before our `disable` call, then re-enable
- // them. Otherwise, keep them disabled
- if self.primask.is_active() {
- unsafe { enable() }
- }
- }
-}
-
-impl<T> Deref for LockGuard<'_, T> {
- type Target = T;
-
- fn deref(&self) -> &Self::Target {
- self.inner
- }
-}
-
-impl<T> DerefMut for LockGuard<'_, T> {
- fn deref_mut(&mut self) -> &mut Self::Target {
- self.inner
+ /// This function gets a mutable reference to the inner `T` _without_ locking the lock.
+ /// This is inherently unsafe.
+ ///
+ /// # Safety
+ /// This function is only safe if you can guarantee that no other references to the contents of this lock exist.
+ ///
+ /// This generally can be used in the following cases:
+ /// * You only access this mutex from within a single interrupt
+ /// * You only access this mutex outside of interrupts, as interrupts don't break the mutex guarantees
+ #[allow(clippy::mut_from_ref)]
+ pub unsafe fn no_critical_section_lock_mut(&self) -> &mut T {
+ &mut *self.inner.get()
}
}
diff --git a/src/time.rs b/src/time.rs
index 00af2371b42b3ea78cf4fd9de4047479df850589..846fa2a43063b99a6ac9ffd992ef85c68fb1a3a8 100644
--- a/src/time.rs
+++ b/src/time.rs
@@ -106,7 +106,7 @@ const PERIOD: u64 = 30517;
const COUNTER_MAX: u32 = 1 << 24;
/// is set to true when the timer interrupt has gone off.
-/// Used to wait on the timer interrupt in [`wait_for_interrupt`]
+/// Used to wait on the timer interrupt in [`wait_for_next_tick`]
static TIMER_FLAG: AtomicBool = AtomicBool::new(false);
/// Global time in magic timer units ([`PERIOD`]) since timers started
@@ -120,25 +120,25 @@ static PREV_COUNTER: AtomicU32 = AtomicU32::new(0);
static COUNTER_PERIOD: AtomicU32 = AtomicU32::new(0);
pub(crate) fn initialize(clock_instance: RTC0, nvic: &mut NVIC) {
- let mut rtc = RTC.lock();
-
- rtc.initialize(Rtc::new(clock_instance, PRESCALER).unwrap());
- rtc.enable_event(RtcInterrupt::Compare0);
- rtc.enable_interrupt(RtcInterrupt::Compare0, Some(nvic));
- rtc.enable_counter();
+ RTC.modify(|rtc| {
+ rtc.initialize(Rtc::new(clock_instance, PRESCALER).unwrap());
+ rtc.enable_event(RtcInterrupt::Compare0);
+ rtc.enable_interrupt(RtcInterrupt::Compare0, Some(nvic));
+ rtc.enable_counter();
+ });
}
// get the current global time in nanoseconds. The precision is not necessarily in single nanoseconds
fn get_time_ns() -> u64 {
- // the number of periods of the clock that passed in total
- let global_time = GLOBAL_TIME.lock();
- // the current state of the clock
- let counter = RTC.lock().get_counter();
- // the previous state of the clock, when the global_time was last updated
- let prev_counter = PREV_COUNTER.load(Ordering::SeqCst);
-
- // take the global time, and add to that how much time has passed since the last interrupt
- (*global_time + u64::from(counter_diff(prev_counter, counter))) * PERIOD
+ GLOBAL_TIME.modify(|global_time| {
+ let counter = RTC.modify(|counter| counter.get_counter());
+
+ // the previous state of the clock, when the global_time was last updated
+ let prev_counter = PREV_COUNTER.load(Ordering::SeqCst);
+
+ // take the global time, and add to that how much time has passed since the last interrupt
+ (*global_time + u64::from(counter_diff(prev_counter, counter))) * PERIOD
+ })
}
/// neatly calculates a difference in clockcycles between two rtc counter values
@@ -156,9 +156,9 @@ fn counter_diff(prev: u32, curr: u32) -> u32 {
#[interrupt]
unsafe fn RTC0() {
// SAFETY: we're in an interrupt so this code cannot be run concurrently anyway
- let rtc = RTC.no_critical_section_lock();
+ let rtc = RTC.no_critical_section_lock_mut();
// SAFETY: we're in an interrupt so this code cannot be run concurrently anyway
- let global_time = GLOBAL_TIME.no_critical_section_lock();
+ let global_time = GLOBAL_TIME.no_critical_section_lock_mut();
if rtc.is_event_triggered(RtcInterrupt::Compare0) {
let counter = rtc.get_counter();
@@ -192,18 +192,21 @@ pub fn wait_for_next_tick() {
///
#[allow(clippy::missing_panics_doc)]
pub fn set_tick_frequency(hz: u64) {
- let mut rtc = RTC.lock();
+ RTC.modify(|rtc| {
+ let counter_setting = (1_000_000_000 / hz) / PERIOD;
+ // this can't actually happen, since it'd need hz < 1
+ debug_assert!(counter_setting < (1 << 24), "counter period should be less than 1<<24 (roughly 6 minutes with the default PRESCALER settings)");
- let counter_setting = (1_000_000_000 / hz) / PERIOD;
- // this can't actually happen, since it'd need hz < 1
- debug_assert!(counter_setting < (1 << 24), "counter period should be less than 1<<24 (roughly 6 minutes with the default PRESCALER settings)");
+ COUNTER_PERIOD.store(counter_setting as u32, Ordering::SeqCst);
- COUNTER_PERIOD.store(counter_setting as u32, Ordering::SeqCst);
+ rtc.set_compare(RtcCompareReg::Compare0, counter_setting as u32)
+ .unwrap();
+ rtc.clear_counter();
+ PREV_COUNTER.store(0, Ordering::SeqCst);
+ });
- rtc.set_compare(RtcCompareReg::Compare0, counter_setting as u32)
- .unwrap();
- rtc.clear_counter();
- PREV_COUNTER.store(0, Ordering::SeqCst);
+ // Give the counter time to clear (Section 19.1.8 of the NRF51 reference manual V3)
+ delay_us_assembly(100);
}
/// Delay the program for a time using assembly instructions.
diff --git a/src/twi.rs b/src/twi.rs
index 2ce109a53da69075b0d28ef8754640256d01364f..f8ec8c3023f4eb471c406563740ad536af7681de 100644
--- a/src/twi.rs
+++ b/src/twi.rs
@@ -13,12 +13,14 @@ pub(crate) fn initialize(twi: TWI0, scl_pin: P0_04<Disconnected>, sda_pin: P0_02
let scl_pin = scl_pin.into_floating_input();
let sda_pin = sda_pin.into_floating_input();
- TWI.lock().initialize(Twi::new(
- twi,
- Pins {
- scl: Pin::from(scl_pin),
- sda: Pin::from(sda_pin),
- },
- FREQUENCY_A::K400,
- ));
+ TWI.modify(|t| {
+ t.initialize(Twi::new(
+ twi,
+ Pins {
+ scl: Pin::from(scl_pin),
+ sda: Pin::from(sda_pin),
+ },
+ FREQUENCY_A::K400,
+ ))
+ });
}
diff --git a/src/uart.rs b/src/uart.rs
index a47fbc54f45f5efca25d81f2cd240575697c8252..c74c0699d7add24d6dcd354a8da24e4ef7993b32 100644
--- a/src/uart.rs
+++ b/src/uart.rs
@@ -1,4 +1,4 @@
-use crate::mutex::{LockGuard, Mutex};
+use crate::mutex::Mutex;
use crate::once_cell::OnceCell;
use cortex_m::peripheral::NVIC;
use nrf51_pac::interrupt;
@@ -44,17 +44,19 @@ pub(crate) fn initialize(uart: nrf51_pac::UART0, nvic: &mut NVIC) {
// actualy enable the uart interrupt
unsafe { NVIC::unmask(nrf51_pac::Interrupt::UART0) };
- UART.lock().initialize(UartDriver {
- rx_buffer: ConstGenericRingBuffer::default(),
- tx_buffer: ConstGenericRingBuffer::default(),
- tx_data_available: true,
- uart,
- });
+ UART.modify(|uartd| {
+ uartd.initialize(UartDriver {
+ rx_buffer: ConstGenericRingBuffer::default(),
+ tx_buffer: ConstGenericRingBuffer::default(),
+ tx_data_available: true,
+ uart,
+ })
+ })
}
/// Checks if the UART is initialized
pub fn is_initialized() -> bool {
- UART.lock().is_initialized()
+ UART.modify(|uart| uart.is_initialized())
}
/// Safe usage: this should only be called if you never run any real code after this again.
@@ -63,45 +65,46 @@ pub fn is_initialized() -> bool {
/// again
#[doc(hidden)]
pub unsafe fn uninitialize() {
- UART.lock().uninitialize();
+ UART.modify(|uart| uart.uninitialize())
}
/// Reads as many bytes as possible from the UART
pub fn receive_bytes(bytes: &mut [u8]) -> usize {
- let mut uart = UART.lock();
-
- let mut i = 0;
- while let Some(byte) = get_byte(&mut uart) {
- bytes[i] = byte;
- i += 1;
- if i == bytes.len() {
- break;
+ UART.modify(|uart| {
+ let mut i = 0;
+ while let Some(byte) = get_byte(uart) {
+ bytes[i] = byte;
+ i += 1;
+ if i == bytes.len() {
+ break;
+ }
}
- }
- i
+ i
+ })
}
/// Reads a single byte from the UART
-fn get_byte(uart: &mut LockGuard<OnceCell<UartDriver>>) -> Option<u8> {
+fn get_byte(uart: &mut OnceCell<UartDriver>) -> Option<u8> {
uart.rx_buffer.dequeue()
}
/// Writes the entire buffer over UART
pub fn send_bytes(bytes: &[u8]) -> bool {
- let mut uart = UART.lock();
- if uart.tx_buffer.len() + bytes.len() >= uart.tx_buffer.capacity() {
- return false;
- }
+ UART.modify(|uart| {
+ if uart.tx_buffer.len() + bytes.len() >= uart.tx_buffer.capacity() {
+ return false;
+ }
- for byte in bytes {
- put_byte(&mut uart, *byte);
- }
+ for byte in bytes {
+ put_byte(uart, *byte);
+ }
- true
+ true
+ })
}
/// Pushes a single byte over uart
-fn put_byte(uart: &mut LockGuard<OnceCell<UartDriver>>, byte: u8) {
+fn put_byte(uart: &mut OnceCell<UartDriver>, byte: u8) {
if uart.tx_data_available {
uart.tx_data_available = false;
uart.uart.txd.write(|w| unsafe { w.txd().bits(byte) });
@@ -115,7 +118,7 @@ fn put_byte(uart: &mut LockGuard<OnceCell<UartDriver>>, byte: u8) {
/// It's called when the enabled interrupts for uart0 are triggered
unsafe fn UART0() {
// Safety: interrupts are already turned off here, since we are inside an interrupt
- let uart = unsafe { UART.no_critical_section_lock() };
+ let uart = unsafe { UART.no_critical_section_lock_mut() };
if uart.uart.events_rxdrdy.read().bits() != 0 {
uart.uart.events_rxdrdy.reset();