|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
NVIC + ICU IELSR allocator. More...
Go to the source code of this file.
Typedefs | |
| typedef void(* | ra8_isr_handler_t) (void *ctx) |
| Driver-supplied callback invoked on interrupt entry. | |
Enumerations | |
| enum | ra8_isr_slot_count_t : uint16_t { k_ra8_isr_slot_count = 96U } |
| Size of the ISR allocator's slot pool – one slot per ICU IELSR route. More... | |
| enum | ra8_isr_prio_t : uint8_t { k_ra8_isr_prio_max = 15U , k_ra8_isr_prio_default = 8U } |
| Cortex-M85 NVIC priority range. More... | |
| enum | ra8_isr_invalid_slot_t : uint16_t { k_ra8_isr_slot_none = 0xFFFFU } |
| Sentinel for "no slot allocated". More... | |
Functions | |
| ra8_err_t | ra8_isr_init (void) |
| Initialise the ra8_isr table. | |
| 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). | |
NVIC + ICU IELSR allocator.
substrate module that owns every write to the Cortex-M NVIC and every write to the RA8D2 ICU's IELSR registers. Drivers that need an interrupt register an (event, handler) pair with ra8_isr_register() and the substrate:
At runtime, the vector-table entry for each IELSR slot calls ra8_isr_dispatch(slot) which looks up the stored handler and invokes it with its stored context. This is the mechanism every + driver uses for interrupt delivery.
The RA ICU's "events are programmable, NVIC lines are assigned at runtime" model means multiple drivers independently assigning IELSR slots will collide. Putting one module in charge of the free-list means:
The event argument is the ELC event number from HUM Ch 19 "Event Link Controller (ELC)" (p 817). Each peripheral has well-known events (SCI0_RXI, GPT0_CCMPA, etc.). The ra8_elc facility provides the enum.
Slots persist until explicitly unregistered. A driver that wants to re-route an event calls ra8_isr_unregister first.
Not thread-safe. Driver init runs from single-threaded init context; IRQ handlers run in their own context with the caller stored state but never reach the allocator.
Definition in file ra8_isr.h.
| typedef void(* ra8_isr_handler_t) (void *ctx) |
| enum ra8_isr_invalid_slot_t : uint16_t |
| enum ra8_isr_prio_t : uint8_t |
| enum ra8_isr_slot_count_t : uint16_t |
Size of the ISR allocator's slot pool – one slot per ICU IELSR route.
The RA8D2 ICU exposes ra8_icu_regs.h::k_ra8_icu_num_ielsr (96) IELSR registers, each routing one ELC event to an NVIC line. The allocator keeps a pool of exactly that many slots: a larger pool would let a slot be allocated and its NVIC line enabled while ra8_icu_ielsr() returns NULL for it, so the interrupt would be NVIC-enabled with no ICU event route (#237). A static_assert in ra8_isr.c pins this count to k_ra8_icu_num_ielsr so the two capacity constants cannot silently diverge.
| Enumerator | |
|---|---|
| k_ra8_isr_slot_count | One slot per ICU IELSR route (= k_ra8_icu_num_ielsr). |
| 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.
| [in] | slot | Slot number 0..k_ra8_isr_slot_count - 1. |
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.
| 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).
Definition at line 445 of file ra8_isr.c.
References ra8_hw_irq_disable().
| 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".
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().
|
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.
| k_ra8_ok | Table cleared. |
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().
|
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.
| [in] | event | ELC event number. |
| [out] | out_slot | Slot number on success, or k_ra8_isr_slot_none if unregistered. |
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().
|
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.
| [in] | event | ELC event number from ra8_elc_event_t. |
| [in] | handler | Callback invoked on interrupt entry. Must not be NULL. |
| [in] | ctx | Caller-supplied context handed to the handler on every invocation. May be NULL. |
| [in] | priority | NVIC priority 0..k_ra8_isr_prio_max. |
| [out] | out_slot | Slot number on success. May be NULL if the caller does not need it. |
| k_ra8_ok | Slot allocated, IELSR written, NVIC line enabled. |
| k_ra8_err_null_ptr | handler was NULL. |
| k_ra8_err_invalid_arg | priority out of range. |
| k_ra8_err_no_mem | No free IELSR slot. |
| k_ra8_err_exists | event is already mapped by a previous registration. |
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().
|
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.
| [in] | slot | IELSR slot 0..k_ra8_isr_slot_count - 1, as returned by ra8_isr_register through its out_slot parameter. |
| [in] | enable | true sets DTCE (route the event to the DTC); false clears it (route the event to the CPU). |
| k_ra8_ok | IELSRn.DTCE for the slot now equals enable. |
| k_ra8_err_invalid_arg | slot is out of range. |
| k_ra8_err_not_found | slot is not currently registered. |
| k_ra8_err_hw_error | The IELSR accessor returned NULL. |
enable. 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().
|
nodiscard |
Change the NVIC priority of a registered slot.
| [in] | event | ELC event number that was previously registered. |
| [in] | priority | New priority 0..k_ra8_isr_prio_max. |
| k_ra8_ok | Priority updated. |
| k_ra8_err_not_found | event not registered. |
| k_ra8_err_invalid_arg | priority out of range. |
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.
|
nodiscard |
Release a previously-allocated IELSR slot.
| [in] | event | ELC event number to tear down. |
| k_ra8_ok | Slot released. |
| k_ra8_err_not_found | event was not registered. |
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().