ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_isr.c File Reference

NVIC + ICU IELSR allocator implementation. More...

#include "ra8_isr.h"
#include <stdint.h>
#include "ra8_attributes.h"
#include "ra8_check.h"
#include "ra8_err.h"
#include "ra8_hw_intrinsics.h"
#include "ra8_icu_regs.h"
#include "ra8_log.h"
Include dependency graph for ra8_isr.c:

Go to the source code of this file.

Data Structures

struct  ra8_isr_slot_t
 Dispatch-table entry for one IELSR slot. More...

Enumerations

enum  ra8_isr_nvic_t : uintptr_t {
  k_ra8_isr_nvic_iser_base = 0xE000E100UL ,
  k_ra8_isr_nvic_icer_base = 0xE000E180UL ,
  k_ra8_isr_nvic_icpr_base = 0xE000E280UL ,
  k_ra8_isr_nvic_ipr_base = 0xE000E400UL
}
 NVIC register-base offsets used by the dispatcher. More...
enum  ra8_isr_nvic_layout_t : uint16_t {
  k_ra8_isr_nvic_bits_per_word = 32U ,
  k_ra8_isr_nvic_prio_shift = 4U
}
 Bit-per-word geometry of ISER / ICER arrays. More...

Functions

static void internal_nvic_enable (uint16_t n)
 Enable NVIC line n.
static void internal_nvic_disable (uint16_t n)
 Disable NVIC line n.
static void internal_nvic_clear_pending (uint16_t n)
 Clear pending flag on NVIC line n.
static void internal_nvic_set_priority (uint16_t n, uint8_t prio)
 Set NVIC priority byte for line n.
static void internal_ielsr_write (uint16_t slot, ra8_elc_event_t event)
 Write the event number into an IELSR slot.
static void internal_ielsr_clear (uint16_t slot)
 Clear an IELSR slot (set event = 0, IR bit clear).
ra8_err_t ra8_isr_init (void)
 Initialise the ra8_isr table.
static uint16_t internal_find_event (ra8_elc_event_t event)
 Search the dispatch table for a previously-registered event.
static uint16_t internal_find_free (void)
 Find the first free dispatch-table slot.
ra8_err_t ra8_isr_register (ra8_elc_event_t event, ra8_isr_handler_t handler, void *ctx, uint8_t priority, uint16_t *out_slot)
 Allocate an IELSR slot for an ELC event + handler.
ra8_err_t ra8_isr_unregister (ra8_elc_event_t event)
 Release a previously-allocated IELSR slot.
void ra8_isr_dispatch (uint16_t slot)
 Invoke the handler stored in dispatch-table slot slot.
ra8_err_t ra8_isr_set_priority (ra8_elc_event_t event, uint8_t priority)
 Change the NVIC priority of a registered slot.
ra8_err_t ra8_isr_lookup_slot (ra8_elc_event_t event, uint16_t *out_slot)
 Look up the slot allocated to a registered event.
ra8_err_t ra8_isr_set_dtc (uint16_t slot, bool enable)
 Enable or disable DTC activation on a registered IELSR slot.
void ra8_isr_globals_enable (void)
 Globally enable maskable interrupts (PRIMASK = 0).
void ra8_isr_globals_disable (void)
 Globally mask maskable interrupts (PRIMASK = 1).

Variables

static const char * s_tag = "ISR"
static ra8_isr_slot_t s_slots [k_ra8_isr_slot_count]
 Per-slot dispatch table.

Detailed Description

NVIC + ICU IELSR allocator implementation.

Tag
[Ring 3 / HAL] {World: S}

Ring 3 / HAL substrate. Owns every write to the ICU IELSR slot array and to the Cortex-M85 NVIC ISER / ICER / IPR windows. See ra8_isr.h for the API contract.

Definition in file ra8_isr.c.

Enumeration Type Documentation

◆ ra8_isr_nvic_layout_t

enum ra8_isr_nvic_layout_t : uint16_t

Bit-per-word geometry of ISER / ICER arrays.

Enumerator
k_ra8_isr_nvic_bits_per_word 

32 bits per ISER/ICER entry.

k_ra8_isr_nvic_prio_shift 

Upper 4 priority bits used.

Definition at line 51 of file ra8_isr.c.

◆ ra8_isr_nvic_t

enum ra8_isr_nvic_t : uintptr_t

NVIC register-base offsets used by the dispatcher.

Cortex-M85 architectural layout from the Armv8.1-M reference manual. The same addresses apply on the Cortex-M33 secondary core; that is why this module is a substrate module and not a target-specific peripheral driver.

Enumerator
k_ra8_isr_nvic_iser_base 

