Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions on-target-tests/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ fn main() {
let memory_x = include_bytes!("memory_rp2040.x");
#[cfg(feature = "rp235x")]
let memory_x = include_bytes!("memory_rp235x.x");
#[cfg(not(any(feature = "rp2040", feature = "rp235x")))]
compile_error!("No target feature enabled");

let mut f = File::create(out.join("memory.x")).unwrap();
f.write_all(memory_x).unwrap();
println!("cargo:rerun-if-changed=memory.x");
Expand Down
22 changes: 10 additions & 12 deletions rp2040-hal/src/async_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,12 @@ pub trait AsyncPeripheral: sealed::Wakeable {
pub(crate) struct CancellablePollFn<'periph, Periph, PFn, EnIrqFn, CancelFn, OutputTy>
where
Periph: sealed::Wakeable,
CancelFn: FnMut(&mut Periph),
CancelFn: FnOnce(&mut Periph),
{
periph: &'periph mut Periph,
poll: PFn,
enable_irq: EnIrqFn,
cancel: CancelFn,
done: bool,
cancel: Option<CancelFn>,
// captures F's return type.
phantom: PhantomData<OutputTy>,
}
Expand All @@ -80,7 +79,7 @@ where
Periph: sealed::Wakeable,
PFn: FnMut(&mut Periph) -> Poll<OutputTy>,
EnIrqFn: FnMut(&mut Periph),
CancelFn: FnMut(&mut Periph),
CancelFn: FnOnce(&mut Periph),
{
pub(crate) fn new(
periph: &'p mut Periph,
Expand All @@ -92,8 +91,7 @@ where
periph,
poll,
enable_irq,
cancel,
done: false,
cancel: Some(cancel),
phantom: PhantomData,
}
}
Expand All @@ -105,7 +103,7 @@ where
Periph: sealed::Wakeable,
PFn: FnMut(&mut Periph) -> Poll<OutputTy>,
EnIrqFn: FnMut(&mut Periph),
CancelFn: FnMut(&mut Periph),
CancelFn: FnOnce(&mut Periph),
{
type Output = OutputTy;

Expand All @@ -115,15 +113,15 @@ where
ref mut periph,
poll: ref mut is_ready,
enable_irq: ref mut setup_flags,
ref mut done,
ref mut cancel,
..
} = unsafe { self.get_unchecked_mut() };
let r = (is_ready)(periph);
if r.is_pending() {
Periph::waker().register(cx.waker());
(setup_flags)(periph);
} else {
*done = true;
*cancel = None;
}
r
}
Expand All @@ -132,12 +130,12 @@ impl<Periph, PFn, EnIrqFn, CancelFn, OutputTy> Drop
for CancellablePollFn<'_, Periph, PFn, EnIrqFn, CancelFn, OutputTy>
where
Periph: sealed::Wakeable,
CancelFn: FnMut(&mut Periph),
CancelFn: FnOnce(&mut Periph),
{
fn drop(&mut self) {
if !self.done {
if let Some(cancel) = self.cancel.take() {
Periph::waker().clear();
(self.cancel)(self.periph);
cancel(self.periph);
}
}
}
1 change: 1 addition & 0 deletions rp2040-hal/src/i2c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ impl ValidAddress for u16 {

/// I2C error
#[non_exhaustive]
#[derive(PartialEq, Eq)]
pub enum Error {
/// I2C abort with error
Abort(u32),
Expand Down
24 changes: 16 additions & 8 deletions rp2040-hal/src/i2c/peripheral.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,10 +210,10 @@ impl<T: Deref<Target = RegisterBlock>, PINS> Iterator for I2C<T, PINS, Periphera
}
}
impl<T: Deref<Target = RegisterBlock>, PINS> I2C<T, PINS, Peripheral> {
/// Returns the next i2c event if any.
pub fn next_event(&mut self) -> Option<Event> {
let stat = self.i2c.ic_raw_intr_stat().read();

fn internal_next_event(
&mut self,
stat: rp2040_pac::i2c0::ic_raw_intr_stat::R,
) -> Option<Event> {
match self.mode.state {
State::Idle if stat.start_det().bit_is_set() => {
self.i2c.ic_clr_start_det().read();
Expand Down Expand Up @@ -241,7 +241,7 @@ impl<T: Deref<Target = RegisterBlock>, PINS> I2C<T, PINS, Peripheral> {
State::Read if stat.rd_req().bit_is_set() => Some(Event::TransferRead),
State::Write if !self.rx_fifo_empty() => Some(Event::TransferWrite),

State::Read | State::Write if stat.restart_det().bit_is_set() => {
State::Read | State::Write | State::Active if stat.restart_det().bit_is_set() => {
self.i2c.ic_clr_restart_det().read();
self.i2c.ic_clr_start_det().read();
self.mode.state = State::Active;
Expand All @@ -258,6 +258,13 @@ impl<T: Deref<Target = RegisterBlock>, PINS> I2C<T, PINS, Peripheral> {
_ => None,
}
}

/// Returns the next i2c event if any.
pub fn next_event(&mut self) -> Option<Event> {
let stat = self.i2c.ic_raw_intr_stat().read();

self.internal_next_event(stat)
}
}

macro_rules! impl_wakeable {
Expand Down Expand Up @@ -291,12 +298,13 @@ where
{
/// Asynchronously waits for an Event.
pub async fn wait_next(&mut self) -> Event {
let mut stat = self.i2c.ic_raw_intr_stat().read();
loop {
if let Some(evt) = self.next_event() {
if let Some(evt) = self.internal_next_event(stat) {
return evt;
}

CancellablePollFn::new(
stat = CancellablePollFn::new(
self,
|me| {
let stat = me.i2c.ic_raw_intr_stat().read();
Expand All @@ -306,7 +314,7 @@ where
|| stat.rd_req().bit_is_set()
|| stat.rx_full().bit_is_set()
{
Poll::Ready(())
Poll::Ready(stat)
} else {
Poll::Pending
}
Expand Down
101 changes: 87 additions & 14 deletions rp2040-hal/src/pio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,27 @@ use crate::{
typelevel::Sealed,
};

mod non_blocking;

const PIO_INSTRUCTION_COUNT: usize = 32;

impl Sealed for PIO0 {}
impl Sealed for PIO1 {}

/// PIO Instance
pub trait PIOExt: Deref<Target = RegisterBlock> + SubsystemReset + Sized + Send + Sealed {
/// RX FIFO depth
const RX_FIFO_DEPTH: usize;

/// TX FIFO depth
const TX_FIFO_DEPTH: usize;

/// Associated Pin Function.
type PinFunction: Function;

/// Returns a pointer to the PIO’s Register Block
fn ptr() -> *const RegisterBlock;

/// Create a new PIO wrapper and split the state machines into individual objects.
#[allow(clippy::type_complexity)] // Required for symmetry with PIO::free().
fn split(
Expand Down Expand Up @@ -76,13 +87,23 @@ pub trait PIOExt: Deref<Target = RegisterBlock> + SubsystemReset + Sized + Send
}

impl PIOExt for PIO0 {
const RX_FIFO_DEPTH: usize = 4;
const TX_FIFO_DEPTH: usize = 4;
type PinFunction = FunctionPio0;
fn ptr() -> *const RegisterBlock {
PIO0::ptr()
}
fn id() -> usize {
0
}
}
impl PIOExt for PIO1 {
const RX_FIFO_DEPTH: usize = 4;
const TX_FIFO_DEPTH: usize = 4;
type PinFunction = FunctionPio1;
fn ptr() -> *const RegisterBlock {
PIO1::ptr()
}
fn id() -> usize {
1
}
Expand Down Expand Up @@ -576,9 +597,9 @@ pub struct Running;
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum PioIRQ {
#[allow(missing_docs)]
Irq0,
Irq0 = 0,
#[allow(missing_docs)]
Irq1,
Irq1 = 1,
}
impl PioIRQ {
const fn to_index(self) -> usize {
Expand Down Expand Up @@ -644,8 +665,8 @@ impl<SM: ValidStateMachine, State> StateMachine<SM, State> {
pub fn clear_fifos(&mut self) {
// Safety: all accesses to these registers are controlled by this instance
unsafe {
let sm = &self.sm.sm();
let sm_shiftctrl = &sm.sm_shiftctrl();
let sm = self.sm.sm();
let sm_shiftctrl = sm.sm_shiftctrl();
let mut current = false;
// Toggling the FIFO join state clears the fifo
sm_shiftctrl.modify(|r, w| {
Expand Down Expand Up @@ -679,10 +700,10 @@ impl<SM: ValidStateMachine, State> StateMachine<SM, State> {

// Safety: all accesses to these registers are controlled by this instance
unsafe {
let sm = &self.sm.sm();
let sm_pinctrl = &sm.sm_pinctrl();
let sm_instr = &sm.sm_instr();
let fstat = &self.sm.pio().fstat();
let sm = self.sm.sm();
let sm_pinctrl = sm.sm_pinctrl();
let sm_instr = sm.sm_instr();
let fstat = self.sm.pio().fstat();

let operands = if sm.sm_shiftctrl().read().autopull().bit_is_set() {
OUT
Expand Down Expand Up @@ -771,9 +792,9 @@ impl<SM: ValidStateMachine> StateMachine<SM, Stopped> {
// Safety: all accesses to these registers are controlled by this instance
unsafe {
let sm = self.sm.sm();
let sm_pinctrl = &sm.sm_pinctrl();
let sm_execctrl = &sm.sm_execctrl();
let sm_instr = &sm.sm_instr();
let sm_pinctrl = sm.sm_pinctrl();
let sm_execctrl = sm.sm_execctrl();
let sm_instr = sm.sm_instr();

// sideset_count is implicitly set to 0 when the set_base/set_count are written (rather
// than modified)
Expand Down Expand Up @@ -1271,8 +1292,8 @@ impl<SM: ValidStateMachine> StateMachine<SM, Running> {
// Safety: all accesses to these registers are controlled by this instance
unsafe {
let sm = self.sm.sm();
let sm_pinctrl = &sm.sm_pinctrl();
let sm_instr = &sm.sm_instr();
let sm_pinctrl = sm.sm_pinctrl();
let sm_instr = sm.sm_instr();

// save exec_ctrl & make side_set optional
let mut saved_sideset_count = 0;
Expand Down Expand Up @@ -1380,6 +1401,32 @@ impl<SM: ValidStateMachine, RxSize: TransferSize> Rx<SM, RxSize> {
unsafe { self.block().fstat().read().rxfull().bits() & (1 << SM::id()) != 0 }
}

/// Reads the number of word in the fifo
pub fn fifo_level(&self) -> usize {
// Safety: read-only access without side-effect
let flevel = unsafe { self.block().flevel().read() };
(match SM::id() {
0 => flevel.rx0().bits(),
1 => flevel.rx1().bits(),
2 => flevel.rx2().bits(),
3 => flevel.rx3().bits(),
_ => unreachable!(),
}) as usize
}

/// Returns the FIFO depth.
pub fn fifo_depth(&self) -> usize {
// Safety: read-only access without side-effect
let block = unsafe { self.block() };
let join_rx = block.sm(SM::id()).sm_shiftctrl().read().fjoin_rx().bit();
let depth = block.dbg_cfginfo().read().fifo_depth().bits() as usize;
if join_rx {
depth * 2
} else {
depth
}
}

/// Enable RX FIFO not empty interrupt.
///
/// This interrupt is raised when the RX FIFO is not empty, i.e. one could read more data from it.
Expand Down Expand Up @@ -1498,7 +1545,7 @@ impl<SM: ValidStateMachine, TxSize: TransferSize> Tx<SM, TxSize> {
/// This is a value between 0 and 39. Each FIFO on each state machine on
/// each PIO has a unique value.
pub fn dreq_value(&self) -> u8 {
if self.block as usize == 0x5020_0000usize {
if self.block == PIO0::ptr() {
TREQ_SEL_A::PIO0_TX0 as u8 + (SM::id() as u8)
} else {
TREQ_SEL_A::PIO1_TX0 as u8 + (SM::id() as u8)
Expand Down Expand Up @@ -1588,6 +1635,32 @@ impl<SM: ValidStateMachine, TxSize: TransferSize> Tx<SM, TxSize> {
unsafe { self.block().fstat().read().txfull().bits() & (1 << SM::id()) != 0 }
}

/// Reads the number of word in the FIFO
pub fn fifo_level(&self) -> usize {
// Safety: read-only access without side-effect
let flevel = unsafe { self.block().flevel().read() };
(match SM::id() {
0 => flevel.tx0().bits(),
1 => flevel.tx1().bits(),
2 => flevel.tx2().bits(),
3 => flevel.tx3().bits(),
_ => unreachable!(),
}) as usize
}

/// Returns the FIFO depth.
pub fn fifo_depth(&self) -> usize {
// Safety: read-only access without side-effect
let block = unsafe { self.block() };
let join_tx = block.sm(SM::id()).sm_shiftctrl().read().fjoin_tx().bit();
let depth = block.dbg_cfginfo().read().fifo_depth().bits() as usize;
if join_tx {
depth * 2
} else {
depth
}
}

/// Enable TX FIFO not full interrupt.
///
/// This interrupt is raised when the TX FIFO is not full, i.e. one could push more data to it.
Expand Down
Loading