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

Native USB controller driver implementation (device + host). More...

#include "ra8_usb.h"
#include <stdint.h>
#include "ra8_attributes.h"
#include "ra8_check.h"
#include "ra8_err.h"
#include "ra8_hw_err.h"
#include "ra8_mstp.h"
#include "ra8_usb_internal.h"
#include "ra8_usb_regs.h"
Include dependency graph for ra8_usb.c:

Go to the source code of this file.

Typedefs

typedef uint32_t ra8_usb_cfifo32_t
 32-bit view of the CFIFO data port, permitted to alias the 16-bit CFIFO register lane.

Enumerations

enum  ra8_usb_internal_lim32_t : uint32_t {
  k_ra8_usb_frdy_poll_limit = 10000000UL ,
  k_ra8_usb_dblb_frdy_poll_limit = 256UL ,
  k_ra8_usb_fifosel_settle_limit = 1000UL
}
 32-bit driver-wide bounds (don't fit in uint16_t). More...
enum  ra8_usb_fifo_shift_t : uint8_t {
  k_ra8_usb_shift_b1 = 8U ,
  k_ra8_usb_shift_b2 = 16U ,
  k_ra8_usb_shift_b3 = 24U
}
 Byte-shift constants for packing CFIFO writes. More...

Functions

volatile r_usb_regs_tpriv_pick (ra8_usb_speed_t speed)
 Resolve the per-speed register pointer.
ra8_mstp_t priv_mstp (ra8_usb_speed_t speed)
 Resolve the per-speed MSTP id.
void priv_rmw16 (volatile uint16_t *reg, uint16_t set_mask, uint16_t clr_mask)
 Apply a generic read-modify-write to a 16-bit register.
bool priv_is_hs (volatile const r_usb_regs_t *reg)
 Detect whether reg points at the USBHS (IP1) register block.
void priv_select_cfifo (volatile r_usb_regs_t *reg, uint16_t pipe_num, bool is_in_dir)
 Set CFIFOSEL.MBW + CURPIPE + ISEL for the given pipe / direction.
ra8_err_t priv_wait_frdy (volatile r_usb_regs_t *reg)
 Spin until CFIFOCTR.FRDY asserts or a deadline elapses.
void priv_dcp_pid (volatile r_usb_regs_t *reg, ra8_usb_pid_t pid)
 Set DCPCTR PID field to a specific value while preserving the rest of the register.
void priv_pipe_pid (volatile r_usb_regs_t *reg, uint8_t pipe_num, ra8_usb_pid_t pid)
 Set PIPECTR[idx] PID field.
uint16_t priv_pipebuf_word (uint8_t pipe_num, uint16_t max_packet)
 Compute the PIPEBUF word for a bulk pipe (2*MPS region).
uint16_t priv_pipecfg_word (uint8_t ep_addr, ra8_usb_ep_dir_t dir, ra8_usb_ep_type_t type, bool dblb_in)
 Pack PIPECFG fields for a configured non-control pipe.
void priv_pipe_quiesce (volatile r_usb_regs_t *reg, uint8_t pipe_num)
 Quiesce the pipe so PIPECFG/PIPEMAXP/PIPEPERI become writable.
static void internal_fifo_write_hs_tail (volatile r_usb_regs_t *reg, const uint8_t *data, uint16_t len)
 HS-only: write the residual 0-3 bytes after 32-bit chunks.
static void internal_fifo_write_hs_head (volatile r_usb_regs_t *reg, const uint8_t *data, uint16_t len)
 HS-only: 32-bit CFIFO write loop for the head bytes.
void priv_fifo_write (volatile r_usb_regs_t *reg, const uint8_t *data, uint16_t len)
 Push a byte buffer into the CFIFO data port.
static void internal_fifo_read_hs_head (volatile r_usb_regs_t *reg, uint8_t *data, uint16_t len)
 HS-only: 32-bit CFIFO read loop for the head bytes.
static void internal_fifo_read_hs_tail (volatile r_usb_regs_t *reg, uint8_t *data, uint16_t len)
 HS-only: read trailing 1..3 bytes from CFIFOH / CFIFOHH aliases.
void priv_fifo_read (volatile r_usb_regs_t *reg, uint8_t *data, uint16_t len)
 Drain the CFIFO data port into a buffer.
ra8_err_t priv_dcp_push_chunk (volatile r_usb_regs_t *reg, const uint8_t *p, uint16_t n)
 Push a single DCP IN chunk: wait for FRDY, write FIFO, pulse BVAL.

Variables

static const char * s_tag = "USB"

Detailed Description

Native USB controller driver implementation (device + host).

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

Hand-written driver for the two RA8D2 USB controllers (USBFS @ 0x40250000 – HUM Ch 36, USBHS @ 0x40351000 – HUM Ch 37). The two instances share the FSP "USB2_B" register layout so this file multiplexes them via a ra8_usb_speed_t argument and an priv_pick(speed) helper. No FSP, CherryUSB, or TinyUSB source ships in this tree – this file is the native peripheral driver, modelled on FSP's r_usb_pdriver.c / r_usb_preg_access.c / r_usb_preg_abs.c (device) and r_usb_hreg_access.c / r_usb_hreg_abs.c (host) flow.

Mapping vs FSP (FSP function -> our entry point):

Intentional gaps (deferred work, with FSP file:line + reason):

  • HS PHY power-down / PLL bring-up (r_usb_preg_access.c) – the EK-RA8D2 boots its HS PHY from the same 48 MHz clock the bootloader leaves running, so the driver assumes the PHY is already powered. Adding a full HS PHY sequence is tracked against the next iteration.
  • DMA glue (r_usb_dma.c) – this driver runs in CPU-FIFO mode only.
  • OTG / role-swap paths (r_usb_hdriver.c) – not ported. Host and device modes are independently selected at init time.
  • USB hubs – the host-side starter targets a single attached device. Hub class enumeration is out of scope.

Definition in file ra8_usb.c.

Typedef Documentation

◆ ra8_usb_cfifo32_t

typedef uint32_t ra8_usb_cfifo32_t

32-bit view of the CFIFO data port, permitted to alias the 16-bit CFIFO register lane.

The CFIFO data port is physically 32 bits wide at CFIFO+0, and at MBW=32 a single 32-bit access is what advances the FIFO read/write pointer (HUM Ch 37.2.7 "CFIFO Port Register"). The register map (r_usb_regs_t) declares only the low 16-bit CFIFO half, so draining/filling a 32-bit word is a legitimate width-pun of that MMIO address. Marking the access type may_alias tells the optimiser the 32-bit read/write aliases the register storage, so it stays a single 32-bit load/store under strict aliasing at -O2 – without it GCC assumes the 32-bit access is independent of the 16-bit struct member (undefined behaviour, flagged by -Wstrict-aliasing) and may reorder or elide it.

Note
Used only for the 32-bit CFIFO fills/drains in this file.
Since
0.1.0

Definition at line 490 of file ra8_usb.c.

Enumeration Type Documentation

◆ ra8_usb_fifo_shift_t

enum ra8_usb_fifo_shift_t : uint8_t

Byte-shift constants for packing CFIFO writes.

Enumerator
k_ra8_usb_shift_b1 

Shift for byte 1.

k_ra8_usb_shift_b2 

Shift for byte 2.

k_ra8_usb_shift_b3 

Shift for byte 3.

Definition at line 465 of file ra8_usb.c.

◆ ra8_usb_internal_lim32_t

enum ra8_usb_internal_lim32_t : uint32_t

32-bit driver-wide bounds (don't fit in uint16_t).

frdy_poll_limit is sized for the worst-case wait between two consecutive DCP IN chunks. The DCP is single-buffered: after pushing chunk N, FRDY does NOT re-assert until the host has actually pulled chunk N off the wire (one full IN token + data + ACK round-trip on USB-FS, ~50 us). The original 1000-spin limit (~1 us at 1 GHz) timed out unconditionally on every multi-chunk EP0 IN, so 75-byte CONFIGURATION descriptors stalled at chunk 1. 10 million spins == ~10 ms ceiling at 1 GHz, well above the USB-FS host's IN re-issue cadence; the loop exits early on the first FRDY=1 sample so the typical post-host-pull wait is still sub-100 us. Synchronous polling is acceptable because the dispatch loop runs in a dedicated ThreadX worker, not in NVIC context.

Enumerator
k_ra8_usb_frdy_poll_limit 

Spin-loops before timeout.

k_ra8_usb_dblb_frdy_poll_limit 

RA8 USB dblb frdy poll limit.

k_ra8_usb_fifosel_settle_limit 

RA8 USB fifosel settle limit.

Definition at line 90 of file ra8_usb.c.

Function Documentation

◆ internal_fifo_read_hs_head()

void internal_fifo_read_hs_head ( volatile r_usb_regs_t * reg,
uint8_t * data,
uint16_t len )
static

HS-only: 32-bit CFIFO read loop for the head bytes.

Mirrors FSP hw_usb_read_fifo32: cast &CFIFO to uint32_t* and read len/4 32-bit words into the destination buffer (little-endian byte order).

Parameters
[in]regHS register block.
[out]dataDestination byte pointer.
[in]lenTotal payload length; reads only the head (len & ~0x3) bytes.
Precondition
CFIFOSEL.MBW == 32.
data != NULL when len > 0.
Postcondition
DTLN advanced by exactly (len & ~0x3) bytes.
data[0..(len&~0x3)-1] holds the received bytes in LE order.
Note
Not thread-safe.
Since
0.1.0

Definition at line 639 of file ra8_usb.c.

References r_usb_regs_t::CFIFO, k_ra8_usb_byte_mask, k_ra8_usb_shift_b1, k_ra8_usb_shift_b2, and k_ra8_usb_shift_b3.

Referenced by priv_fifo_read().

◆ internal_fifo_read_hs_tail()

void internal_fifo_read_hs_tail ( volatile r_usb_regs_t * reg,
uint8_t * data,
uint16_t len )
static

HS-only: read trailing 1..3 bytes from CFIFOH / CFIFOHH aliases.

Mirrors FSP hw_usb_read_fifo16 / hw_usb_read_fifo8 (little-endian). On USBHS a narrow read must go to CFIFOH (+0x02) / CFIFOHH (+0x03); reading CFIFO itself at MBW=16/8 does not advance the read pointer.

Parameters
[in]regHS register block.
[out]dataDestination byte pointer.
[in]lenTotal payload length; reads only the tail (len & 0x3) bytes.
Precondition
CFIFOSEL.MBW == 32 on entry (restored on exit).
data != NULL when len > 0.
Postcondition
Tail bytes written; CFIFOSEL.MBW restored.
DTLN advanced by exactly (len & 0x3) bytes.
Note
Not thread-safe.
Since
0.1.0

Definition at line 669 of file ra8_usb.c.

References r_usb_regs_t::CFIFO, k_ra8_usb_byte_mask, k_ra8_usb_shift_b1, k_ra8_usb_shift_b2, and k_ra8_usb_shift_b3.

Referenced by priv_fifo_read().

◆ internal_fifo_write_hs_head()

void internal_fifo_write_hs_head ( volatile r_usb_regs_t * reg,
const uint8_t * data,
uint16_t len )
static

HS-only: 32-bit CFIFO write loop for the head bytes.

Mirrors FSP hw_usb_write_fifo32: cast &CFIFO to uint32_t* and write len/4 32-bit words.

Parameters
[in]regHS register block.
[in]dataSource byte pointer.
[in]lenTotal payload length; this helper writes only the head (len & ~0x3) bytes.
Precondition
CFIFOSEL.MBW == 32.
data != NULL when len > 0.
Postcondition
DTLN advanced by exactly (len & ~0x3) bytes.
FIFO contains head bytes ready for BVAL commit.
Note
Not thread-safe.
Since
0.1.0

Definition at line 560 of file ra8_usb.c.

References r_usb_regs_t::CFIFO, k_ra8_usb_shift_b1, k_ra8_usb_shift_b2, and k_ra8_usb_shift_b3.

Referenced by priv_fifo_write().

◆ internal_fifo_write_hs_tail()

void internal_fifo_write_hs_tail ( volatile r_usb_regs_t * reg,
const uint8_t * data,
uint16_t len )
static

HS-only: write the residual 0-3 bytes after 32-bit chunks.

FSP narrows CFIFOSEL.MBW to 16 then 8 for trailing halfword/byte. We save+restore MBW around these writes.

Parameters
[in]regHS register block.
[in]dataSource byte pointer.
[in]lenTotal payload length.
Precondition
Caller already wrote (len & ~0x3) bytes via 32-bit access.
CFIFOSEL.MBW currently == 32.
Postcondition
Tail bytes pushed; CFIFOSEL.MBW restored.
DTLN advanced by exactly (len & 0x3) bytes.
Note
Not thread-safe.
Since
0.1.0

Definition at line 508 of file ra8_usb.c.

References internal_fifo_write_hs_tail(), k_ra8_fifosel_mbw_16, k_ra8_fifosel_mbw_8, k_ra8_fifosel_mbw_msk, and k_ra8_usb_byte_bits.

Referenced by internal_fifo_write_hs_tail(), and priv_fifo_write().

◆ priv_dcp_pid()

void priv_dcp_pid ( volatile r_usb_regs_t * reg,
ra8_usb_pid_t pid )

Set DCPCTR PID field to a specific value while preserving the rest of the register.

Set DCPCTR PID field while preserving the rest of the register.

See implementation.

Parameters
[in]regSee implementation.
[in]pidSee 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 288 of file ra8_usb.c.

References r_usb_regs_t::DCPCTR, k_ra8_pid_mask, and priv_rmw16().

Referenced by internal_dcp_in_payload(), internal_dcp_in_zlp(), internal_host_ctrl_data_arm(), internal_host_ctrl_data_in(), internal_host_ctrl_data_out(), internal_host_ctrl_setup(), internal_host_ctrl_status(), internal_host_dcp_in_wait(), ra8_usb_control_response(), ra8_usb_dcp_out_arm(), ra8_usb_dcp_out_read(), and ra8_usb_stall_endpoint().

◆ priv_dcp_push_chunk()

ra8_err_t priv_dcp_push_chunk ( volatile r_usb_regs_t * reg,
const uint8_t * p,
uint16_t n )

Push a single DCP IN chunk: wait for FRDY, write FIFO, pulse BVAL.

Push a single DCP IN chunk: wait FRDY, write FIFO, pulse BVAL.

Bounded helper extracted from ra8_usb_dcp_in_data so the top-level function stays under the clang-tidy readability-function-size threshold. Performs exactly one controller-buffer transfer cycle.

Parameters
[in,out]regDCP register block (chip or host shim).
[in]pSource byte pointer; must hold at least n bytes.
[in]nChunk size in bytes; must be > 0 and <= the DCP MPS.
Returns
ra8_err_t Error code.
Return values
k_ra8_okChunk queued; BVAL pulsed.
k_ra8_err_timeoutFRDY never asserted within the bound.
Precondition
reg was returned by priv_pick() and is non-NULL.
CFIFO is already selected on DCP (CURPIPE=0) in IN direction.
Postcondition
On success, the controller buffer holds the new chunk and BVAL has been pulsed.
On error, no PID transition has been performed.
Note
Not thread-safe; the parent function holds the DCP lock.
Since
0.1.0

Definition at line 770 of file ra8_usb.c.

References r_usb_regs_t::CFIFOCTR, k_ra8_fifoctr_bval, k_ra8_ok, priv_fifo_write(), priv_wait_frdy(), RA8_RETURN_ON_ERROR, and s_tag.

Referenced by internal_dcp_in_payload(), and internal_host_ctrl_data_out().

◆ priv_fifo_read()

void priv_fifo_read ( volatile r_usb_regs_t * reg,
uint8_t * data,
uint16_t len )

Drain the CFIFO data port into a buffer.

Dispatches to the speed-appropriate access width: USBHS requires 32-bit reads (MBW=32) – a 16-bit read does not advance the FIFO read pointer (HUM Ch 37.2.7 p 2070, FSP hw_usb_read_fifo32). USBFS keeps MBW=16. Mirrors FSP usb_pstd_read_fifo for IP1/IP0.

Parameters
[in]regUSB instance register block.
[out]dataDestination byte pointer (may be NULL when len == 0).
[in]lenNumber of bytes to drain.
Precondition
Caller selected DCP / pipe with priv_select_cfifo and FRDY=1.
data != NULL when len > 0.
Postcondition
DTLN advanced by len bytes.
data[0..len-1] holds the received payload bytes.
Note
Not thread-safe.
Since
0.1.0

Definition at line 712 of file ra8_usb.c.

References r_usb_regs_t::CFIFO, r_usb_regs_t::CFIFOSEL, internal_fifo_read_hs_head(), internal_fifo_read_hs_tail(), k_ra8_fifosel_mbw_8, k_ra8_fifosel_mbw_msk, k_ra8_usb_byte_bits, k_ra8_usb_byte_mask, and priv_is_hs().

Referenced by internal_host_bulk_rx_packet(), internal_host_ctrl_data_in(), ra8_usb_dcp_out_read(), and ra8_usb_queue_out().

◆ priv_fifo_write()

void priv_fifo_write ( volatile r_usb_regs_t * reg,
const uint8_t * data,
uint16_t len )

Push a byte buffer into the CFIFO data port.

Dispatches to the speed-appropriate access width: USBHS uses 32-bit writes (with FSP-style 16/8 narrowing for the trailing 0..3 bytes), USBFS uses 16-bit writes with a single-byte tail. Mirrors FSP usb_pstd_write_fifo for IP1 / IP0 respectively.

Parameters
[in]regUSB instance register block.
[in]dataSource byte pointer (may be NULL when len == 0).
[in]lenNumber of bytes to push.
Precondition
Caller selected DCP / pipe with priv_select_cfifo and observed FRDY=1.
data != NULL when len > 0.
Postcondition
DTLN advanced by len bytes.
FIFO ready for caller's BVAL commit.
Note
Not thread-safe.
Since
0.1.0

Definition at line 592 of file ra8_usb.c.

References r_usb_regs_t::CFIFO, r_usb_regs_t::CFIFOSEL, internal_fifo_write_hs_head(), internal_fifo_write_hs_tail(), k_ra8_fifosel_mbw_8, k_ra8_fifosel_mbw_msk, k_ra8_usb_byte_bits, and priv_is_hs().

Referenced by priv_dcp_push_chunk(), and ra8_usb_queue_in().

◆ priv_is_hs()

bool priv_is_hs ( volatile const r_usb_regs_t * reg)

Detect whether reg points at the USBHS (IP1) register block.

FSP gates USB1_CFIFO_MBW = USB_MBW_32 on the same predicate (p_utr->ip == USB_CFG_IP1), and the FIFO write helpers below mirror that to keep CFIFOSEL.MBW and the CFIFO write width in agreement on each controller.

Parameters
[in]regUSB instance register block pointer.
Returns
true if reg is the HS instance, false for FS.
Return values
trueUSBHS (IP1) – caller should use MBW=32 + 32-bit FIFO.
falseUSBFS (IP0) – caller should use MBW=16 + 16-bit FIFO.
Precondition
reg is a pointer returned by ra8_usb_fs() or ra8_usb_hs().
USB module pointers are populated.
Postcondition
No state mutated.
Returned value reflects controller identity.
Note
Pure function.
Since
0.1.0

Definition at line 179 of file ra8_usb.c.

References ra8_usb_hs().

Referenced by internal_host_ctrl_setup(), priv_fifo_read(), priv_fifo_write(), and priv_select_cfifo().

◆ priv_mstp()

ra8_mstp_t priv_mstp ( ra8_usb_speed_t speed)

Resolve the per-speed MSTP id.

See implementation.

Parameters
[in]speedSee implementation.
Returns
Result code.
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 135 of file ra8_usb.c.

References k_ra8_mstp_usbfs, k_ra8_mstp_usbhs, and k_ra8_usb_speed_hs.

Referenced by ra8_usb_device_deinit(), ra8_usb_device_init(), ra8_usb_enter_stop(), ra8_usb_exit_stop(), ra8_usb_host_deinit(), and ra8_usb_host_init().

◆ priv_pick()

volatile r_usb_regs_t * priv_pick ( ra8_usb_speed_t speed)

Resolve the per-speed register pointer.

Promoted from a TU-private static so every TU in the driver split can map a ra8_usb_speed_t to its controller register block.

Parameters
[in]speedController selector (FS / HS).
Returns
The selected register block, or nullptr for an unknown speed.
Return values
nullptrspeed is neither FS nor HS.
Precondition
USB module pointers are populated.
speed is a ra8_usb_speed_t value.
Postcondition
No state mutated; the helper is pure.
Returned pointer identifies the requested controller.
Note
Pure / thread-safe.
Since
0.1.0

Definition at line 110 of file ra8_usb.c.

References k_ra8_usb_speed_fs, k_ra8_usb_speed_hs, ra8_usb_fs(), and ra8_usb_hs().

Referenced by ra8_usb_clear_status(), ra8_usb_configure_endpoint(), ra8_usb_control_response(), ra8_usb_dcp_in_data(), ra8_usb_dcp_out_arm(), ra8_usb_dcp_out_read(), ra8_usb_device_attach(), ra8_usb_device_busreset_rearm(), ra8_usb_device_deinit(), ra8_usb_device_init(), ra8_usb_dispatch(), ra8_usb_get_device_state(), ra8_usb_get_status(), ra8_usb_host_bulk_in(), ra8_usb_host_bulk_out(), ra8_usb_host_bus_reset(), ra8_usb_host_control_xfer(), ra8_usb_host_deinit(), ra8_usb_host_init(), ra8_usb_host_line_state(), ra8_usb_host_pipe_setup(), ra8_usb_host_set_target(), ra8_usb_host_set_uact(), ra8_usb_host_setup_request(), ra8_usb_intsts0_snapshot(), ra8_usb_park_out_pipe(), ra8_usb_queue_in(), ra8_usb_queue_out(), ra8_usb_read_setup_if_valid(), ra8_usb_read_setup_unconditional(), ra8_usb_rearm_out_pipe(), ra8_usb_set_address(), and ra8_usb_stall_endpoint().

◆ priv_pipe_pid()

void priv_pipe_pid ( volatile r_usb_regs_t * reg,
uint8_t pipe_num,
ra8_usb_pid_t pid )

Set PIPECTR[idx] PID field.

See implementation.

Parameters
[in]regSee implementation.
[in]pipe_numSee implementation.
[in]pidSee 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 308 of file ra8_usb.c.

References k_ra8_pid_mask, r_usb_regs_t::PIPECTR, and priv_rmw16().

Referenced by internal_pipe_finalize(), priv_pipe_quiesce(), ra8_usb_host_bulk_in(), ra8_usb_host_bulk_out(), ra8_usb_park_out_pipe(), ra8_usb_queue_in(), ra8_usb_queue_out(), ra8_usb_rearm_out_pipe(), and ra8_usb_stall_endpoint().

◆ priv_pipe_quiesce()

void priv_pipe_quiesce ( volatile r_usb_regs_t * reg,
uint8_t pipe_num )

Quiesce the pipe so PIPECFG/PIPEMAXP/PIPEPERI become writable.

Clears BRDYENB/NRDYENB/BEMPENB for this pipe and forces PID=NAK (HUM Ch 36.2.24 NOTE 1, p 1996; mirrors STAR rx_usb_hw.c::internal_usb_quiesce_pipe).

Parameters
[in,out]regController register window.
[in]pipe_numPipe index 1..9.
Precondition
reg is non-null and points at a powered controller.
pipe_num in [1,9].
Postcondition
BRDY/NRDY/BEMPENB bit for pipe_num is cleared.
PIPECTR PID for pipe_num == NAK.
Note
Not thread-safe.
Since
0.1.0

Definition at line 447 of file ra8_usb.c.

References r_usb_regs_t::BEMPENB, r_usb_regs_t::BRDYENB, k_ra8_pid_nak, r_usb_regs_t::NRDYENB, and priv_pipe_pid().

Referenced by ra8_usb_configure_endpoint(), and ra8_usb_host_pipe_setup().

◆ priv_pipebuf_word()

uint16_t priv_pipebuf_word ( uint8_t pipe_num,
uint16_t max_packet )

Compute the PIPEBUF word for a bulk pipe (2*MPS region).

Statically partition the controller's internal FIFO RAM among the bulk pipes. Reserve blocks 0..7 (64-byte units) for the DCP (per FSP/Renesas examples), then pack user pipes in pipe-number order with 2*MPS per pipe – IN bulk pipes use both as a double-buffer (PIPECFG.DBLB set), OUT bulk pipes use only the first block (DBLB clear). Uniform 2*MPS keeps the BUFNMB arithmetic simple and wastes at most one block per OUT pipe.

BUFNMB = 8 + (pipe_num - 1) * (2 * mps_blocks) BUFSIZE = (2 * mps_blocks) - 1

HS MPS=512 -> 2*mps_blocks = 16, BUFSIZE = 15 FS MPS=64 -> 2*mps_blocks = 2, BUFSIZE = 1

Parameters
[in]pipe_numPIPE number 1..9.
[in]max_packetPipe MPS (bytes).
Returns
PIPEBUF word ready to be written to register PIPEBUF.
Return values
0..0xFFFFPacked BUFNMB/BUFSIZE word (no error condition; the helper is total over its enum-checked inputs).
Precondition
pipe_num is in the 1..9 range (caller-checked).
max_packet is the pipe's MPS (caller validated <= 1024).
Postcondition
No global state is touched; the helper is pure.
Returned word satisfies HUM Ch 37.2.35 PIPEBUF layout.
Note
Pure / thread-safe.
Since
0.1.0

Definition at line 353 of file ra8_usb.c.

References k_ra8_pipebuf_block_bytes, k_ra8_pipebuf_bufnmb_mask, and k_ra8_pipebuf_bufsize_shift.

Referenced by ra8_usb_configure_endpoint(), and ra8_usb_host_pipe_setup().

◆ priv_pipecfg_word()

uint16_t priv_pipecfg_word ( uint8_t ep_addr,
ra8_usb_ep_dir_t dir,
ra8_usb_ep_type_t type,
bool dblb_in )

Pack PIPECFG fields for a configured non-control pipe.

Encodes endpoint number, direction (DIR), pipe type (TYPE), and for bulk pipes the SHTNAK flag plus (optionally, IN only) the DBLB flag into the PIPECFG word. HUM Ch 36.2.24 PIPECFG. Bulk OUT is always single-buffered, otherwise the controller fills both banks with host data and the one-bank-per-call ra8_usb_queue_out drainer wedges the data phase (GitHub issue #6). Bulk IN double-banking is the caller's choice: HOST mode wants it so queue_in can push a data + ZLP pair back-to-back without the second push hitting a full-bank FRDY stall; DEVICE mode must run single-banked because the free-bank handshake after an MPS-exact fill is unreliable (staging the BOT CSW behind a 512-byte data phase on a 512-MPS HS pipe FRDY-times-out and the transport wedges, observed live vs macOS).

Parameters
[in]ep_addrEndpoint address (low nibble = EP number; bit 7 direction; the helper reads only the EP number).
[in]dirPipe direction (k_ra8_usb_ep_dir_in or _out).
[in]typePipe type (bulk / interrupt / iso).
[in]dblb_inDouble-bank bulk IN pipes (host mode true, device mode false; ignored for OUT / non-bulk).
Returns
PIPECFG word ready to write to PIPECFG.
Return values
0..0xFFFFPacked configuration word; no error condition.
Precondition
ep_addr low nibble is the EP number (caller validated 1..15).
dir / type are valid enum values.
Postcondition
No global state is touched; the helper is pure.
For bulk pipes SHTNAK is set; DBLB only when dblb_in is true with dir == IN (nested ifs, no compound decision).
Note
Pure / thread-safe.
Since
0.1.0

Definition at line 401 of file ra8_usb.c.

References k_ra8_pipecfg_dblb, k_ra8_pipecfg_dir_in, k_ra8_pipecfg_epnum_mask, k_ra8_pipecfg_shtnak, k_ra8_pipecfg_type_bulk, k_ra8_pipecfg_type_intr, k_ra8_pipecfg_type_iso, k_ra8_usb_ep_dir_in, k_ra8_usb_ep_dir_out, k_ra8_usb_ep_type_bulk, and k_ra8_usb_ep_type_intr.

Referenced by ra8_usb_configure_endpoint(), and ra8_usb_host_pipe_setup().

◆ priv_rmw16()

void priv_rmw16 ( volatile uint16_t * reg,
uint16_t set_mask,
uint16_t clr_mask )

Apply a generic read-modify-write to a 16-bit register.

See implementation.

Parameters
[in]regSee implementation.
[in]set_maskSee implementation.
[in]clr_maskSee 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 154 of file ra8_usb.c.

Referenced by internal_host_ctrl_data_arm(), internal_host_ctrl_data_out(), internal_host_ctrl_setup(), internal_host_ctrl_status(), internal_host_hs_bringup(), internal_host_setup_wait(), internal_pipe_finalize(), priv_dcp_pid(), priv_pipe_pid(), ra8_usb_control_response(), ra8_usb_dcp_out_arm(), ra8_usb_device_attach(), ra8_usb_host_bus_reset(), ra8_usb_host_init(), ra8_usb_host_pipe_setup(), ra8_usb_host_set_uact(), and ra8_usb_host_setup_request().

◆ priv_select_cfifo()

void priv_select_cfifo ( volatile r_usb_regs_t * reg,
uint16_t pipe_num,
bool is_in_dir )

Set CFIFOSEL.MBW + CURPIPE + ISEL for the given pipe / direction.

Picks MBW=32 for USBHS (FSP USB1_CFIFO_MBW) and MBW=16 for USBFS (FSP USB0_CFIFO_MBW). The CFIFO data-port access width must match the MBW field on subsequent CFIFO accesses.

Parameters
[in]regUSB instance register block.
[in]pipe_numCURPIPE value (0 = DCP, 1..n = data pipe).
[in]is_in_dirtrue = device-to-host (write), false = host-to-device.
Precondition
reg != NULL.
Caller holds the DCP / pipe lock.
Postcondition
CFIFOSEL = MBW(speed) | (is_in_dir ? ISEL : 0) | pipe_num.
Subsequent CFIFO accesses must use the matching width.
Note
Not thread-safe.
Since
0.1.0

Definition at line 199 of file ra8_usb.c.

References r_usb_regs_t::CFIFOSEL, k_ra8_fifosel_curpipe, k_ra8_fifosel_isel, k_ra8_fifosel_mbw_16, k_ra8_fifosel_mbw_32, k_ra8_usb_fifosel_settle_limit, and priv_is_hs().

Referenced by internal_dcp_reset_defaults(), internal_host_bulk_rx_packet(), internal_host_ctrl_data_arm(), internal_host_ctrl_data_in(), internal_host_ctrl_data_out(), internal_host_ctrl_status(), ra8_usb_dcp_in_data(), ra8_usb_dcp_out_arm(), ra8_usb_dcp_out_read(), ra8_usb_queue_in(), and ra8_usb_queue_out().

◆ priv_wait_frdy()

ra8_err_t priv_wait_frdy ( volatile r_usb_regs_t * reg)

Spin until CFIFOCTR.FRDY asserts or a deadline elapses.

Returns
ra8_ok on FRDY, k_ra8_err_hw_timeout otherwise.

Runs the real bounded FRDY poll on every build. On the host unit-test build each poll's loop-exit decision is routed through the ra8_fake_mmio fault seam keyed on CFIFOCTR: first-poll success when no fault is armed, or a test-armed retry / timeout leg (T1-01).

Parameters
[in]regSelected controller register block (non-NULL).
Return values
k_ra8_okFRDY observed before the deadline.
k_ra8_err_hw_timeoutFRDY never asserted within the budget.
Precondition
The CFIFO window is selected on the intended pipe.
reg points at a live controller register block.
Postcondition
On k_ra8_ok the CFIFO port is ready for a read/write access.
No register is modified by this function.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Definition at line 251 of file ra8_usb.c.

References r_usb_regs_t::CFIFOCTR, k_ra8_err_hw_timeout, k_ra8_fifoctr_frdy, k_ra8_ok, and k_ra8_usb_frdy_poll_limit.

Referenced by internal_dcp_in_zlp(), internal_host_bulk_rx_packet(), internal_host_ctrl_data_in(), priv_dcp_push_chunk(), ra8_usb_dcp_out_read(), ra8_usb_queue_in(), and ra8_usb_queue_out().

Variable Documentation

◆ s_tag

const char* s_tag = "USB"
static

Definition at line 66 of file ra8_usb.c.