ISER base: enables.

k_ra8_isr_nvic_icer_base 

ICER base: disables.

k_ra8_isr_nvic_icpr_base 

ICPR base: clear pending.

k_ra8_isr_nvic_ipr_base 

IPR base: priority bytes.

Definition at line 40 of file ra8_isr.c.

Function Documentation

◆ internal_find_event()

uint16_t internal_find_event ( ra8_elc_event_t event)
static

Search the dispatch table for a previously-registered event.

Returns
Slot index on success, k_ra8_isr_slot_none otherwise.

See implementation.

Parameters
[in]eventSee implementation.
Return values
k_ra8_okOperation succeeded.
Precondition
Module state is consistent.
Module state is consistent.
Postcondition
Caller-visible state matches the documented contract.
Caller-visible state matches the documented contract.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Definition at line 262 of file ra8_isr.c.

References k_ra8_isr_slot_count, k_ra8_isr_slot_none, RA8_INTERNAL, and s_slots.

Referenced by ra8_isr_lookup_slot(), ra8_isr_register(), ra8_isr_set_priority(), and ra8_isr_unregister().

◆ internal_find_free()

uint16_t internal_find_free ( void )
static

Find the first free dispatch-table slot.

Returns
Slot index on success, k_ra8_isr_slot_none when full.

See implementation.

Return values
k_ra8_okOperation succeeded.
Precondition
Module state is consistent.
Module state is consistent.
Postcondition
Caller-visible state matches the documented contract.
Caller-visible state matches the documented contract.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Definition at line 286 of file ra8_isr.c.

References k_ra8_isr_slot_count, k_ra8_isr_slot_none, RA8_INTERNAL, and s_slots.

Referenced by ra8_isr_register().

◆ internal_ielsr_clear()

void internal_ielsr_clear ( uint16_t slot)
static

Clear an IELSR slot (set event = 0, IR bit clear).

See implementation.

Parameters
[in]slotSee implementation.
Precondition
Module state is consistent.
Module state is consistent.
Postcondition
Caller-visible state matches the documented contract.
Caller-visible state matches the documented contract.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Definition at line 216 of file ra8_isr.c.

References ra8_icu_ielsr(), and RA8_INTERNAL.

Referenced by ra8_isr_init(), and ra8_isr_unregister().

◆ internal_ielsr_write()

void internal_ielsr_write ( uint16_t slot,
ra8_elc_event_t event )
static

Write the event number into an IELSR slot.

The 9-bit event number goes into bits 8..0 per HUM Ch 14.2.x (IELSRn layout). Upper bits (DTC enable, IR status) are written zero so the slot starts clean.

Parameters
[in]slotSee implementation.
[in]eventSee implementation.
Precondition
Module state is consistent.
Module state is consistent.
Postcondition
Caller-visible state matches the documented contract.
Caller-visible state matches the documented contract.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Definition at line 195 of file ra8_isr.c.

References k_ra8_ielsr_iels_mask, ra8_icu_ielsr(), and RA8_INTERNAL.

Referenced by ra8_isr_register().

◆ internal_nvic_clear_pending()

void internal_nvic_clear_pending ( uint16_t n)
static

Clear pending flag on NVIC line n.

See implementation.

Parameters
[in]nSee implementation.
Precondition
Module state is consistent.
Module state is consistent.
Postcondition
Caller-visible state matches the documented contract.
Caller-visible state matches the documented contract.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Definition at line 150 of file ra8_isr.c.

References k_ra8_isr_nvic_bits_per_word, k_ra8_isr_nvic_icpr_base, and RA8_INTERNAL.

Referenced by ra8_isr_init(), ra8_isr_register(), and ra8_isr_unregister().

◆ internal_nvic_disable()

void internal_nvic_disable ( uint16_t n)
static

Disable NVIC line n.

See implementation.

Parameters
[in]nSee implementation.
Precondition
Module state is consistent.
Module state is consistent.
Postcondition
Caller-visible state matches the documented contract.
Caller-visible state matches the documented contract.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Definition at line 129 of file ra8_isr.c.

References k_ra8_isr_nvic_bits_per_word, k_ra8_isr_nvic_icer_base, and RA8_INTERNAL.

Referenced by ra8_isr_init(), and ra8_isr_unregister().

◆ internal_nvic_enable()

void internal_nvic_enable ( uint16_t n)
static

Enable NVIC line n.

See implementation.

Parameters
[in]nSee implementation.
Precondition
Module state is consistent.
Module state is consistent.
Postcondition
Caller-visible state matches the documented contract.
Caller-visible state matches the documented contract.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Definition at line 108 of file ra8_isr.c.

