|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
USBX device-controller-driver bridge to ra8_usb – lifecycle + storm guard. More...
#include "ux_dcd_ra8_usb.h"#include <stdint.h>#include <string.h>#include "ra8_check.h"#include "ra8_elc_regs.h"#include "ra8_isr.h"#include "ra8_log.h"#include "ra8_usb_regs.h"#include "tx_api.h"#include "ux_api.h"#include "ux_dcd_ra8_usb_internal.h"#include "ux_device_stack.h"#include "ux_system.h"#include "ux_utility.h"Go to the source code of this file.
Macros | |
| #define | UX_SOURCE_CODE |
Enumerations | |
| enum | ra8_usb_dcd_isr_prio_t : uint8_t { k_ra8_usb_dcd_isr_prio = 8U } |
| NVIC priority chosen for the USB controller IRQs. More... | |
| enum | ra8_nvic_reg_t : uintptr_t { k_nvic_iser_base = 0xE000E100U , k_nvic_icer_base = 0xE000E180U , k_nvic_ispr_base = 0xE000E200U } |
| Cortex-M NVIC set/clear-enable register array base addresses. More... | |
| enum | ra8_nvic_layout_t : uint32_t { k_nvic_irqs_per_reg = 32U , k_nvic_reg_stride = 4U } |
| Bit layout of the NVIC ISER/ICER register array. More... | |
| enum | ra8_usb_dcd_ctrl_id_t : uint8_t { k_ra8_usb_dcd_controller_id = 99U } |
| Private USBX controller-type id reported by this DCD bridge. More... | |
Functions | |
| void | ux_dcd_ra8_usb_auto_echo_enable (uint8_t out_pipe, uint8_t in_pipe) |
| Enable bridge-side auto-echo on the configured pipe pair. | |
| static void | internal_usbfs_irq_set_enabled (bool enabled) |
| Set or clear the USB controller's NVIC enable bit. | |
| void | priv_usbfs_irq_mask (void) |
| Mask the USB IRQ at the NVIC to break an interrupt storm. | |
| void | ux_dcd_ra8_usb_irq_reenable (void) |
| Storm-guard recovery: zero the run counter and re-enable the USB IRQ. | |
| static void | internal_usbfs_storm_guard_init (ra8_usb_speed_t speed) |
| Resolve the USB controller's NVIC slot for the storm guard. | |
| static ra8_err_t | internal_init_bind_owner (ra8_usb_speed_t speed) |
| Bind _ux_system_slave->ux_system_slave_dcd to this bridge. | |
| static void | internal_init_parse_framework (UX_SLAVE_DEVICE *device) |
| Select the active device-framework pair and parse the descriptor. | |
| static void | internal_init_setup_ep0 (UX_SLAVE_DEVICE *device, UX_SLAVE_DCD *owner) |
| Bind the EP0 transfer-request endpoint and run CREATE_ENDPOINT. | |
| ra8_err_t | ux_dcd_ra8_usb_initialize (ra8_usb_speed_t speed) |
| Bring up the USBX DCD bridge for the selected RA8 USB controller. | |
| ra8_err_t | ux_dcd_ra8_usb_uninitialize (void) |
| Ux dcd ra usb uninitialize. | |
| ra8_usb_dcd_state_t | ux_dcd_ra8_usb_state (void) |
| Ux dcd ra usb state. | |
Variables | |
| static const char *const | s_tag = "ux_dcd_ra8_usb" |
| volatile uint16_t | g_syscfg_after_dcd_init = 0U |
| SYSCFG snapshot at end of ux_dcd_ra8_usb_initialize. | |
| volatile uint16_t | g_lpsts_after_dcd_init = 0U |
| LPSTS snapshot at end of ux_dcd_ra8_usb_initialize. | |
| ra8_usb_dcd_t | g_dcd |
| The single bridge instance, defined in ux_dcd_ra8_usb.c. | |
| volatile uint32_t | g_dcd_auto_echo_enable = 0U |
| Non-zero once ISR-side auto-echo is armed. | |
| uint8_t | g_dcd_auto_echo_out_pipe = 0U |
| Pipe drained by the in-ISR auto-echo path. | |
| uint8_t | g_dcd_auto_echo_in_pipe = 0U |
| Pipe the auto-echo path re-queues onto. | |
| static uint16_t | s_usb_irq_slot = 0U |
| NVIC slot the USB controller's ELC event is routed to. | |
| volatile uint32_t | g_isr_spurious_run = 0U |
| Consecutive event-less ISR entries since the last SysTick re-enable. | |
| ra8_usb_dcd_diag_t | g_diag = {} |
| Bridge diagnostic counter block, defined in ux_dcd_ra8_usb.c. | |
USBX device-controller-driver bridge to ra8_usb – lifecycle + storm guard.
Implements the dispatch contract documented in ux_dcd_ra8_usb.h. Mirrors the layout of upstream USBX DCD ports (e.g. ux_dcd_sim_slave_function) but routes every call through the project's ra8_usb_* register-level driver instead of touching USB controller registers directly.
This translation unit owns the bridge singleton (g_dcd / g_diag), the lifecycle entry points (ux_dcd_ra8_usb_initialize / _uninitialize / _state), and the USBFS interrupt-storm guard. The per-aspect siblings (ux_dcd_ra8_usb_{ep,xfer,isr,setup,dvst,dvst_default,irq}.c) share state and helpers through ux_dcd_ra8_usb_internal.h.
Definition in file ux_dcd_ra8_usb.c.
| #define UX_SOURCE_CODE |
Definition at line 26 of file ux_dcd_ra8_usb.c.
| enum ra8_nvic_layout_t : uint32_t |
Bit layout of the NVIC ISER/ICER register array.
| Enumerator | |
|---|---|
| k_nvic_irqs_per_reg | IRQ lines covered by one ISER/ICER word. |
| k_nvic_reg_stride | Byte stride between consecutive ISER/ICER words. |
Definition at line 162 of file ux_dcd_ra8_usb.c.
| enum ra8_nvic_reg_t : uintptr_t |
Cortex-M NVIC set/clear-enable register array base addresses.
| Enumerator | |
|---|---|
| k_nvic_iser_base | NVIC Interrupt Set-Enable Register array. |
| k_nvic_icer_base | NVIC Interrupt Clear-Enable Register array. |
| k_nvic_ispr_base | NVIC Interrupt Set-Pending Register array. |
Definition at line 152 of file ux_dcd_ra8_usb.c.
| enum ra8_usb_dcd_ctrl_id_t : uint8_t |
Private USBX controller-type id reported by this DCD bridge.
| Enumerator | |
|---|---|
| k_ra8_usb_dcd_controller_id | RA-USB private controller id. |
Definition at line 297 of file ux_dcd_ra8_usb.c.
| enum ra8_usb_dcd_isr_prio_t : uint8_t |
NVIC priority chosen for the USB controller IRQs.
USB completion IRQs sit between SysTick (priority 0, the highest in this firmware) and the application-level work threads. Picking 4 leaves headroom for higher-priority drivers (timers, fault paths) while still pre-empting ThreadX context switches and USBX class threads so SETUP / BRDY / BEMP events drain promptly.
| Enumerator | |
|---|---|
| k_ra8_usb_dcd_isr_prio | RA8 USB dcd ISR prio. |
Definition at line 56 of file ux_dcd_ra8_usb.c.
|
static |
Bind _ux_system_slave->ux_system_slave_dcd to this bridge.
Wires the USBX DCD ownership block to the bridge's dispatcher trampoline, resets the per-pipe transfer stash, registers the controller's ELC event onto an NVIC line via ra8_isr_register, then arms the FS interrupt-storm guard.
| [in] | speed | Which controller (FS or HS). |
| k_ra8_ok | Bridge attached and IRQ line armed. |
| k_ra8_err_invalid_state | _ux_system_slave not bound. |
Definition at line 356 of file ux_dcd_ra8_usb.c.
References _ux_dcd_ra8_usb_function(), g_dcd, internal_usbfs_storm_guard_init(), k_ra8_err_invalid_state, k_ra8_ok, k_ra8_usb_dcd_controller_id, k_ra8_usb_dcd_isr_prio, k_ux_dcd_ra8_usb_max_pipes, k_ux_dcd_ra8_usb_state_ready, owner, priv_pick_event(), priv_pick_isr(), RA8_INTERNAL, ra8_isr_init(), ra8_isr_register(), RA8_RETURN_ON_ERROR, and s_tag.
Referenced by ux_dcd_ra8_usb_initialize().
|
static |
Select the active device-framework pair and parse the descriptor.
Mirrors the work upstream DCDs do in their initialize_complete hook (see ux_dcd_sim_slave_initialize_complete.c). Picks the HS or FS device-framework slot based on ux_system_slave_speed, then parses the device descriptor so EP0's MaxPacketSize0 is available below.
| [in,out] | device | USBX peripheral device to populate (USBX vendor type UX_SLAVE_DEVICE – not renamed; legacy external API symbol). |
Definition at line 420 of file ux_dcd_ra8_usb.c.
References RA8_INTERNAL.
Referenced by ux_dcd_ra8_usb_initialize().
|
static |
Bind the EP0 transfer-request endpoint and run CREATE_ENDPOINT.
Populates the EP0 transfer-request with timeout / buffer / MaxPacketSize0, calls the bridge dispatcher's CREATE_ENDPOINT path so EP0 ends up in the per-pipe stash, then stamps the device into the ATTACHED state so the chapter-9 dispatcher accepts the host's first SETUP (gate at _ux_device_stack_transfer_request).
| [in,out] | device | USBX peripheral device (USBX vendor type UX_SLAVE_DEVICE – not renamed; legacy external API symbol). |
| [in] | owner | DCD ownership block returned from internal_init_bind_owner. |
Definition at line 464 of file ux_dcd_ra8_usb.c.
References _ux_dcd_ra8_usb_function(), owner, and RA8_INTERNAL.
Referenced by ux_dcd_ra8_usb_initialize().
|
static |
Set or clear the USB controller's NVIC enable bit.
Indexes the NVIC ISER (enable) or ICER (disable) register array by s_usb_irq_slot. Writing 1 to an ISER/ICER bit is the architected way to enable/disable a single IRQ line (Arm v8-M); writing 0 is a no-op, so no read-modify-write and no race with the NVIC.
| [in] | enabled | true -> ISER (enable); false -> ICER (disable). |
Definition at line 205 of file ux_dcd_ra8_usb.c.
References k_nvic_icer_base, k_nvic_irqs_per_reg, k_nvic_iser_base, k_nvic_reg_stride, RA8_INTERNAL, and s_usb_irq_slot.
Referenced by priv_usbfs_irq_mask(), and ux_dcd_ra8_usb_irq_reenable().
|
static |
Resolve the USB controller's NVIC slot for the storm guard.
Looks up the NVIC slot the controller's ELC event was routed to and records it in s_usb_irq_slot, so internal_usbfs_irq_set_enabled (the mask / re-enable) targets the right ISER/ICER bit. No timer is created here – the storm guard's recovery clock is the per-app 1 ms SysTick_Handler, which calls ux_dcd_ra8_usb_irq_reenable.
| [in] | speed | Which controller was just registered. |
Definition at line 325 of file ux_dcd_ra8_usb.c.
References k_ra8_ok, priv_pick_event(), RA8_INTERNAL, ra8_isr_lookup_slot(), and s_usb_irq_slot.
Referenced by internal_init_bind_owner().
| void priv_usbfs_irq_mask | ( | void | ) |
Mask the USB IRQ at the NVIC to break an interrupt storm.
Called from internal_usbfs_isr or internal_usbhs_isr once a sustained run of event-less entries proves a storm is in progress. With the line masked the storming controller cannot tail-chain the CPU, so RTOS thread mode runs; the per-app 1 ms SysTick_Handler re-enables the line via ux_dcd_ra8_usb_irq_reenable. The line masked is s_usb_irq_slot – whichever controller this DCD instance drives.
Definition at line 231 of file ux_dcd_ra8_usb.c.
References internal_usbfs_irq_set_enabled().
Referenced by internal_usbfs_isr(), and internal_usbhs_isr().
| void ux_dcd_ra8_usb_auto_echo_enable | ( | uint8_t | out_pipe, |
| uint8_t | in_pipe ) |
Enable bridge-side auto-echo on the configured pipe pair.
Enable ISR-side auto-echo from a bulk OUT pipe to a bulk IN pipe.
All data arriving on out_pipe (bulk OUT) is drained and re-queued onto in_pipe (bulk IN) from inside the IRQ path. Workaround for ThreadX worker thread scheduling failure on this silicon. Once enabled, the loop runs whenever internal_irq_walk_pipe encounters an OUT pipe with no waiter; see internal_irq_auto_echo for the body.
| [in] | out_pipe | Pipe index to drain on (bulk OUT). |
| [in] | in_pipe | Pipe index to re-queue on (bulk IN). |
Definition at line 141 of file ux_dcd_ra8_usb.c.
References g_dcd_auto_echo_enable, g_dcd_auto_echo_in_pipe, and g_dcd_auto_echo_out_pipe.
Referenced by demo_cdc_activate(), demo_cdc_activate(), and ns_cdc_activate().
|
nodiscard |
Bring up the USBX DCD bridge for the selected RA8 USB controller.
Register the ra8_usb bridge as the active USBX DCD.
Initialises the underlying ra8_usb_* register layer for the given speed (FS or HS), attaches the bridge's priv_event_cb so the dispatcher can re-enter USBX, binds the controller into the USBX DCD ownership block (_ux_system_slave), wires the matching ELC event into the NVIC, parses the active device descriptor framework, and stamps EP0 so the chapter-9 dispatcher accepts the host's first SETUP token. Idempotent across calls: re-running with the same speed is a no-op once g_dcd.state has reached ready.
| [in] | speed | Which controller to bring up (k_ra8_usb_speed_fs or k_ra8_usb_speed_hs). |
| k_ra8_ok | Bridge fully initialized and ready for enumeration. |
| k_ra8_err_invalid_arg | speed out of range. |
| k_ra8_err_internal | A fallible driver or ownership initialisation step failed. |
Definition at line 521 of file ux_dcd_ra8_usb.c.
References g_dcd, g_lpsts_after_dcd_init, g_syscfg_after_dcd_init, internal_init_bind_owner(), internal_init_parse_framework(), internal_init_setup_ep0(), k_ra8_err_invalid_arg, k_ra8_ok, k_ra8_usb_speed_hs, priv_event_cb(), ra8_log_info, RA8_RETURN_ON_ERROR, ra8_usb_attach_handler(), ra8_usb_device_init(), ra8_usb_hs(), ra8_usbhs_lpsts(), s_tag, and r_usb_regs_t::SYSCFG.
Referenced by cdc_device_worker(), demo_worker(), demo_worker_start_dcd(), dfu_device_worker(), hid_device_worker(), hid_device_worker(), microsd_device_worker(), mlun_device_worker(), ns_usb_worker(), ospirw_device_worker(), sdmsc_device_worker(), selftest_device_worker(), selftest_device_worker(), and wlun_device_worker().
| void ux_dcd_ra8_usb_irq_reenable | ( | void | ) |
Storm-guard recovery: zero the run counter and re-enable the USB IRQ.
Re-enable the USB NVIC IRQ at the controller level.
The recovery half of the USBFS interrupt-storm guard. Each USB-FS app's SysTick_Handler calls this every 1 ms. Zeroing g_isr_spurious_run makes that counter a per-millisecond rate gauge – so normal idle SOFR can never accumulate to the mask threshold – and re-enabling the NVIC line undoes any mask internal_usbfs_isr applied. Re-enabling an already-enabled line is a no-op, so calling this outside a storm is harmless. SysTick is used rather than a ThreadX TX_TIMER because it is an exception handler: it keeps running even while a storm has thread mode – and the ThreadX timer subsystem – starved.
Definition at line 260 of file ux_dcd_ra8_usb.c.
References g_dcd, g_isr_spurious_run, internal_usbfs_irq_set_enabled(), k_nvic_irqs_per_reg, k_nvic_ispr_base, k_nvic_reg_stride, k_ux_dcd_ra8_usb_max_pipes, and s_usb_irq_slot.
Referenced by SysTick_Handler().
| ra8_usb_dcd_state_t ux_dcd_ra8_usb_state | ( | void | ) |
Ux dcd ra usb state.
Read the bridge run-state.
See implementation for details.
| 0 | Success or default value. |
Definition at line 603 of file ux_dcd_ra8_usb.c.
References g_dcd.
|
nodiscard |
Ux dcd ra usb uninitialize.
Tear down the ra8_usb DCD bridge.
See implementation for details.
| 0 | Success or default value. |
Definition at line 569 of file ux_dcd_ra8_usb.c.
References g_dcd, k_ra8_err_invalid_state, k_ra8_ok, k_ux_dcd_ra8_usb_state_uninit, ra8_usb_attach_handler(), and ra8_usb_device_deinit().
| ra8_usb_dcd_t g_dcd |
The single bridge instance, defined in ux_dcd_ra8_usb.c.
The single bridge instance.
RA8 has two USB controllers but the device stack only ever drives one at a time, so a single instance is sufficient. Updated from the ISR and the dispatch trampoline; concurrency is arbitrated at the call-site.
RA8 has two USB controllers but the device stack only ever drives one at a time, so a single static is sufficient.
Definition at line 103 of file ux_dcd_ra8_usb.c.
Referenced by _ux_dcd_ra8_usb_function(), internal_endpoint_arm_out_pid(), internal_endpoint_create(), internal_endpoint_destroy(), internal_endpoint_stall(), internal_ep0_transfer(), internal_init_bind_owner(), internal_irq_auto_echo(), internal_irq_complete_in(), internal_irq_complete_out(), internal_irq_drain_orphan_out(), internal_irq_finish_out(), internal_irq_recover_in_nak(), internal_irq_stage_next_in(), internal_irq_walk_pipe(), internal_submit_consume_orphan(), internal_submit_in_pipe(), internal_submit_pipe(), internal_try_defer_ctrl_out(), internal_wait_completion(), priv_transfer_request(), ux_dcd_ra8_usb_initialize(), ux_dcd_ra8_usb_irq(), ux_dcd_ra8_usb_irq_reenable(), ux_dcd_ra8_usb_state(), and ux_dcd_ra8_usb_uninitialize().
| volatile uint32_t g_dcd_auto_echo_enable = 0U |
Non-zero once ISR-side auto-echo is armed.
Defined in ux_dcd_ra8_usb.c.
Definition at line 110 of file ux_dcd_ra8_usb.c.
Referenced by internal_endpoint_arm_out_pid(), internal_irq_auto_echo(), internal_irq_drain_orphan_out(), and ux_dcd_ra8_usb_auto_echo_enable().
| uint8_t g_dcd_auto_echo_in_pipe = 0U |
Pipe the auto-echo path re-queues onto.
Defined in ux_dcd_ra8_usb.c.
Definition at line 114 of file ux_dcd_ra8_usb.c.
Referenced by internal_irq_auto_echo(), and ux_dcd_ra8_usb_auto_echo_enable().
| uint8_t g_dcd_auto_echo_out_pipe = 0U |
Pipe drained by the in-ISR auto-echo path.
Defined in ux_dcd_ra8_usb.c.
Definition at line 112 of file ux_dcd_ra8_usb.c.
Referenced by internal_endpoint_arm_out_pid(), internal_irq_auto_echo(), internal_irq_drain_orphan_out(), and ux_dcd_ra8_usb_auto_echo_enable().
| ra8_usb_dcd_diag_t g_diag = {} |
Bridge diagnostic counter block, defined in ux_dcd_ra8_usb.c.
Bridge diagnostic counter block.
Read via JLink memory.
Definition at line 291 of file ux_dcd_ra8_usb.c.
Referenced by internal_count_change_state(), internal_endpoint_create(), internal_irq_complete_out(), internal_irq_recover_in_nak(), internal_irq_stage_next_in(), internal_irq_walk_pipe(), internal_wait_completion(), and priv_transfer_request().
| volatile uint32_t g_isr_spurious_run = 0U |
Consecutive event-less ISR entries since the last SysTick re-enable.
Consecutive event-less FS ISR entries since the last SysTick re-enable.
Defined in ux_dcd_ra8_usb.c.
Incremented by internal_usbfs_isr on an entry with no real event bit, reset by it on a real event, and zeroed every 1 ms by ux_dcd_ra8_usb_irq_reenable. JLink-readable storm probe.
Definition at line 185 of file ux_dcd_ra8_usb.c.
Referenced by internal_usbfs_isr(), internal_usbhs_isr(), and ux_dcd_ra8_usb_irq_reenable().
| volatile uint16_t g_lpsts_after_dcd_init = 0U |
LPSTS snapshot at end of ux_dcd_ra8_usb_initialize.
Companion bisect probe; expected SUSPENDM=1 (0x4000). HUM Ch 37.2.43 LPSTS p 2111.
Definition at line 92 of file ux_dcd_ra8_usb.c.
Referenced by ux_dcd_ra8_usb_initialize().
| volatile uint16_t g_syscfg_after_dcd_init = 0U |
SYSCFG snapshot at end of ux_dcd_ra8_usb_initialize.
Bisect probe for the "USBE clears between phy bring-up and echo loop" regression. Read via JLink to confirm whether the DCD bridge or anything it calls (e.g. _ux_dcd_ra8_usb_function CREATE_ENDPOINT, _ux_utility_descriptor_parse, the dispatch worker spawn) clobbers SYSCFG. HUM Ch 37.2.1 SYSCFG p 2060.
Definition at line 80 of file ux_dcd_ra8_usb.c.
Referenced by ux_dcd_ra8_usb_initialize().
|
static |
Definition at line 65 of file ux_dcd_ra8_usb.c.
|
static |
NVIC slot the USB controller's ELC event is routed to.
Resolved once via ra8_isr_lookup_slot in internal_usbfs_storm_guard_init; drives the ISER/ICER math.
Definition at line 175 of file ux_dcd_ra8_usb.c.
Referenced by internal_usbfs_irq_set_enabled(), internal_usbfs_storm_guard_init(), and ux_dcd_ra8_usb_irq_reenable().