|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
Inter-Processor Communication (IPC) HAL driver – sync API. More...
#include <stdint.h>#include "ra8_attributes.h"#include "ra8_err.h"#include "ra8_ipc_regs.h"#include "ra8_ipc_types.h"Go to the source code of this file.
Functions | |
| static void | ra8_ipc_barrier (void) |
| Cross-core data-memory barrier for IPC publish + lock ordering. | |
| ra8_err_t | ra8_ipc_sem_try_take (uint8_t sem_id) |
| Test-and-set acquire on one IPC hardware semaphore. | |
| ra8_err_t | ra8_ipc_sem_take_timeout (uint8_t sem_id, uint16_t max_spins) |
| Bounded-spin take on one IPC hardware semaphore. | |
| ra8_err_t | ra8_ipc_sem_release (uint8_t sem_id) |
| Release one IPC hardware semaphore. | |
| ra8_err_t | ra8_ipc_sem_is_locked (uint8_t sem_id, bool *out_locked) |
| Predicate: is the semaphore currently locked? | |
| ra8_err_t | ra8_ipc_nmi_send (uint8_t unit) |
| Issue an inter-processor NMI to the peer core. | |
| ra8_err_t | ra8_ipc_nmi_clear (uint8_t unit) |
| Acknowledge an inter-processor NMI on the local core. | |
| ra8_err_t | ra8_ipc_nmi_get_status (uint8_t unit, bool *out_pending) |
| Read NMISTA.NMI for one IPC NMI unit. | |
| ra8_err_t | ra8_ipc_attach_nmi_handler (ra8_ipc_nmi_fn_t fn, void *ctx) |
| Attach a callback for inter-processor NMI dispatch. | |
| void | ra8_ipc_dispatch_nmi (uint8_t unit) |
| Drive the NMI dispatch path for one unit. | |
| ra8_err_t | ra8_ipc_attach_handler (ra8_ipc_event_fn_t fn, void *ctx) |
| Attach a single event callback shared across all channels. | |
| ra8_err_t | ra8_ipc_attach_event_handler (uint8_t channel, ra8_ipc_irq_event_id_t event_id, ra8_ipc_irq_fn_t fn, void *ctx) |
| Attach a callback for a single IRQ event line on a channel. | |
| void | ra8_ipc_dispatch (uint8_t channel) |
| Drive the event callback for one channel. | |
| ra8_err_t | ra8_ipc_install_isr (uint8_t unit, uint8_t priority) |
| Wire the IPC IRQ event into the ISR table. | |
| ra8_err_t | ra8_ipc_uninstall_isr (uint8_t unit) |
| Tear down a previously installed IPC ISR. | |
| ra8_err_t | ra8_ipc_ring_init (ra8_ipc_ring_t *ring) |
| Initialise a producer/consumer ring backed by shared SRAM. | |
| ra8_err_t | ra8_ipc_ring_produce (ra8_ipc_ring_t *ring, uint32_t payload) |
| Push one word into the shared-memory ring (producer side). | |
| ra8_err_t | ra8_ipc_ring_consume (ra8_ipc_ring_t *ring, uint32_t *out_payload) |
| Pop one word from the shared-memory ring (consumer side). | |
| ra8_err_t | ra8_ipc_ring_is_empty (const ra8_ipc_ring_t *ring, bool *out_empty) |
| Predicate: ring empty? | |
| ra8_err_t | ra8_ipc_ring_is_full (const ra8_ipc_ring_t *ring, bool *out_full) |
| Predicate: ring full? | |
Inter-Processor Communication (IPC) HAL driver – sync API.
Hardware-semaphore, NMI-surface, maskable-interrupt dispatch, and shared-memory ring-buffer protocol prototypes for the RA8D2 IPC mailbox driver. Split out of ra8_ipc.h so each header stays within the repository file-size budget; ra8_ipc.h re-includes this header so existing consumers are unaffected.
Definition in file ra8_ipc_sync.h.
|
nodiscard |
Attach a callback for a single IRQ event line on a channel.
Each FIFO channel exposes 8 maskable IRQ event lines (HUM Ch 3.2.10 p 214). This API lets each line have its own decoded callback so application code does not have to walk the bitmask returned by ra8_ipc_dispatch.
| [in] | channel | Channel id 0..3. |
| [in] | event_id | IRQ event line 0..7. |
| [in] | fn | Callback fired when this line is observed in STA. NULL detaches. |
| [in] | ctx | Opaque context handed to fn. |
| k_ra8_ok | Stored. |
| k_ra8_err_invalid_arg | channel >= 4 or event_id > 7. |
Definition at line 716 of file ra8_ipc.c.
References ra8_ipc_irq_slot_t::ctx, ra8_ipc_irq_slot_t::fn, k_ra8_err_invalid_arg, k_ra8_ipc_channel_count, k_ra8_ipc_irq_event_count, k_ra8_ok, and s_ipc_channels.
Referenced by arm_ipc_wake().
|
nodiscard |
Attach a single event callback shared across all channels.
| [in] | fn | Callback fired during dispatch. NULL to detach. |
| [in] | ctx | Opaque context forwarded to fn. |
| k_ra8_ok | Always succeeds. |
Definition at line 709 of file ra8_ipc.c.
References k_ra8_ok, s_ipc_callback, and s_ipc_context.
|
nodiscard |
Attach a callback for inter-processor NMI dispatch.
Single global callback shared by both NMI units; unit is passed back as a parameter so the callback can demux IPC0NMI vs IPC1NMI. Pass NULL to detach.
| [in] | fn | Callback fired by ra8_ipc_dispatch_nmi. |
| [in] | ctx | Opaque context forwarded to fn. |
| k_ra8_ok | Always. |
Definition at line 267 of file ra8_ipc_sem_ring.c.
References k_ra8_ok, s_ipc_nmi_callback, and s_ipc_nmi_context.
|
inlinestatic |
Cross-core data-memory barrier for IPC publish + lock ordering.
Issues a full-system Data Memory Barrier (DMB SY) so a producer's Normal-memory payload and ring-index stores – and the accesses inside an IPCSEM critical section – become observable to the peer core BEFORE the Device-mapped FIFO/IRQ notification (TXD / ISET) or the IPCSEM release the peer wakes on. Without it the Cortex-M85 may post the notification ahead of the SRAM payload store, letting the Cortex-M33 consumer observe the new head index while the payload is still in the write buffer – a stale or torn message. The hand-rolled dual-core mailbox examples open-code the same dsb; this is the reusable-HAL equivalent (a DMB suffices: it orders accesses without waiting for completion the way DSB would).
Definition at line 70 of file ra8_ipc_sync.h.
Referenced by ra8_ipc_sem_release(), ra8_ipc_sem_take_timeout(), ra8_ipc_sem_try_take(), ra8_ipc_send_burst(), ra8_ipc_send_event(), ra8_ipc_send_message(), and ra8_ipc_send_message_retry().
| void ra8_ipc_dispatch | ( | uint8_t | channel | ) |
Drive the event callback for one channel.
Reads STA, masks against the per-channel event mask installed at init, and calls the registered callback if any bits remain. If the dispatched event includes k_ra8_ipc_event_msg_ready the driver pops one word from RXD and passes it to the callback. Decoded per-line callbacks attached via ra8_ipc_attach_event_handler are invoked one per IRQn bit present in the dispatched mask. Finally clears every dispatched event bit via CLR.
| [in] | channel | Channel id 0..3. |
Definition at line 733 of file ra8_ipc.c.
References r_ipc_channel_regs_t::CLR, internal_ra8_ipc_dispatch_irq_lines(), internal_ra8_ipc_event_to_clr(), k_ra8_ipc_channel_count, k_ra8_ipc_event_msg_ready, k_ra8_ipc_internal_event_full_mask, ra8_ipc_channel(), r_ipc_channel_regs_t::RXD, s_ipc_callback, s_ipc_channels, s_ipc_context, and r_ipc_channel_regs_t::STA.
Referenced by internal_ra8_ipc_isr(), and ipc0_receive_isr().
| void ra8_ipc_dispatch_nmi | ( | uint8_t | unit | ) |
Drive the NMI dispatch path for one unit.
Reads NMISTA.NMI; if set, calls the registered NMI callback and writes NMICLR.CLR to acknowledge. Safe to call when no NMI is pending (becomes a no-op).
| [in] | unit | NMI unit id 0..1. |
Definition at line 274 of file ra8_ipc_sem_ring.c.
References internal_ra8_ipc_get_nmi(), k_ra8_ipc_nmi_mask_bit, r_ipc_nmi_regs_t::NMICLR, r_ipc_nmi_regs_t::NMISTA, s_ipc_nmi_callback, and s_ipc_nmi_context.
|
nodiscard |
Wire the IPC IRQ event into the ISR table.
Registers ra8_ipc_dispatch_unit against the ELC event for the matching IPC unit (k_ra8_ipc_elc_event_irq0 for unit 0, k_ra8_ipc_elc_event_irq1 for unit 1). The vector trampoline then calls ra8_ipc_dispatch for both channels in the unit (channels 0+1 for unit 0; channels 2+3 for unit 1) so the per-line callbacks fire on every interrupt.
| [in] | unit | IPC unit id 0..1. |
| [in] | priority | NVIC priority forwarded to ra8_isr_register. |
| k_ra8_ok | Registered. |
| k_ra8_err_invalid_arg | unit >= 2. |
| k_ra8_err_no_mem | ra8_isr_register had no free slot. |
| k_ra8_err_exists | Already installed for that unit. |
Definition at line 804 of file ra8_ipc.c.
References internal_ra8_ipc_isr(), internal_ra8_ipc_unit_to_event(), k_ra8_err_exists, k_ra8_err_invalid_arg, k_ra8_ipc_nmi_unit_count, k_ra8_ok, ra8_isr_register(), and s_ipc_isr_state.
|
nodiscard |
Acknowledge an inter-processor NMI on the local core.
| [in] | unit | NMI unit id 0..1. |
| k_ra8_ok | CLR written. |
| k_ra8_err_invalid_arg | unit >= 2. |
Definition at line 243 of file ra8_ipc_sem_ring.c.
References internal_ra8_ipc_get_nmi(), k_ra8_err_invalid_arg, k_ra8_ipc_nmi_mask_bit, k_ra8_ok, and r_ipc_nmi_regs_t::NMICLR.
|
nodiscard |
Read NMISTA.NMI for one IPC NMI unit.
| [in] | unit | NMI unit id 0..1. |
| [out] | out_pending | Receives true if NMI is currently asserted. |
| k_ra8_ok | Status read. |
| k_ra8_err_invalid_arg | unit >= 2. |
| k_ra8_err_null_ptr | out_pending was NULL. |
Definition at line 255 of file ra8_ipc_sem_ring.c.
References internal_ra8_ipc_get_nmi(), k_ra8_err_invalid_arg, k_ra8_ipc_nmi_mask_bit, k_ra8_ok, r_ipc_nmi_regs_t::NMISTA, RA8_CHECK_NULL_PTR, and s_tag.
|
nodiscard |
Issue an inter-processor NMI to the peer core.
Writes 1 to IPCnNMISET.SET (HUM Ch 3.2.5 p 211 / Ch 3.2.8 p 213). The peer core observes IPCnNMISTA.NMI = 1 and (if the ICU has the IPCNMIn line enabled) takes the NMI exception.
| [in] | unit | NMI unit id (k_ra8_ipc_unit_ipc0 or k_ra8_ipc_unit_ipc1). |
| k_ra8_ok | SET written. |
| k_ra8_err_invalid_arg | unit >= 2. |
Definition at line 231 of file ra8_ipc_sem_ring.c.
References internal_ra8_ipc_get_nmi(), k_ra8_err_invalid_arg, k_ra8_ipc_nmi_mask_bit, k_ra8_ok, and r_ipc_nmi_regs_t::NMISET.
|
nodiscard |
Pop one word from the shared-memory ring (consumer side).
Acquires the semaphore, samples head/tail, copies slots[tail % capacity] into out_payload if non-empty, advances tail, releases the semaphore.
| [in] | ring | Non-NULL initialized descriptor. |
| [out] | out_payload | Receives the popped word. |
| k_ra8_ok | Word dequeued. |
| k_ra8_err_null_ptr | ring or out_payload was NULL. |
| k_ra8_err_busy | Semaphore not available. |
| k_ra8_err_no_data | Ring was empty. |
Definition at line 380 of file ra8_ipc_sem_ring.c.
References ra8_ipc_ring_t::capacity, ra8_ipc_ring_t::head, k_ra8_err_no_data, k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_ipc_sem_release(), ra8_ipc_sem_try_take(), s_tag, ra8_ipc_ring_t::sem_id, ra8_ipc_ring_t::slots, and ra8_ipc_ring_t::tail.
|
nodiscard |
Initialise a producer/consumer ring backed by shared SRAM.
Zeroes the head/tail counters and stores the descriptor for later ra8_ipc_ring_produce / ra8_ipc_ring_consume calls. Does not touch the underlying slots array; the caller is responsible for placing it in shared SRAM that both cores can see.
| [in] | ring | Non-NULL descriptor (caller-allocated). |
| k_ra8_ok | Initialized. |
| k_ra8_err_null_ptr | ring or one of its required pointer fields was NULL. |
| k_ra8_err_invalid_arg | capacity == 0 or non-power-of-two. |
Definition at line 340 of file ra8_ipc_sem_ring.c.
References ra8_ipc_ring_t::head, internal_ra8_ipc_ring_validate(), k_ra8_ok, RA8_CHECK_NULL_PTR, s_tag, ra8_ipc_ring_t::slots, and ra8_ipc_ring_t::tail.
|
nodiscard |
Predicate: ring empty?
| [in] | ring | Non-NULL descriptor. |
| [out] | out_empty | true when head == tail. |
| k_ra8_ok | Predicate evaluated. |
| k_ra8_err_null_ptr | ring or out_empty was NULL. |
Definition at line 399 of file ra8_ipc_sem_ring.c.
References ra8_ipc_ring_t::head, k_ra8_ok, RA8_CHECK_NULL_PTR, s_tag, and ra8_ipc_ring_t::tail.
|
nodiscard |
Predicate: ring full?
| [in] | ring | Non-NULL descriptor. |
| [out] | out_full | true when (head - tail) == capacity. |
| k_ra8_ok | Predicate evaluated. |
| k_ra8_err_null_ptr | ring or out_full was NULL. |
Definition at line 407 of file ra8_ipc_sem_ring.c.
References ra8_ipc_ring_t::capacity, ra8_ipc_ring_t::head, k_ra8_ok, RA8_CHECK_NULL_PTR, s_tag, and ra8_ipc_ring_t::tail.
|
nodiscard |
Push one word into the shared-memory ring (producer side).
Acquires ring->sem_id via ra8_ipc_sem_try_take, writes payload into slots[head % capacity], advances head, releases the semaphore, then signals the consumer through ra8_ipc_send_event(ring->channel, ring->notify_id).
| [in] | ring | Non-NULL initialized descriptor. |
| [in] | payload | 32-bit word to enqueue. |
| k_ra8_ok | Word enqueued and notification sent. |
| k_ra8_err_null_ptr | ring was NULL. |
| k_ra8_err_busy | Ring full or semaphore not available. |
Definition at line 355 of file ra8_ipc_sem_ring.c.
References ra8_ipc_ring_t::capacity, ra8_ipc_ring_t::channel, ra8_ipc_ring_t::head, k_ra8_err_busy, k_ra8_ok, ra8_ipc_ring_t::notify_id, RA8_CHECK_NULL_PTR, ra8_ipc_sem_release(), ra8_ipc_sem_try_take(), ra8_ipc_send_event(), s_tag, ra8_ipc_ring_t::sem_id, ra8_ipc_ring_t::slots, and ra8_ipc_ring_t::tail.
|
nodiscard |
Predicate: is the semaphore currently locked?
Note that simply reading IPCSEMn through a 32-bit access takes the semaphore (HUM Ch 3.2.3 p 210 NOTE). This API therefore samples the LOCK bit by reading and, if the read observed "unlocked", undoes the probe's own take with the write-1-to-clear release command so the register reads back 0 again.
Only safe to call when the caller already owns the lock or knows the peer is quiescent. Most users should treat this as a debug-only helper and stick to ra8_ipc_sem_try_take for real acquisition.
| [in] | sem_id | Semaphore index 0..15. |
| [out] | out_locked | Receives true if the semaphore was already locked. |
| k_ra8_ok | Predicate evaluated. |
| k_ra8_err_invalid_arg | sem_id >= 16. |
| k_ra8_err_null_ptr | out_locked was NULL. |
Definition at line 204 of file ra8_ipc_sem_ring.c.
References internal_ra8_ipc_sem_read_take(), internal_ra8_ipc_sem_release_write(), k_ra8_err_invalid_arg, k_ra8_ipc_sem_count, k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_ipc_sem(), and s_tag.
|
nodiscard |
Release one IPC hardware semaphore.
| [in] | sem_id | Semaphore index 0..15. |
| k_ra8_ok | Released. |
| k_ra8_err_invalid_arg | sem_id >= 16. |
Definition at line 190 of file ra8_ipc_sem_ring.c.
References internal_ra8_ipc_sem_release_write(), k_ra8_err_invalid_arg, k_ra8_ipc_sem_count, k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_ipc_barrier(), ra8_ipc_sem(), and s_tag.
Referenced by ra8_ipc_ring_consume(), and ra8_ipc_ring_produce().
|
nodiscard |
Bounded-spin take on one IPC hardware semaphore.
| [in] | sem_id | Semaphore index 0..15. |
| [in] | max_spins | Iteration cap (<= k_ra8_ipc_sem_take_max). |
| k_ra8_ok | Acquired before the budget ran out. |
| k_ra8_err_invalid_arg | sem_id >= 16. |
| k_ra8_err_hw_timeout | Budget expired without acquiring. |
Definition at line 163 of file ra8_ipc_sem_ring.c.
References internal_ra8_ipc_sem_read_take(), k_ra8_err_hw_timeout, k_ra8_err_invalid_arg, k_ra8_ipc_sem_count, k_ra8_ipc_sem_take_max, k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_ipc_barrier(), ra8_ipc_sem(), and s_tag.
|
nodiscard |
Test-and-set acquire on one IPC hardware semaphore.
IPCSEMn implements test-and-set semantics: a 32-bit read sets the LOCK bit and returns the previous value. A return of 0 means the caller acquired the lock (it was previously unlocked). A return of 1 means another core owned it.
| [in] | sem_id | Semaphore index 0..15. |
| k_ra8_ok | Lock acquired. |
| k_ra8_err_busy | Lock already held by another core. |
| k_ra8_err_invalid_arg | sem_id >= 16. |
Definition at line 143 of file ra8_ipc_sem_ring.c.
References internal_ra8_ipc_sem_read_take(), k_ra8_err_busy, k_ra8_err_invalid_arg, k_ra8_ipc_sem_count, k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_ipc_barrier(), ra8_ipc_sem(), and s_tag.
Referenced by ra8_ipc_ring_consume(), and ra8_ipc_ring_produce().
|
nodiscard |
Tear down a previously installed IPC ISR.
| [in] | unit | IPC unit id 0..1. |
| k_ra8_ok | Unregistered. |
| k_ra8_err_invalid_arg | unit >= 2. |
| k_ra8_err_not_found | Was not installed. |
Definition at line 832 of file ra8_ipc.c.
References internal_ra8_ipc_unit_to_event(), k_ra8_err_invalid_arg, k_ra8_err_not_found, k_ra8_ipc_nmi_unit_count, k_ra8_ok, ra8_isr_unregister(), and s_ipc_isr_state.