v2.0.0
Macros | Functions
hardware_sync
Hardware APIs

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

## Macros
#define | SW_SPIN_LOCK_TYPE volatile uint8_t
| A spin lock identifier.

## Functions
static __force_inline void | __nop (void)
| Insert a NOP instruction in to the code path. More...
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 void | restore_interrupts_from_disabled (uint32_t status)
| Restore interrupts to a specified state with restricted transitions. More...
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...
static __force_inline spin_lock_t * | spin_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_t * | spin_lock_init (uint lock_num)
| Initialise a spin lock. More...
void | spin_locks_reset (void)
| Release all spin locks.

## Detailed Description

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

## Spin Locks

The RP-series microcontrollers provide 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.

RP2350 Warning. Due to erratum RP2350-E2, writes to new SIO registers above an offset of +0x180 alias the spinlocks, causing spurious lock releases. This SDK by default uses atomic memory accesses to implement the hardware_sync_spin_lock API, as a workaround on RP2350 A2.

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.

## ◆ __nop()

static __force_inline void __nop | ( | void |  | ) |
| static

Insert a NOP instruction in to the code path.

NOP does nothing for one cycle. On RP2350 Arm binaries this is forced to be a 32-bit instruction to avoid dual-issue of NOPs.

## ◆ __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

  lock | Spinlock 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

  status | Previous interrupt status from save_and_disable_interrupts()

## ◆ restore_interrupts_from_disabled()

static __force_inline void restore_interrupts_from_disabled | ( | uint32_t | status | ) |
| static

Restore interrupts to a specified state with restricted transitions.

This method should only be used when the interrupt state is known to be disabled, e.g. when paired with save_and_disable_interrupts()

Parameters

  status | Previous 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

  lock | Spinlock 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_num | the 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_mask | Bitfield 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

  required | if 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

  lock | The 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_num | The 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_num | Spinlock 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_num | the 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_num | the 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

  lock | Spinlock 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

  lock | Spinlock instance
  saved_irq | Return value from the spin_lock_blocking() function.

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

  lock | Spinlock instance