ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
usb_selftest_cdc_steps.c
Go to the documentation of this file.
1
26
28
29#include <stdint.h>
30#include <string.h>
31
32#include "ra8_board_ek_ra8d2.h"
33#include "ra8_err.h"
34#include "ra8_time.h"
35#include "ra8_usb.h"
36
37#ifndef RA8_OFF_TARGET
38
50
55typedef enum : uint32_t {
59
71
72/* -------------------------------------------------------------------------- */
73/* J-Link probes (host side) */
74/* -------------------------------------------------------------------------- */
75
77static volatile uint32_t s_dbg_phase;
79static volatile uint32_t s_dbg_rounds_ok;
81static volatile uint32_t s_dbg_pid;
83static volatile uint32_t s_dbg_mismatch = (uint32_t)k_cdc_no_mismatch;
85static volatile uint32_t s_dbg_pass_count;
86
87/* -------------------------------------------------------------------------- */
88/* Shared per-round echo pattern */
89/* -------------------------------------------------------------------------- */
90
111static void cdc_pattern_fill(uint32_t round, uint8_t* out, uint32_t len)
112{
113 for (uint32_t i = 0U; i < len; i++) {
114 const uint32_t v = (round * (uint32_t)k_cdc_pat_round_mul) + (i * (uint32_t)k_cdc_pat_idx_mul) +
115 (uint32_t)k_cdc_pat_bias;
116 out[i] = (uint8_t)(v & (uint32_t)k_cdc_byte_mask);
117 }
118}
119
120/* -------------------------------------------------------------------------- */
121/* Console helpers (SCI8 -> J-Link OB CDC) */
122/* -------------------------------------------------------------------------- */
123
142static uint8_t cdc_nibble_to_hex(uint32_t nibble)
143{
144 if (nibble < k_cdc_hex_digit_split) {
145 return (uint8_t)((uint8_t)'0' + (uint8_t)nibble);
146 }
147 return (uint8_t)((uint8_t)'A' + (uint8_t)nibble - (uint8_t)k_cdc_hex_digit_split);
148}
149
168static uint32_t cdc_str_len(const char* text)
169{
170 uint32_t len = 0U;
171 while (len < (uint32_t)k_cdc_print_cap) {
172 if (text[len] == '\0') {
173 break;
174 }
175 len++;
176 }
177 return len;
178}
179
199[[nodiscard]] static ra8_err_t cdc_sci_write(const uint8_t* data, uint32_t len)
200{
201 return ra8_board_uart_console_write(data, (size_t)len);
202}
203
222[[nodiscard]] static ra8_err_t cdc_print(const char* text)
223{
224 return cdc_sci_write((const uint8_t*)text, cdc_str_len(text));
225}
226
245[[nodiscard]] static ra8_err_t cdc_print_dec(uint32_t value)
246{
247 uint8_t scratch[k_cdc_dec_chars_u32] = {};
248 uint8_t out[k_cdc_dec_chars_u32] = {};
249 uint8_t count = 0U;
250 uint32_t v = value;
251 if (v == 0U) {
252 out[0] = (uint8_t)'0';
253 return cdc_sci_write(out, 1U);
254 }
255 while (v != 0U) {
256 if (count >= (uint8_t)k_cdc_dec_chars_u32) {
257 break;
258 }
259 scratch[count] = (uint8_t)((uint8_t)'0' + (uint8_t)(v % k_cdc_dec_radix));
260 v = v / k_cdc_dec_radix;
261 count++;
262 }
263 for (uint8_t i = 0U; i < count; i++) {
264 out[i] = scratch[count - 1U - i];
265 }
266 return cdc_sci_write(out, (uint32_t)count);
267}
268
288[[nodiscard]] static ra8_err_t cdc_print_hex(uint32_t value, uint8_t digits)
289{
290 uint8_t out[k_cdc_hex_chars_u32] = {};
291 uint8_t width = digits;
292 if (width > (uint8_t)k_cdc_hex_chars_u32) {
293 width = (uint8_t)k_cdc_hex_chars_u32;
294 }
295 for (uint8_t i = 0U; i < width; i++) {
296 const uint8_t shift = (uint8_t)((width - 1U - i) * k_cdc_nibble_bits);
297 out[i] = cdc_nibble_to_hex((value >> shift) & k_cdc_nibble_mask);
298 }
299 return cdc_sci_write(out, (uint32_t)width);
300}
301
321[[nodiscard]] static ra8_err_t cdc_print_fail(const char* what, ra8_err_t err)
322{
323 ra8_err_t e = cdc_print("ra8d2 cdc: FAIL ");
324 if (e != k_ra8_ok) {
325 return e;
326 }
327 e = cdc_print(what);
328 if (e != k_ra8_ok) {
329 return e;
330 }
331 e = cdc_print(" err=0x");
332 if (e != k_ra8_ok) {
333 return e;
334 }
335 e = cdc_print_hex((uint32_t)err, (uint8_t)k_cdc_hex_chars_u32);
336 if (e != k_ra8_ok) {
337 return e;
338 }
339 return cdc_print("\r\n");
340}
341
342/* -------------------------------------------------------------------------- */
343/* Host side: self-contained polled CDC enumerate + bulk echo */
344/* -------------------------------------------------------------------------- */
345
362
377
395[[nodiscard]] static ra8_err_t cdc_ctrl_get_dev_desc(uint8_t* desc)
396{
397 const ra8_usb_setup_t setup = {
398 .bm_request_type = (uint8_t)k_cdc_bm_std_dev_in,
399 .b_request = (uint8_t)k_cdc_breq_get_desc,
400 .w_value = (uint16_t)((uint16_t)k_cdc_desc_device << (uint16_t)k_cdc_byte_bits),
401 .w_index = 0U,
402 .w_length = (uint16_t)k_cdc_dev_desc_len,
403 };
404 uint16_t rx = 0U;
405 const ra8_err_t err =
407 if (err != k_ra8_ok) {
408 return err;
409 }
410 if (rx != (uint16_t)k_cdc_dev_desc_len) {
411 return k_ra8_err_hw_error;
412 }
413 return k_ra8_ok;
414}
415
438[[nodiscard]] static ra8_err_t cdc_enum_hunt(uint8_t* desc)
439{
441 const uint32_t t0 = ra8_time_ms();
442 for (uint32_t spin = 0U; spin < (uint32_t)k_cdc_attach_spin; spin++) {
444 break;
445 }
446 if ((ra8_time_ms() - t0) > (uint32_t)k_cdc_attach_to_ms) {
447 break;
448 }
449 }
452 for (uint8_t attempt = 0U; attempt < (uint8_t)k_cdc_enum_tries; attempt++) {
459 err = cdc_ctrl_get_dev_desc(desc);
460 if (err == k_ra8_ok) {
461 return k_ra8_ok;
462 }
463 }
464 return err;
465}
466
481[[nodiscard]] static ra8_err_t cdc_enum_set_address(void)
482{
483 const ra8_usb_setup_t setup = {
484 .bm_request_type = (uint8_t)k_cdc_bm_std_dev_out,
485 .b_request = (uint8_t)k_cdc_breq_set_addr,
486 .w_value = (uint16_t)k_cdc_dev_addr,
487 .w_index = 0U,
488 .w_length = 0U,
489 };
490 ra8_err_t err = ra8_usb_host_control_xfer(k_ra8_usb_speed_hs, &setup, nullptr, 0U, nullptr);
491 if (err != k_ra8_ok) {
492 return err;
493 }
496}
497
512[[nodiscard]] static ra8_err_t cdc_enum_set_config(void)
513{
514 const ra8_usb_setup_t setup = {
515 .bm_request_type = (uint8_t)k_cdc_bm_std_dev_out,
516 .b_request = (uint8_t)k_cdc_breq_set_config,
517 .w_value = (uint16_t)k_cdc_config_value,
518 .w_index = 0U,
519 .w_length = 0U,
520 };
521 return ra8_usb_host_control_xfer(k_ra8_usb_speed_hs, &setup, nullptr, 0U, nullptr);
522}
523
542[[nodiscard]] static ra8_err_t cdc_open_pipes(void)
543{
545 (uint8_t)k_cdc_pipe_out,
546 (uint8_t)k_cdc_dev_addr,
547 (uint8_t)k_cdc_ep_out_num,
548 false,
549 (uint16_t)k_cdc_mps);
550 if (err != k_ra8_ok) {
551 return err;
552 }
554 (uint8_t)k_cdc_pipe_in,
555 (uint8_t)k_cdc_dev_addr,
556 (uint8_t)k_cdc_ep_in_num,
557 true,
558 (uint16_t)k_cdc_mps);
559}
560
581[[nodiscard]] static ra8_err_t cdc_enumerate(uint32_t* out_pid)
582{
583 uint8_t desc[k_cdc_dev_desc_len] = {};
584 ra8_err_t err = cdc_enum_hunt(desc);
585 if (err != k_ra8_ok) {
586 (void)cdc_print_fail("enumerate", err);
587 return err;
588 }
589 *out_pid = (uint32_t)desc[k_cdc_off_dev_pid] |
590 ((uint32_t)desc[(uint32_t)k_cdc_off_dev_pid + 1U] << (uint32_t)k_cdc_byte_bits);
591 err = cdc_enum_set_address();
592 if (err != k_ra8_ok) {
593 (void)cdc_print_fail("set_address", err);
594 return err;
595 }
596 err = cdc_enum_set_config();
597 if (err != k_ra8_ok) {
598 (void)cdc_print_fail("set_config", err);
599 return err;
600 }
601 err = cdc_open_pipes();
602 if (err != k_ra8_ok) {
603 (void)cdc_print_fail("open_pipes", err);
604 }
605 return err;
606}
607
624[[nodiscard]] static ra8_err_t cdc_print_enum(uint32_t pid)
625{
626 ra8_err_t err = cdc_print("ra8d2 cdc: enumerated pid=0x");
627 if (err != k_ra8_ok) {
628 return err;
629 }
630 err = cdc_print_hex(pid, (uint8_t)k_cdc_hex_chars_u16);
631 if (err != k_ra8_ok) {
632 return err;
633 }
634 return cdc_print("\r\n");
635}
636
651[[nodiscard]] static ra8_err_t cdc_print_pass(void)
652{
653 ra8_err_t err = cdc_print("ra8d2 cdc: ");
654 if (err != k_ra8_ok) {
655 return err;
656 }
657 err = cdc_print_dec((uint32_t)k_cdc_rounds);
658 if (err != k_ra8_ok) {
659 return err;
660 }
661 return cdc_print(" rounds echoed -- USB SELFTEST CDC-ECHO PASS\r\n");
662}
663
687[[nodiscard]] static ra8_err_t cdc_echo_round(uint32_t round)
688{
689 static uint8_t s_tx[k_cdc_payload] = {};
690 static uint8_t s_rx[k_cdc_echo_buf] = {};
691 cdc_pattern_fill(round, s_tx, (uint32_t)k_cdc_payload);
693 (uint8_t)k_cdc_pipe_out,
694 s_tx,
695 (uint16_t)k_cdc_payload);
696 if (err != k_ra8_ok) {
697 (void)cdc_print_fail("bulk_out", err);
698 return err;
699 }
700 uint16_t rx = 0U;
702 (uint8_t)k_cdc_pipe_in,
703 s_rx,
704 (uint16_t)k_cdc_echo_buf,
705 &rx);
706 if (err != k_ra8_ok) {
707 (void)cdc_print_fail("bulk_in", err);
708 return err;
709 }
710 if (rx != (uint16_t)k_cdc_payload) {
711 s_dbg_mismatch = round;
712 (void)cdc_print_fail("echo length", k_ra8_err_invalid_size);
714 }
715 if (memcmp(s_rx, s_tx, (size_t)k_cdc_payload) != 0) {
716 s_dbg_mismatch = round;
717 (void)cdc_print_fail("echo data mismatch", k_ra8_err_invalid_state);
719 }
720 return k_ra8_ok;
721}
722
740[[nodiscard]] static ra8_err_t cdc_host_pass(void)
741{
742 s_dbg_phase = (uint32_t)k_cdc_phase_init;
743 ra8_err_t err = cdc_print("ra8d2 cdc: host up on USB-HS, probing the loop...\r\n");
744 if (err != k_ra8_ok) {
745 return err;
746 }
748 if (err != k_ra8_ok) {
749 (void)cdc_print_fail("host init", err);
750 return err;
751 }
752
753 s_dbg_phase = (uint32_t)k_cdc_phase_enum;
754 uint32_t pid = 0U;
755 err = cdc_enumerate(&pid);
756 if (err != k_ra8_ok) {
758 return err;
759 }
760 s_dbg_pid = pid;
761 err = cdc_print_enum(pid);
762 if (err != k_ra8_ok) {
763 return err;
764 }
765
767 s_dbg_rounds_ok = 0U;
768 for (uint32_t r = 0U; r < (uint32_t)k_cdc_rounds; r++) {
769 err = cdc_echo_round(r);
770 if (err != k_ra8_ok) {
772 return err;
773 }
775 }
776
777 s_dbg_phase = (uint32_t)k_cdc_phase_pass;
779 err = cdc_print_pass();
780 if (err != k_ra8_ok) {
781 return err;
782 }
784 return k_ra8_ok;
785}
786
788{
789 (void)arg;
790
792 for (;;) {
793 const ra8_err_t err = cdc_host_pass();
794 if (err == k_ra8_ok) {
795 break;
796 }
798 }
799 while (1) {
801 }
802}
803
804#endif /* !RA8_OFF_TARGET */
static volatile uint32_t s_dbg_pid
Device-reported product id captured at enumeration.
Definition main.c:208
static volatile uint32_t s_dbg_rounds_ok
Reports the host confirmed pattern-equal (expect k_hid_rounds).
Definition main.c:172
Board-support layer for the Renesas EK-RA8D2 v1 evaluation kit.
ra8_err_t ra8_board_led_on(ra8_board_led_id_t led)
Drive led HIGH (light it).
@ k_ra8_board_led2
LED2, GREEN, P303 (jumper E26).
ra8_err_t ra8_board_uart_console_write(const uint8_t *data, size_t len)
Polled blocking write to the J-Link OB VCOM console.
Error Code Definitions for ra8-firmware.
@ 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
@ k_ra8_err_invalid_size
Invalid size parameter (too large, too small, or misaligned).
Definition ra8_err.h:167
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
int memcmp(const void *a, const void *b, size_t n)
Compare bytes in two memory areas.
SysTick-based tick counter, delay and timestamp helpers.
void ra8_delay_ms(uint32_t ms)
Busy-wait for at least ms milliseconds.
Definition ra8_time.c:129
uint32_t ra8_time_ms(void)
Get the current 1 kHz tick count.
Definition ra8_time.c:108
Native USB controller driver public API (device + host modes).
@ k_ra8_usb_speed_hs
High-Speed controller (USBHS @ 0x40351000).
ra8_err_t ra8_usb_host_bulk_out(ra8_usb_speed_t speed, uint8_t pipe_num, const uint8_t *data, uint16_t len)
Transmit one bulk packet to the device and wait for the ACK.
ra8_err_t ra8_usb_host_bus_reset(ra8_usb_speed_t speed, bool assert_reset)
Drive (or release) the bus reset line.
uint16_t ra8_usb_host_line_state(ra8_usb_speed_t speed)
Read the host port's D+/D- line state (SYSSTS0.LNST).
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)
Configure a controller pipe against an attached device's bulk endpoint.
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)
Receive a bulk transfer from the device into buf.
ra8_err_t ra8_usb_host_init(ra8_usb_speed_t speed)
Bring up a USB controller in HOST mode.
ra8_err_t ra8_usb_host_deinit(ra8_usb_speed_t speed)
Tear down a host-mode controller and drop its MSTP reference.
ra8_err_t ra8_usb_host_control_xfer(ra8_usb_speed_t speed, const ra8_usb_setup_t *setup, uint8_t *data, uint16_t data_len, uint16_t *out_received)
Run a complete host control transfer (SETUP, optional DATA, STATUS).
ra8_err_t ra8_usb_host_set_uact(ra8_usb_speed_t speed, bool enable)
Enable / disable SOF (Start-of-Frame) generation on the bus.
ra8_err_t ra8_usb_host_set_target(ra8_usb_speed_t speed, uint8_t dev_addr)
Retarget the host's default control pipe at a device address.
#define tx_thread_sleep
unsigned long ULONG
ThreadX-compatible unsigned long (host stub).
Decoded 8-byte USB SETUP packet.
static ra8_err_t cdc_print_pass(void)
Print "N rounds echoed -- USB SELFTEST CDC-ECHO PASS".
static ra8_err_t cdc_host_pass(void)
One full host-side pass: enumerate, then run the echo rounds.
static ra8_err_t cdc_ctrl_get_dev_desc(uint8_t *desc)
GET_DESCRIPTOR(DEVICE) over the polled control engine.
static ra8_err_t cdc_enum_set_address(void)
SET_ADDRESS to k_cdc_dev_addr, then retarget the DCP.
static uint8_t cdc_nibble_to_hex(uint32_t nibble)
Format one nibble (0..15) into an uppercase hex character.
static ra8_err_t cdc_print_enum(uint32_t pid)
Print "enumerated pid=0xNNNN" for the looped device.
static uint32_t cdc_str_len(const char *text)
Bounded ASCII string length (cap k_cdc_print_cap).
static ra8_err_t cdc_sci_write(const uint8_t *data, uint32_t len)
Push a literal block over SCI8 polled.
static ra8_err_t cdc_enum_set_config(void)
SET_CONFIGURATION(::k_cdc_config_value) on the addressed device.
cdc_hex_t
Hex/decimal text-formatter sizing constants.
@ k_cdc_hex_chars_u16
16-bit value -> "ABCD".
@ k_cdc_hex_chars_u32
32-bit value -> "ABCDEF01".
@ k_cdc_hex_digit_split
Threshold between '0-9'/'A-F'.
@ k_cdc_dec_chars_u32
Max digits for a 32-bit count.
@ k_cdc_nibble_bits
Bits per hex nibble.
static ra8_err_t cdc_print_dec(uint32_t value)
Print a uint32_t as ASCII decimal.
cdc_phase_t
J-Link probe values marking host-ladder progress.
@ k_cdc_phase_pass
All rounds echoed back OK.
@ k_cdc_phase_enum
Enumerating.
@ k_cdc_phase_verify
Running echo rounds.
@ k_cdc_phase_boot
Host thread not started.
@ k_cdc_phase_init
Host controller init.
VOID cdc_host_worker(ULONG arg)
Host-side worker: retry the full pass until it succeeds.
static ra8_err_t cdc_enum_hunt(uint8_t *desc)
Wait for the device to attach, then bus-reset + read its descriptor.
cdc_enum_tune_t
Timing / retry tunables for the polled enumeration ladder.
@ k_cdc_addr_settle_ms
Post-SET_ADDRESS recovery.
@ k_cdc_attach_spin
Attach spin cap (frozen-tick guard).
@ k_cdc_attach_to_ms
Wait for the D+ pull-up.
@ k_cdc_enum_tries
Reset+probe attempts.
@ k_cdc_reset_hold_ms
USB bus-reset hold (>=10 ms).
@ k_cdc_vbus_settle_ms
VBUS settle before probing.
@ k_cdc_debounce_ms
Post-attach debounce (>=100 ms).
@ k_cdc_recovery_ms
Post-reset recovery (TRSTRCY).
static ra8_err_t cdc_echo_round(uint32_t round)
One echo round: bulk-OUT a pattern, bulk-IN the echo, compare.
cdc_usb_req_t
Standard chapter-9 request / descriptor constants for the host.
@ k_cdc_breq_set_addr
SET_ADDRESS.
@ k_cdc_config_value
bConfigurationValue to select.
@ k_cdc_bm_std_dev_in
bmRequestType: Std | Device | In.
@ k_cdc_breq_get_desc
GET_DESCRIPTOR.
@ k_cdc_desc_device
DEVICE descriptor type.
@ k_cdc_bm_std_dev_out
bmRequestType: Std | Device | Out.
@ k_cdc_byte_bits
Bits per byte.
@ k_cdc_dev_desc_len
DEVICE descriptor length.
@ k_cdc_off_dev_pid
idProduct LSB byte offset.
@ k_cdc_breq_set_config
SET_CONFIGURATION.
static ra8_err_t cdc_print_fail(const char *what, ra8_err_t err)
Print "FAIL <what> err=0xNNNNNNNN" on its own line.
cdc_mask_t
Bit-mask constants used by the text formatters.
@ k_cdc_nibble_mask
4-bit nibble mask.
@ k_cdc_dec_radix
Base for decimal conversion.
static ra8_err_t cdc_print_hex(uint32_t value, uint8_t digits)
Print a value as fixed-width uppercase hex.
static void cdc_pattern_fill(uint32_t round, uint8_t *out, uint32_t len)
Fill an echo payload with this round's deterministic bytes.
static ra8_err_t cdc_enumerate(uint32_t *out_pid)
Run the full enumeration ladder and open the bulk pipes.
static ra8_err_t cdc_open_pipes(void)
Open the host bulk pipes for the device's CDC data endpoints.
static ra8_err_t cdc_print(const char *text)
Print a NUL-terminated ASCII string over the console.
Host-side self-test ladder + console helpers shared with main.c.
@ k_cdc_rounds
Echo rounds the host runs.
@ k_cdc_pipe_in
Host pipe for the device bulk-IN.
@ k_cdc_echo_buf
One-MPS scratch buffer (bytes).
@ k_cdc_ep_out_num
Device bulk-OUT endpoint number.
@ k_cdc_no_mismatch
Probe: no mismatch.
@ k_cdc_pat_idx_mul
Per-index pattern multiplier.
@ k_cdc_payload
Bytes per echo round (sub-MPS).
@ k_cdc_byte_mask
Byte mask.
@ k_cdc_pat_bias
Pattern constant bias.
@ k_cdc_ep_in_num
Device bulk-IN endpoint number.
@ k_cdc_pipe_out
Host pipe for the device bulk-OUT.
@ k_cdc_pat_round_mul
Per-round pattern multiplier.
@ k_cdc_mps
Bulk endpoint wMaxPacketSize (FS).
@ k_cdc_dev_addr
Address the host assigns.
@ k_cdc_retry_ticks
Pause between ladder retries.
@ k_cdc_print_cap
Bound for console-string scans.
@ k_cdc_boot_wait_ticks
Host start delay (1 ms ticks).
@ k_cdc_idle_ticks
Parked-loop back-off (ticks).
static volatile uint32_t s_dbg_phase
Host-ladder phase marker (wlun_phase_t).
static volatile uint32_t s_dbg_pass_count
Completed full passes (sticky success counter).
static volatile uint32_t s_dbg_mismatch
First mismatching sector, or k_wlun_no_mismatch.