References k_ra8_isr_nvic_bits_per_word, k_ra8_isr_nvic_iser_base, and RA8_INTERNAL.

Referenced by ra8_isr_register().

◆ internal_nvic_set_priority()

void internal_nvic_set_priority ( uint16_t n,
uint8_t prio )
static

Set NVIC priority byte for line n.

See implementation.

Parameters
[in]nSee implementation.
[in]prioSee implementation.
Precondition
Module state is consistent.
Module state is consistent.
Postcondition
Caller-visible state matches the documented contract.
Caller-visible state matches the documented contract.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Definition at line 172 of file ra8_isr.c.

References k_ra8_isr_nvic_ipr_base, k_ra8_isr_nvic_prio_shift, and RA8_INTERNAL.

Referenced by ra8_isr_register(), and ra8_isr_set_priority().

◆ ra8_isr_dispatch()

void ra8_isr_dispatch ( uint16_t slot)

Invoke the handler stored in dispatch-table slot slot.

Called from the Cortex-M85 vector-table trampoline when any ICU NVIC line fires. The trampoline feeds its NVIC index (which matches the IELSR slot number). ra8_isr_dispatch looks up the handler + context stored at registration time and calls the handler with the stored context. The IELSR.IR flag is cleared before the handler runs so a nested identical event re-raises the interrupt instead of being latched.

Parameters
[in]slotSlot number 0..k_ra8_isr_slot_count - 1.
Precondition
Called from Cortex-M85 handler mode.
slot has been registered via ra8_isr_register.
Postcondition
IELSR.IR is cleared.
Dispatch-table handler was invoked exactly once.
Note
Thread safety: re-entrant in the sense that the handler itself may enable nested interrupts; the dispatcher does not take any locks.
Since
0.1.0

Definition at line 362 of file ra8_isr.c.

References k_ra8_ielsr_ir_bit, k_ra8_isr_slot_count, ra8_icu_ielsr(), and s_slots.

◆ ra8_isr_globals_disable()

void ra8_isr_globals_disable ( void )

Globally mask maskable interrupts (PRIMASK = 1).

Companion to ra8_isr_globals_enable. Used by the application around critical sections where an ISR firing mid-update would corrupt shared state (the per-driver ra8_register_guard.h helpers wrap this for short scopes; this function exists for application-level sequencing during shutdown / reset).

Precondition
None.
Postcondition
PRIMASK is set; subsequent NVIC interrupts will pend until PRIMASK is cleared again.
Note
Faults still fire (NMI / HardFault are not maskable via PRIMASK). Use FAULTMASK if you need that, but the project does not expose a wrapper for it.
Since
0.1.0
Precondition
Module state is consistent.
Postcondition
Caller-visible state matches the documented contract.

Definition at line 445 of file ra8_isr.c.

References ra8_hw_irq_disable().

◆ ra8_isr_globals_enable()

void ra8_isr_globals_enable ( void )

Globally enable maskable interrupts (PRIMASK = 0).

The Cortex-M85 boots with PRIMASK clear, but SystemInit masks IRQs with cpsid i to give the application a quiet boot window for driver setup. Once every IRQ source has been registered via ra8_isr_register and the application is ready to start servicing interrupts, call this to drop the global mask. Standard CMSIS convention is "mask at boot, unmask once main() has finished deterministic init".

Precondition
Every IRQ source the application uses has been wired up.
Every shared data structure that ISRs touch is initialized.
Postcondition
PRIMASK is clear; pending NVIC interrupts will dispatch.
Note
Symmetric counterpart of ra8_isr_globals_disable. Calling ra8_isr_globals_enable while PRIMASK is already clear is a safe no-op.
Since
0.1.0
Postcondition
Caller-visible state matches the documented contract.

Definition at line 439 of file ra8_isr.c.

References ra8_hw_irq_enable().

Referenced by app_bringup_clocks(), arm_ipc_wake(), c6_cam_app_run(), cm_bringup_clocks(), ez_bringup_clocks(), internal_lcd_bringup_clocks(), internal_npu_infer_execute(), internal_rtc_demo_setup_or_halt(), lcd_bringup_clocks(), main(), mg_bringup_clocks(), and sfr_bringup_clocks().

◆ ra8_isr_init()

ra8_err_t ra8_isr_init ( void )
nodiscard

Initialise the ra8_isr table.

Zeros every IELSR slot, clears every dispatch-table entry, and disables every NVIC line 0..k_ra8_isr_slot_count. After this call every ra8_isr_register starts from a clean table.

