mirror of
https://github.com/italicsjenga/rp-hal-boards.git
synced 2025-01-23 01:36:35 +11:00
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:
parent
0eb65ee99b
commit
bac6714f09
4 changed files with 57 additions and 26 deletions
40
rp2040-hal/src/atomic_register_access.rs
Normal file
40
rp2040-hal/src/atomic_register_access.rs
Normal 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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue