hardware_sync

Low level hardware spin locks, barrier and processor event APIs. More...

Typedefs

typedef volatile uint32_t spin_lock_t
 A spin lock identifier.
 

Functions

static __force_inline void __sev (void)
 Insert a SEV instruction in to the code path. More...
 
static __force_inline void __wfe (void)
 Insert a WFE instruction in to the code path. More...
 
static __force_inline void __wfi (void)
 Insert a WFI instruction in to the code path. More...
 
static __force_inline void __dmb (void)
 Insert a DMB instruction in to the code path. More...
 
static __force_inline void __dsb (void)
 Insert a DSB instruction in to the code path. More...
 
static __force_inline void __isb (void)
 Insert a ISB instruction in to the code path. More...
 
static __force_inline void __mem_fence_acquire (void)
 Acquire a memory fence.
 
static __force_inline void __mem_fence_release (void)
 Release a memory fence.
 
static __force_inline uint32_t save_and_disable_interrupts (void)
 Save and disable interrupts. More...
 
static __force_inline void restore_interrupts (uint32_t status)
 Restore interrupts to a specified state. More...
 
static __force_inline spin_lock_tspin_lock_instance (uint lock_num)
 Get HW Spinlock instance from number. More...
 
static __force_inline uint spin_lock_get_num (spin_lock_t *lock)
 Get HW Spinlock number from instance. More...
 
static __force_inline void spin_lock_unsafe_blocking (spin_lock_t *lock)
 Acquire a spin lock without disabling interrupts (hence unsafe) More...
 
static __force_inline void spin_unlock_unsafe (spin_lock_t *lock)
 Release a spin lock without re-enabling interrupts. More...
 
static __force_inline uint32_t spin_lock_blocking (spin_lock_t *lock)
 Acquire a spin lock safely. More...
 
static bool is_spin_locked (spin_lock_t *lock)
 Check to see if a spinlock is currently acquired elsewhere. More...
 
static __force_inline void spin_unlock (spin_lock_t *lock, uint32_t saved_irq)
 Release a spin lock safely. More...
 
spin_lock_tspin_lock_init (uint lock_num)
 Initialise a spin lock. More...
 
void spin_locks_reset (void)
 Release all spin locks.
 
uint next_striped_spin_lock_num (void)
 Return a spin lock number from the striped range. More...
 
void spin_lock_claim (uint lock_num)
 Mark a spin lock as used. More...
 
void spin_lock_claim_mask (uint32_t lock_num_mask)
 Mark multiple spin locks as used. More...
 
void spin_lock_unclaim (uint lock_num)
 Mark a spin lock as no longer used. More...
 
int spin_lock_claim_unused (bool required)
 Claim a free spin lock. More...
 
bool spin_lock_is_claimed (uint lock_num)
 Determine if a spin lock is claimed. More...
 

Detailed Description

Low level hardware spin locks, barrier and processor event APIs.

Spin Locks

The RP2040 provides 32 hardware spin locks, which can be used to manage mutually-exclusive access to shared software and hardware resources.

Generally each spin lock itself is a shared resource, i.e. the same hardware spin lock can be used by multiple higher level primitives (as long as the spin locks are neither held for long periods, nor held concurrently with other spin locks by the same core - which could lead to deadlock). A hardware spin lock that is exclusively owned can be used individually without more flexibility and without regard to other software. Note that no hardware spin lock may be acquired re-entrantly (i.e. hardware spin locks are not on their own safe for use by both thread code and IRQs) however the default spinlock related methods here (e.g. spin_lock_blocking) always disable interrupts while the lock is held as use by IRQ handlers and user code is common/desirable, and spin locks are only expected to be held for brief periods.

The SDK uses the following default spin lock assignments, classifying which spin locks are reserved for exclusive/special purposes vs those suitable for more general shared use:

Number (ID) Description
0-13 Currently reserved for exclusive use by the SDK and other libraries. If you use these spin locks, you risk breaking SDK or other library functionality. Each reserved spin lock used individually has its own PICO_SPINLOCK_ID so you can search for those.
14,15 (PICO_SPINLOCK_ID_OS1 and PICO_SPINLOCK_ID_OS2). Currently reserved for exclusive use by an operating system (or other system level software) co-existing with the SDK.
16-23 (PICO_SPINLOCK_ID_STRIPED_FIRST - PICO_SPINLOCK_ID_STRIPED_LAST). Spin locks from this range are assigned in a round-robin fashion via next_striped_spin_lock_num(). These spin locks are shared, but assigning numbers from a range reduces the probability that two higher level locking primitives using striped spin locks will actually be using the same spin lock.
24-31 (PICO_SPINLOCK_ID_CLAIM_FREE_FIRST - PICO_SPINLOCK_ID_CLAIM_FREE_LAST). These are reserved for exclusive use and are allocated on a first come first served basis at runtime via spin_lock_claim_unused()

Function Documentation

◆ __dmb()

static __force_inline void __dmb ( void  )
static

Insert a DMB instruction in to the code path.

The DMB (data memory barrier) acts as a memory barrier, all memory accesses prior to this instruction will be observed before any explicit access after the instruction.

◆ __dsb()

static __force_inline void __dsb ( void  )
static

Insert a DSB instruction in to the code path.

The DSB (data synchronization barrier) acts as a special kind of data memory barrier (DMB). The DSB operation completes when all explicit memory accesses before this instruction complete.

◆ __isb()

static __force_inline void __isb ( void  )
static

Insert a ISB instruction in to the code path.