Returns
ra8_err_t error code.
Return values
k_ra8_okTable cleared.
Precondition
Caller is in single-threaded init context.
Postcondition
IELSR0..IELSR95 all zero.
NVIC lines 0..95 are disabled.
Every dispatch-table entry is (NULL handler, NULL ctx).
Note
Thread safety: not thread-safe.
Since
0.1.0

Definition at line 229 of file ra8_isr.c.

References internal_ielsr_clear(), internal_nvic_clear_pending(), internal_nvic_disable(), k_ra8_isr_slot_count, k_ra8_ok, ra8_log_info, s_slots, and s_tag.

Referenced by arm_ipc_wake(), dtc_arm_setup_or_halt(), dtc_coh_setup_or_halt(), dtc_demo_setup_or_halt(), internal_c6_cam_setup_or_halt(), internal_gpt_irq_demo_arm(), internal_init_bind_owner(), internal_lus_arm_wake(), internal_npu_infer_setup_or_halt(), lpi_arm_wake(), ra8_nsc_periph_init(), and uart_irq_setup_or_halt().

◆ ra8_isr_lookup_slot()

ra8_err_t ra8_isr_lookup_slot ( ra8_elc_event_t event,
uint16_t * out_slot )
nodiscard

Look up the slot allocated to a registered event.

Diagnostic accessor used by unit tests to verify the allocator state. Returns k_ra8_isr_slot_none via *out_slot if the event is not registered.

Parameters
[in]eventELC event number.
[out]out_slotSlot number on success, or k_ra8_isr_slot_none if unregistered.
Returns
k_ra8_ok or k_ra8_err_null_ptr.
Precondition
out_slot is non-NULL.
Postcondition
No hardware state is modified.
Since
0.1.0

Definition at line 408 of file ra8_isr.c.

References internal_find_event(), k_ra8_ok, RA8_CHECK_NULL_PTR, and s_tag.

Referenced by internal_usbfs_storm_guard_init().

◆ ra8_isr_register()

ra8_err_t ra8_isr_register ( ra8_elc_event_t event,
ra8_isr_handler_t handler,
void * ctx,
uint8_t priority,
uint16_t * out_slot )
nodiscard

Allocate an IELSR slot for an ELC event + handler.

Walks the free list, picks the first open slot, writes the event number into the corresponding IELSR register, stores (handler, ctx) in the dispatch table, clears the pending bit in the NVIC, sets the priority, and enables the NVIC line.

On success, *out_slot holds the assigned slot number. The caller normally ignores this value and only cares that the interrupt will fire; the slot number is useful for unregistration and for diagnostic dumps.

Parameters
[in]eventELC event number from ra8_elc_event_t.
[in]handlerCallback invoked on interrupt entry. Must not be NULL.
[in]ctxCaller-supplied context handed to the handler on every invocation. May be NULL.
[in]priorityNVIC priority 0..k_ra8_isr_prio_max.
[out]out_slotSlot number on success. May be NULL if the caller does not need it.
Returns
ra8_err_t error code.
Return values
k_ra8_okSlot allocated, IELSR written, NVIC line enabled.
k_ra8_err_null_ptrhandler was NULL.
k_ra8_err_invalid_argpriority out of range.
k_ra8_err_no_memNo free IELSR slot.
k_ra8_err_existsevent is already mapped by a previous registration.
Precondition
IRQs masked or single-threaded init context.
ra8_isr_init() has been called.
Postcondition
On success, a single NVIC line is enabled with the given priority and its IELSR entry matches event.
Subsequent firings of event invoke handler(ctx) via the vector-table trampoline.
Note
Thread safety: not thread-safe.
See also
ra8_isr_unregister
Since
0.1.0

Definition at line 296 of file ra8_isr.c.

References internal_find_event(), internal_find_free(), internal_ielsr_write(), internal_nvic_clear_pending(), internal_nvic_enable(), internal_nvic_set_priority(), k_ra8_err_exists, k_ra8_err_invalid_arg, k_ra8_err_no_mem, k_ra8_isr_prio_max, k_ra8_isr_slot_none, k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_log_error, s_slots, and s_tag.

Referenced by arm_ipc_wake(), dtc_arm_bringup_or_halt(), dtc_coh_bringup_or_halt(), dtc_demo_bringup_or_halt(), internal_gpt_irq_demo_arm(), internal_init_bind_owner(), internal_lus_arm_wake(), internal_npu_infer_execute(), lpi_arm_wake(), ra8_board_sw_attach_irq(), ra8_cnecc_attach_isr(), ra8_gpio_attach_irq(), ra8_ipc_install_isr(), ra8_pdm_stream_enable(), and uart_irq_register_isrs().

