Use volatile register access for gpio interrupts (#170)

* Use volatile register access for gpio interrupts

* Provide functions for atomic register updates

* Use atomic register access functions in pio.rs

* Improve doc comments

* Limit visibility of atomic register access functions

Also remove write_xor for now, as it's not yet used anywhere
This commit is contained in:
Jan Niehusmann 2021-10-22 14:30:30 +02:00 committed by GitHub
parent 0eb65ee99b
commit bac6714f09
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 57 additions and 26 deletions

View file

@ -0,0 +1,40 @@
//! Provide atomic access to peripheral registers
//!
//! This feature is not available for all peripherals.
//! See [section 2.1.2 of the RP2040 datasheet][section_2_1_2] for details.
//!
//! [section_2_1_2]: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#atomic-rwtype
use core::ptr::write_volatile;
/// Perform atomic bitmask set operation on register
///
/// See [section 2.1.2 of the RP2040 datasheet][section_2_1_2] for details.
///
/// [section_2_1_2]: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#atomic-rwtype
///
/// # Safety
///
/// In addition to the requirements of [core::ptr::write_volatile],
/// `register` must point to a register providing atomic aliases.
#[inline]
pub(crate) unsafe fn write_bitmask_set(register: *mut u32, bits: u32) {
let alias = (register as usize + 0x2000) as *mut u32;
write_volatile(alias, bits);
}
/// Perform atomic bitmask clear operation on register
///
/// See [section 2.1.2 of the RP2040 datasheet][section_2_1_2] for details.
///
/// [section_2_1_2]: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#atomic-rwtype
///
/// # Safety
///
/// In addition to the requirements of [core::ptr::write_volatile],
/// `register` must point to a register providing atomic aliases.
#[inline]
pub(crate) unsafe fn write_bitmask_clear(register: *mut u32, bits: u32) {
let alias = (register as usize + 0x3000) as *mut u32;
write_volatile(alias, bits);
}

View file

@ -4,8 +4,10 @@ use super::{
InputOverride, Interrupt, InterruptOverride, OutputDriveStrength, OutputEnableOverride,
OutputOverride, OutputSlewRate,
};
use crate::atomic_register_access::{write_bitmask_clear, write_bitmask_set};
use crate::gpio::dynpin::{DynDisabled, DynFunction, DynInput, DynOutput, DynPinMode};
use crate::pac;
use core::ptr::read_volatile;
//==============================================================================
// ModeFields
@ -278,7 +280,7 @@ pub(super) unsafe trait RegisterInterface {
.as_ptr()
.add(num / 8 + cpuid as usize * 12);
let bit_in_reg = num % 8 * 4 + interrupt as usize;
(*reg & (1 << bit_in_reg)) != 0
(read_volatile(reg) & (1 << bit_in_reg)) != 0
}
}
@ -293,7 +295,7 @@ pub(super) unsafe trait RegisterInterface {
.as_ptr()
.add(num / 8 + cpuid as usize * 12);
let bit_in_reg = num % 8 * 4 + interrupt as usize;
(*reg & (1 << bit_in_reg)) != 0
(read_volatile(reg) & (1 << bit_in_reg)) != 0
}
}
@ -309,9 +311,9 @@ pub(super) unsafe trait RegisterInterface {
.add(num / 8 + cpuid as usize * 12);
let bit_in_reg = num % 8 * 4 + interrupt as usize;
if enabled {
*reg |= 1 << bit_in_reg;
write_bitmask_set(reg, 1 << bit_in_reg);
} else {
*reg &= !(1 << bit_in_reg);
write_bitmask_clear(reg, 1 << bit_in_reg);
}
}
}
@ -327,7 +329,7 @@ pub(super) unsafe trait RegisterInterface {
.as_ptr()
.add(num / 8 + cpuid as usize * 12);
let bit_in_reg = num % 8 * 4 + interrupt as usize;
(*reg & (1 << bit_in_reg)) != 0
(read_volatile(reg) & (1 << bit_in_reg)) != 0
}
}
@ -343,9 +345,9 @@ pub(super) unsafe trait RegisterInterface {
.add(num / 8 + cpuid as usize * 12);
let bit_in_reg = num % 8 * 4 + interrupt as usize;
if forced {
*reg |= 1 << bit_in_reg;
write_bitmask_set(reg, 1 << bit_in_reg);
} else {
*reg &= !(1 << bit_in_reg);
write_bitmask_clear(reg, 1 << bit_in_reg);
}
}
}

View file

@ -14,6 +14,7 @@ pub use paste;
pub extern crate rp2040_pac as pac;
pub mod adc;
pub(crate) mod atomic_register_access;
pub mod clocks;
pub mod gpio;
pub mod i2c;

View file

@ -1,6 +1,9 @@
//! Programmable IO (PIO)
/// See [Chapter 3](https://rptl.io/pico-datasheet) for more details.
use crate::resets::SubsystemReset;
use crate::{
atomic_register_access::{write_bitmask_clear, write_bitmask_set},
resets::SubsystemReset,
};
use pio::{Program, SideSet, Wrap};
use rp2040_pac::{PIO0, PIO1};
@ -430,26 +433,16 @@ impl<SM: ValidStateMachine> UninitStateMachine<SM> {
}
fn set_ctrl_bits(&mut self, bits: u32) {
const ATOMIC_SET_OFFSET: usize = 0x2000;
// Safety: We only use the atomic alias of the register.
unsafe {
(*self.block)
.ctrl
.as_ptr()
.add(ATOMIC_SET_OFFSET / 4)
.write_volatile(bits);
write_bitmask_set((*self.block).ctrl.as_ptr(), bits);
}
}
fn clear_ctrl_bits(&mut self, bits: u32) {
const ATOMIC_CLEAR_OFFSET: usize = 0x3000;
// Safety: We only use the atomic alias of the register.
unsafe {
(*self.block)
.ctrl
.as_ptr()
.add(ATOMIC_CLEAR_OFFSET / 4)
.write_volatile(bits);
write_bitmask_clear((*self.block).ctrl.as_ptr(), bits);
}
}
@ -638,14 +631,9 @@ impl<'sm, SM: ValidStateMachine> Drop for Synchronize<'sm, SM> {
// Restart the clocks of all state machines specified by the mask.
// Bits 11:8 of CTRL contain CLKDIV_RESTART.
let sm_mask = self.sm_mask << 8;
const ATOMIC_SET_OFFSET: usize = 0x2000;
// Safety: We only use the atomic alias of the register.
unsafe {
(*self.sm.sm.block)
.ctrl
.as_ptr()
.add(ATOMIC_SET_OFFSET / 4)
.write_volatile(sm_mask as u32);
write_bitmask_set((*self.sm.sm.block).ctrl.as_ptr(), sm_mask as u32);
}
}
}