ISB acts as an instruction synchronization barrier. It flushes the pipeline of the processor, so that all instructions following the ISB are fetched from cache or memory again, after the ISB instruction has been completed.

◆ __sev()

static __force_inline void __sev ( void  )
static

Insert a SEV instruction in to the code path.

The SEV (send event) instruction sends an event to both cores.

◆ __wfe()

static __force_inline void __wfe ( void  )
static

Insert a WFE instruction in to the code path.

The WFE (wait for event) instruction waits until one of a number of events occurs, including events signalled by the SEV instruction on either core.

◆ __wfi()

static __force_inline void __wfi ( void  )
static

Insert a WFI instruction in to the code path.

The WFI (wait for interrupt) instruction waits for a interrupt to wake up the core.

◆ is_spin_locked()

static bool is_spin_locked ( spin_lock_t lock)
inlinestatic

Check to see if a spinlock is currently acquired elsewhere.

Parameters
lockSpinlock instance

◆ next_striped_spin_lock_num()

uint next_striped_spin_lock_num ( void  )

Return a spin lock number from the striped range.

Returns a spin lock number in the range PICO_SPINLOCK_ID_STRIPED_FIRST to PICO_SPINLOCK_ID_STRIPED_LAST in a round robin fashion. This does not grant the caller exclusive access to the spin lock, so the caller must:

  1. Abide (with other callers) by the contract of only holding this spin lock briefly (and with IRQs disabled - the default via spin_lock_blocking()), and not whilst holding other spin locks.
  2. Be OK with any contention caused by the - brief due to the above requirement - contention with other possible users of the spin lock.
Returns
lock_num a spin lock number the caller may use (non exclusively)
See also
PICO_SPINLOCK_ID_STRIPED_FIRST
PICO_SPINLOCK_ID_STRIPED_LAST

◆ restore_interrupts()

static __force_inline void restore_interrupts ( uint32_t  status)
static

Restore interrupts to a specified state.

Parameters
statusPrevious interrupt status from save_and_disable_interrupts()

◆ save_and_disable_interrupts()

static __force_inline uint32_t save_and_disable_interrupts ( void  )
static

Save and disable interrupts.

Returns
The prior interrupt enable status for restoration later via restore_interrupts()

◆ spin_lock_blocking()

static __force_inline uint32_t spin_lock_blocking ( spin_lock_t lock)
static

Acquire a spin lock safely.

This function will disable interrupts prior to acquiring the spinlock

Parameters
lockSpinlock instance
Returns
interrupt status to be used when unlocking, to restore to original state

◆ spin_lock_claim()

void spin_lock_claim ( uint  lock_num)

Mark a spin lock as used.

Method for cooperative claiming of hardware. Will cause a panic if the spin lock is already claimed. Use of this method by libraries detects accidental configurations that would fail in unpredictable ways.

Parameters
lock_numthe spin lock number

◆ spin_lock_claim_mask()

void spin_lock_claim_mask ( uint32_t  lock_num_mask)

Mark multiple spin locks as used.

Method for cooperative claiming of hardware. Will cause a panic if any of the spin locks are already claimed. Use of this method by libraries detects accidental configurations that would fail in unpredictable ways.

Parameters
lock_num_maskBitfield of all required spin locks to claim (bit 0 == spin lock 0, bit 1 == spin lock 1 etc)

◆ spin_lock_claim_unused()

int spin_lock_claim_unused ( bool  required)

Claim a free spin lock.

Parameters
requiredif true the function will panic if none are available
Returns
the spin lock number or -1 if required was false, and none were free

◆ spin_lock_get_num()

static __force_inline uint spin_lock_get_num ( spin_lock_t lock)
static

Get HW Spinlock number from instance.

Parameters
lockThe Spinlock instance
Returns
The Spinlock ID

◆ spin_lock_init()

spin_lock_t* spin_lock_init ( uint  lock_num)

Initialise a spin lock.

The spin lock is initially unlocked

Parameters
lock_numThe spin lock number
Returns
The spin lock instance

◆ spin_lock_instance()

static __force_inline spin_lock_t* spin_lock_instance ( uint  lock_num)
static

Get HW Spinlock instance from number.

Parameters
lock_numSpinlock ID
Returns
The spinlock instance

◆ spin_lock_is_claimed()

bool spin_lock_is_claimed ( uint  lock_num)

Determine if a spin lock is claimed.

Parameters
lock_numthe spin lock number
Returns
true if claimed, false otherwise
See also
spin_lock_claim
spin_lock_claim_mask

◆ spin_lock_unclaim()

void spin_lock_unclaim ( uint  lock_num)

Mark a spin lock as no longer used.

Method for cooperative claiming of hardware.

Parameters
lock_numthe spin lock number to release

◆ spin_lock_unsafe_blocking()

static __force_inline void spin_lock_unsafe_blocking ( spin_lock_t lock)
static

Acquire a spin lock without disabling interrupts (hence unsafe)

Parameters
lockSpinlock instance

◆ spin_unlock()

static __force_inline void spin_unlock ( spin_lock_t lock,
uint32_t  saved_irq 
)
static

Release a spin lock safely.

This function will re-enable interrupts according to the parameters.

Parameters
lockSpinlock instance
saved_irqReturn value from the spin_lock_blocking() function.
Returns
interrupt status to be used when unlocking, to restore to original state
See also
spin_lock_blocking()

◆ spin_unlock_unsafe()

static __force_inline void spin_unlock_unsafe ( spin_lock_t lock)
static

Release a spin lock without re-enabling interrupts.

Parameters
lockSpinlock instance