◆ ra8_isr_set_dtc()

ra8_err_t ra8_isr_set_dtc ( uint16_t slot,
bool enable )
nodiscard

Enable or disable DTC activation on a registered IELSR slot.

The Data Transfer Controller has no software-start register (HUM Ch 18.3 p 796: "The DTC is activated by an interrupt request"); a peripheral or ELC event activates it only when that event's ICU.IELSRn slot has its DTCE bit (bit 24) set. With DTCE clear the same event is taken by the CPU as an ordinary interrupt instead. Because ra8_isr owns every IELSR slot (ra8_isr_register writes the IELS event field, the dispatcher clears IR), arming or disarming DTC on an allocated slot belongs here rather than open-coded in every DTC application.

The write is a read-modify-write that touches only DTCE: the IELS event-select field written by ra8_isr_register is preserved, and the write-0-to-clear IR status flag is left untouched – its own read value is written back, which retains it (see ra8_isr_dispatch and issue #170). The DTC clears DTCE itself when a block completes (HUM Figure 18.5 p 801), so a repeating transfer re-arms with enable = true before each activation.

Parameters
[in]slotIELSR slot 0..k_ra8_isr_slot_count - 1, as returned by ra8_isr_register through its out_slot parameter.
[in]enabletrue sets DTCE (route the event to the DTC); false clears it (route the event to the CPU).
Returns
ra8_err_t error code.
Return values
k_ra8_okIELSRn.DTCE for the slot now equals enable.
k_ra8_err_invalid_argslot is out of range.
k_ra8_err_not_foundslot is not currently registered.
k_ra8_err_hw_errorThe IELSR accessor returned NULL.
Precondition
slot was assigned by a prior ra8_isr_register call.
IRQs masked or single-threaded init context.
Postcondition
On k_ra8_ok, IELSRn.DTCE for the slot reflects enable.
No other IELSR field (IELS / IR) is modified.
Note
Thread safety: not thread-safe.
See also
ra8_isr_register
ra8_isr_dispatch
Since
0.1.0

Definition at line 415 of file ra8_isr.c.

References k_ra8_err_hw_error, k_ra8_err_invalid_arg, k_ra8_err_not_found, k_ra8_ielsr_dtce_mask, k_ra8_isr_slot_count, k_ra8_ok, ra8_icu_ielsr(), and s_slots.

Referenced by dtc_arm_run_armed(), and dtc_arm_run_disarmed().

◆ ra8_isr_set_priority()

ra8_err_t ra8_isr_set_priority ( ra8_elc_event_t event,
uint8_t priority )
nodiscard

Change the NVIC priority of a registered slot.

Parameters
[in]eventELC event number that was previously registered.
[in]priorityNew priority 0..k_ra8_isr_prio_max.
Returns
ra8_err_t error code.
Return values
k_ra8_okPriority updated.
k_ra8_err_not_foundevent not registered.
k_ra8_err_invalid_argpriority out of range.
Precondition
IRQs masked.
Postcondition
NVIC IPR byte for the slot reflects the new priority.
Since
0.1.0

Definition at line 394 of file ra8_isr.c.

References internal_find_event(), internal_nvic_set_priority(), k_ra8_err_invalid_arg, k_ra8_err_not_found, k_ra8_isr_prio_max, k_ra8_isr_slot_none, k_ra8_ok, and s_slots.

◆ ra8_isr_unregister()

ra8_err_t ra8_isr_unregister ( ra8_elc_event_t event)
nodiscard

Release a previously-allocated IELSR slot.

Parameters
[in]eventELC event number to tear down.
Returns
ra8_err_t error code.
Return values
k_ra8_okSlot released.
k_ra8_err_not_foundevent was not registered.
Precondition
IRQs masked or single-threaded init context.
Postcondition
NVIC line for the slot is disabled.
IELSR entry for the slot is zero.
Dispatch-table entry for the slot is (NULL, NULL).
Note
Thread safety: not thread-safe.
Since
0.1.0

Definition at line 335 of file ra8_isr.c.

References internal_find_event(), internal_ielsr_clear(), internal_nvic_clear_pending(), internal_nvic_disable(), k_ra8_err_not_found, k_ra8_isr_slot_count, k_ra8_isr_slot_none, k_ra8_ok, and s_slots.

Referenced by ra8_cnecc_attach_isr(), ra8_cnecc_detach_isr(), ra8_gpio_detach_irq(), ra8_ipc_uninstall_isr(), and ra8_pdm_stream_disable().

Variable Documentation

◆ s_slots

◆ s_tag

const char* s_tag = "ISR"
static

Definition at line 28 of file ra8_isr.c.