ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_usb_host_bulk.c
Go to the documentation of this file.
1
24
25#include <stdint.h>
26
27#include "ra8_attributes.h"
28#include "ra8_check.h"
29#include "ra8_err.h"
30#include "ra8_usb.h"
31#include "ra8_usb_internal.h"
32#include "ra8_usb_regs.h"
33
34static const char* s_tag = "USB";
35
36/* =============================================================================
37 * Host-mode bulk-transfer engine (polled, synchronous)
38 *
39 * Built on the same host signals the control engine validated on hardware:
40 * BRDY (a packet landed in the pipe buffer), BEMP (the pipe buffer emptied
41 * onto the wire), and PIPECTR.PID for STALL detection. Pipes reuse the CFIFO
42 * port (CFIFOSEL.CURPIPE selects the pipe; the data direction is fixed by
43 * PIPECFG.DIR, so ISEL stays clear for non-DCP pipes).
44 * =============================================================================
45 */
46
48typedef enum : uint32_t {
49 /* Each spin performs two peripheral-bus reads (~150 ns/read on the FS
50 * block), so 10M spins is roughly a 3 s ceiling -- enough for flash
51 * media latency while keeping a failed phase visibly bounded. */
54
79 volatile const uint16_t* sts,
80 uint8_t pipe_num)
81{
82 const uint16_t bit = (uint16_t)(1U << pipe_num);
83 const uint8_t idx = (uint8_t)(pipe_num - 1U);
84 for (uint32_t i = 0U; i < (uint32_t)k_ra8_usb_bulk_poll_limit; ++i) {
85 if ((*sts & bit) != 0U) {
86 return k_ra8_ok;
87 }
88 if ((reg->PIPECTR[idx] & (uint16_t)k_ra8_usb_pid_stall_bit) != 0U) {
89 /* STALL bit is SIE-async; callers force PID=BUF before this spin, the fake cannot raise it. */
90 return k_ra8_err_hw_error; /* GCOVR_EXCL_LINE -- async SIE STALL absent from host fake */
91 }
92 }
94}
95
113{
114 volatile r_usb_regs_t* reg = priv_pick(speed);
115 if (reg == nullptr) {
117 }
118 if (dev_addr > (uint8_t)k_ra8_usb_dev_addr_max) {
120 }
121 priv_host_program_devadd(reg, dev_addr);
122 const uint16_t mxps = (uint16_t)(reg->DCPMAXP & (uint16_t)k_ra8_usb_dcpmaxp_mxps);
123 reg->DCPMAXP =
124 (uint16_t)((uint16_t)((uint16_t)dev_addr << (uint16_t)k_ra8_usb_devsel_shift) | mxps);
125 return k_ra8_ok;
126}
127
150static ra8_err_t
151internal_host_pipe_args_ok(uint8_t pipe_num, uint8_t dev_addr, uint8_t ep_num, uint16_t max_packet)
152{
153 if (pipe_num == 0U) {
155 }
156 if (pipe_num > (uint8_t)k_ra8_usb_max_pipe_num) {
158 }
159 if (dev_addr > (uint8_t)k_ra8_usb_dev_addr_max) {
161 }
162 if (ep_num == 0U) {
164 }
165 if (ep_num > (uint8_t)k_ra8_pipecfg_epnum_mask) {
167 }
168 if (max_packet == 0U) {
170 }
171 if (max_packet > (uint16_t)k_ra8_usb_pipemaxp_mxps) {
173 }
174 return k_ra8_ok;
175}
176
201 uint8_t pipe_num,
202 uint8_t dev_addr,
203 uint8_t ep_num,
204 bool device_to_host,
205 uint16_t max_packet)
206{
207 volatile r_usb_regs_t* reg = priv_pick(speed);
208 if (reg == nullptr) {
210 }
211 const ra8_err_t arg_err = internal_host_pipe_args_ok(pipe_num, dev_addr, ep_num, max_packet);
212 if (arg_err != k_ra8_ok) {
213 return arg_err;
214 }
215 priv_pipe_quiesce(reg, pipe_num);
216 const ra8_usb_ep_dir_t cfg_dir = device_to_host ? k_ra8_usb_ep_dir_out : k_ra8_usb_ep_dir_in;
217 reg->PIPESEL = pipe_num;
218 reg->PIPECFG = priv_pipecfg_word(ep_num, cfg_dir, k_ra8_usb_ep_type_bulk, true);
219 reg->PIPEBUF = priv_pipebuf_word(pipe_num, max_packet);
220 reg->PIPEMAXP = (uint16_t)((uint16_t)((uint16_t)dev_addr << (uint16_t)k_ra8_usb_devsel_shift) |
221 (uint16_t)(max_packet & (uint16_t)k_ra8_usb_pipemaxp_mxps));
222 reg->PIPEPERI = 0U;
223 reg->PIPESEL = 0U;
224 priv_rmw16(&reg->PIPECTR[(uint8_t)(pipe_num - 1U)], (uint16_t)(1U << k_ra8_dcpctr_bit_sqclr), 0U);
225 const uint16_t pipe_bit = (uint16_t)(1U << pipe_num);
226 reg->BRDYSTS = (uint16_t)~pipe_bit;
227 reg->NRDYSTS = (uint16_t)~pipe_bit;
228 reg->BEMPSTS = (uint16_t)~pipe_bit;
229 return k_ra8_ok;
230}
231
253ra8_usb_host_bulk_out(ra8_usb_speed_t speed, uint8_t pipe_num, const uint8_t* data, uint16_t len)
254{
255 RA8_CHECK_NULL_PTR(data, s_tag, "host_bulk_out: data");
256 volatile r_usb_regs_t* reg = priv_pick(speed);
257 if (reg == nullptr) {
259 }
260 if (pipe_num == 0U) {
262 }
263 if (pipe_num > (uint8_t)k_ra8_usb_max_pipe_num) {
265 }
266 const uint16_t pipe_bit = (uint16_t)(1U << pipe_num);
267 reg->BEMPSTS = (uint16_t)~pipe_bit;
268 reg->BEMPENB = (uint16_t)(reg->BEMPENB | pipe_bit);
269 const ra8_err_t qerr = ra8_usb_queue_in(speed, pipe_num, data, len);
270 if (qerr != k_ra8_ok) {
271 return qerr;
272 }
273 const ra8_err_t werr = internal_host_wait_pipe(reg, &reg->BEMPSTS, pipe_num);
274 priv_pipe_pid(reg, pipe_num, k_ra8_pid_nak);
275 reg->BEMPSTS = (uint16_t)~pipe_bit;
276 return werr;
277}
278
306 uint8_t pipe_num,
307 uint8_t* dst,
308 uint16_t room,
309 uint16_t* out_dtln,
310 uint16_t* out_copied)
311{
312 const ra8_err_t werr = internal_host_wait_pipe(reg, &reg->BRDYSTS, pipe_num);
313 if (werr != k_ra8_ok) {
314 return werr;
315 }
316 /* Acknowledge the BRDY edge BEFORE draining the buffer: at high speed
317 * the device's next packet (e.g. the CSW right behind a full data
318 * packet) lands while the FIFO is being read, and clearing the status
319 * afterwards wipes that new edge (observed as the follow-up packet
320 * stuck with BSTS=1 while the wait times out). */
321 reg->BRDYSTS = (uint16_t)~(uint16_t)(1U << pipe_num);
322 priv_select_cfifo(reg, (uint16_t)pipe_num, false);
323 const ra8_err_t ferr = priv_wait_frdy(reg);
324 if (ferr != k_ra8_ok) {
325 return ferr;
326 }
327 const uint16_t dtln = (uint16_t)(reg->CFIFOCTR & (uint16_t)k_ra8_fifoctr_dtln);
328 uint16_t copy = dtln;
329 if (copy > room) {
330 copy = room;
331 }
332 if (copy > 0U) {
333 priv_fifo_read(reg, dst, copy);
334 }
335 if (copy < dtln) {
336 reg->CFIFOCTR = (uint16_t)k_ra8_fifoctr_bclr;
337 }
338 if (dtln == 0U) {
339 reg->CFIFOCTR = (uint16_t)k_ra8_fifoctr_bclr;
340 }
341 *out_dtln = dtln;
342 *out_copied = copy;
343 return k_ra8_ok;
344}
345
369 uint8_t pipe_num,
370 uint8_t* buf,
371 uint16_t max_len,
372 uint16_t mps,
373 uint16_t* out_rx)
374{
375 uint16_t rx = 0U;
376 ra8_err_t err = k_ra8_ok;
377 bool done = false;
378 while (!done) {
379 uint16_t dtln = 0U;
380 uint16_t copied = 0U;
382 pipe_num,
383 &buf[rx],
384 (uint16_t)(max_len - rx),
385 &dtln,
386 &copied);
387 if (err != k_ra8_ok) {
388 done = true;
389 } else {
390 rx = (uint16_t)(rx + copied);
391 if (dtln < mps) {
392 done = true;
393 }
394 if (rx >= max_len) {
395 done = true;
396 }
397 }
398 }
399 *out_rx = rx;
400 return err;
401}
402
425 uint8_t pipe_num,
426 uint8_t* buf,
427 uint16_t max_len,
428 uint16_t* out_received)
429{
430 RA8_CHECK_NULL_PTR(buf, s_tag, "host_bulk_in: buf");
431 RA8_CHECK_NULL_PTR(out_received, s_tag, "host_bulk_in: out_received");
432 volatile r_usb_regs_t* reg = priv_pick(speed);
433 if (reg == nullptr) {
435 }
436 if (pipe_num == 0U) {
438 }
439 if (pipe_num > (uint8_t)k_ra8_usb_max_pipe_num) {
441 }
442 reg->PIPESEL = pipe_num;
443 const uint16_t mps = (uint16_t)(reg->PIPEMAXP & (uint16_t)k_ra8_usb_pipemaxp_mxps);
444 reg->PIPESEL = 0U;
445 if (mps == 0U) {
447 }
448 const uint16_t pipe_bit = (uint16_t)(1U << pipe_num);
449 /* Do NOT clear a pending BRDY here: at high speed the device can push
450 * the next packet (e.g. the CSW right behind a full data packet) into
451 * the pipe buffer while the previous transfer is winding down, and its
452 * BRDY is already latched -- clearing it would strand that packet in
453 * the buffer (observed as BSTS=1 with the wait timing out). */
454 reg->BRDYENB = (uint16_t)(reg->BRDYENB | pipe_bit);
455 priv_pipe_pid(reg, pipe_num, k_ra8_pid_buf);
456 uint16_t rx = 0U;
457 const ra8_err_t err = internal_host_bulk_rx_loop(reg, pipe_num, buf, max_len, mps, &rx);
458 priv_pipe_pid(reg, pipe_num, k_ra8_pid_nak);
459 *out_received = rx;
460 return err;
461}
462
477{
478 volatile const r_usb_regs_t* reg = priv_pick(speed);
479 if (reg == nullptr) {
480 return 0U;
481 }
482 return (uint16_t)(reg->SYSSTS0 & (uint16_t)k_ra8_usb_lnst_mask);
483}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
Error Code Definitions for ra8-firmware.
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_err_invalid_state
Module in wrong state for requested operation.
Definition ra8_err.h:161
@ k_ra8_err_hw_timeout
Hardware timed out waiting for a flag or handshake.
Definition ra8_err.h:304
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_hw_error
Generic hardware fault detected (error flag set, fault interrupt).
Definition ra8_err.h:310
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
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.
Definition ra8_usb.c:154
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.
Definition ra8_usb.c:199
ra8_err_t priv_wait_frdy(volatile r_usb_regs_t *reg)
Spin until CFIFOCTR.FRDY asserts or a deadline elapses.
Definition ra8_usb.c:251
volatile r_usb_regs_t * priv_pick(ra8_usb_speed_t speed)
Resolve the per-speed register pointer.
Definition ra8_usb.c:110
uint16_t priv_pipebuf_word(uint8_t pipe_num, uint16_t max_packet)
Compute the PIPEBUF word for a bulk pipe (2*MPS region).
Definition ra8_usb.c:353
void priv_pipe_pid(volatile r_usb_regs_t *reg, uint8_t pipe_num, ra8_usb_pid_t pid)
Set PIPECTR[idx] PID field.
Definition ra8_usb.c:308
void priv_pipe_quiesce(volatile r_usb_regs_t *reg, uint8_t pipe_num)
Quiesce the pipe so PIPECFG/PIPEMAXP/PIPEPERI become writable.
Definition ra8_usb.c:447
void priv_fifo_read(volatile r_usb_regs_t *reg, uint8_t *data, uint16_t len)
Drain the CFIFO data port into a buffer.
Definition ra8_usb.c:712
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.
Definition ra8_usb.c:401
Native USB controller driver public API (device + host modes).
@ k_ra8_usb_ep_type_bulk
Bulk transfer.
ra8_usb_ep_dir_t
Endpoint direction.
@ k_ra8_usb_ep_dir_in
Device -> host.
@ k_ra8_usb_ep_dir_out
Host -> device.
ra8_usb_speed_t
Selects which controller instance the call targets.
ra8_err_t ra8_usb_queue_in(ra8_usb_speed_t speed, uint8_t pipe_num, const uint8_t *data, uint16_t len)
Queue an IN transfer (device -> host) on pipe_num.
ra8_err_t ra8_usb_host_bulk_out(ra8_usb_speed_t speed, uint8_t pipe_num, const uint8_t *data, uint16_t len)
Implementation of ra8_usb_host_bulk_out().
static ra8_err_t internal_host_bulk_rx_loop(volatile r_usb_regs_t *reg, uint8_t pipe_num, uint8_t *buf, uint16_t max_len, uint16_t mps, uint16_t *out_rx)
Consume bulk-IN packets until short packet, fill, or error.
uint16_t ra8_usb_host_line_state(ra8_usb_speed_t speed)
Implementation of ra8_usb_host_line_state().
ra8_err_t ra8_usb_host_pipe_setup(ra8_usb_speed_t speed, uint8_t pipe_num, uint8_t dev_addr, uint8_t ep_num, bool device_to_host, uint16_t max_packet)
Implementation of ra8_usb_host_pipe_setup().
ra8_usb_host_bulk_lim_t
Spin bound for bulk-pipe waits (covers media access latency).
@ k_ra8_usb_bulk_poll_limit
Spins per bulk stage wait.
ra8_err_t ra8_usb_host_bulk_in(ra8_usb_speed_t speed, uint8_t pipe_num, uint8_t *buf, uint16_t max_len, uint16_t *out_received)
Implementation of ra8_usb_host_bulk_in().
static ra8_err_t internal_host_bulk_rx_packet(volatile r_usb_regs_t *reg, uint8_t pipe_num, uint8_t *dst, uint16_t room, uint16_t *out_dtln, uint16_t *out_copied)
Receive one bulk packet from an armed IN pipe into dst.
static ra8_err_t internal_host_wait_pipe(volatile const r_usb_regs_t *reg, volatile const uint16_t *sts, uint8_t pipe_num)
Spin until a pipe's W0C status bit asserts, with STALL detection.
static ra8_err_t internal_host_pipe_args_ok(uint8_t pipe_num, uint8_t dev_addr, uint8_t ep_num, uint16_t max_packet)
Validate the argument set for ra8_usb_host_pipe_setup.
ra8_err_t ra8_usb_host_set_target(ra8_usb_speed_t speed, uint8_t dev_addr)
Implementation of ra8_usb_host_set_target().
void priv_host_program_devadd(volatile r_usb_regs_t *reg, uint8_t dev_addr)
Program DEVADDn.USBSPD with the connected device's link speed.
Cross-TU surface for the ra8_usb driver split.
@ k_ra8_usb_dev_addr_max
Highest DEVADDn slot (DEVADDA).
@ k_ra8_usb_devsel_shift
DCPMAXP/PIPEMAXP DEVSEL pos.
@ k_ra8_usb_pid_stall_bit
PID[1]: set for either STALL.
@ k_ra8_usb_pipemaxp_mxps
PIPEMAXP MXPS field (the USBHS instance carries 11 bits, HUM Ch 37.2.36; FS uses the low 9).
@ k_ra8_usb_max_pipe_num
PIPE1..PIPE9 + DCP at 0.
@ k_ra8_usb_dcpmaxp_mxps
DCPMAXP MXPS (max packet) field.
@ k_ra8_usb_lnst_mask
SYSSTS0.LNST line-state field.
USB Full-Speed + High-Speed controller layout for the Renesas RA8D2.
@ k_ra8_pid_buf
BUF response (transmit/receive).
@ k_ra8_pid_nak
NAK response.
@ k_ra8_fifoctr_bclr
Buffer clear.
@ k_ra8_fifoctr_dtln
Data length (write-bytes-rem).
@ k_ra8_dcpctr_bit_sqclr
Sequence toggle clear.
@ k_ra8_pipecfg_epnum_mask
Endpoint number [3:0].
USB FS / HS register window (device-mode subset).
volatile uint16_t CFIFOCTR
+0x022 Control FIFO control.
volatile uint16_t DCPMAXP
+0x05E DCP Max Packet.
volatile uint16_t PIPECTR[k_ra8_usb_pipectr_count]
+0x070 PIPE1..9 ctrl.
volatile uint16_t PIPEPERI
+0x06E Selected pipe period.
volatile uint16_t SYSSTS0
+0x004 System Status 0.
volatile uint16_t BRDYENB
+0x036 BRDY Interrupt Enable.
volatile uint16_t PIPEMAXP
+0x06C Selected pipe max packet.
volatile uint16_t BEMPSTS
+0x04A BEMP Interrupt Status.
volatile uint16_t PIPEBUF
+0x06A Selected pipe buffer.
volatile uint16_t PIPECFG
+0x068 Selected pipe config.
volatile uint16_t NRDYSTS
+0x048 NRDY Interrupt Status.
volatile uint16_t BEMPENB
+0x03A BEMP Interrupt Enable.
volatile uint16_t PIPESEL
+0x064 Pipe window select.
volatile uint16_t BRDYSTS
+0x046 BRDY Interrupt Status.