ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
usb_selftest_ospi_rw_steps.c
Go to the documentation of this file.
1
34
36
37#include <stdint.h>
38#include <string.h>
39
40#include "ra8_board_ek_ra8d2.h"
41#include "ra8_err.h"
42#include "ra8_usb_hmsc.h"
43
44#ifndef RA8_OFF_TARGET
45#include "tx_api.h"
46#include "ux_api.h"
47
48/* -------------------------------------------------------------------------- */
49/* J-Link probes (host-ladder side) */
50/* -------------------------------------------------------------------------- */
51
53static volatile uint32_t s_dbg_phase;
55static volatile uint32_t s_dbg_luns_ok;
57static volatile uint32_t s_dbg_max_lun;
59static volatile uint32_t s_dbg_mismatch = (uint32_t)k_ospirw_no_mismatch;
61static volatile uint32_t s_dbg_pass_count;
62
63/* -------------------------------------------------------------------------- */
64/* Shared per-(LUN,LBA) pattern */
65/* -------------------------------------------------------------------------- */
66
87static void ospirw_pattern_fill(uint32_t lun, uint32_t lba, UCHAR* out)
88{
89 for (uint32_t i = 0U; i < (uint32_t)k_ospirw_block_size; i++) {
90 const uint32_t v = (lun * (uint32_t)k_ospirw_pat_lun_mul) +
91 (lba * (uint32_t)k_ospirw_pat_lba_mul) + i + (uint32_t)k_ospirw_pat_bias;
92 out[i] = (UCHAR)(v & (uint32_t)k_ospirw_byte_mask);
93 }
94}
95
96/* -------------------------------------------------------------------------- */
97/* Console helpers (SCI8 -> J-Link OB CDC) */
98/* -------------------------------------------------------------------------- */
99
118static uint8_t ospirw_nibble_to_hex(uint32_t nibble)
119{
120 if (nibble < k_ospirw_hex_digit_split) {
121 return (uint8_t)((uint8_t)'0' + (uint8_t)nibble);
122 }
123 return (uint8_t)((uint8_t)'A' + (uint8_t)nibble - (uint8_t)k_ospirw_hex_digit_split);
124}
125
144static uint32_t ospirw_str_len(const char* text)
145{
146 uint32_t len = 0U;
147 while (len < (uint32_t)k_ospirw_print_cap) {
148 if (text[len] == '\0') {
149 break;
150 }
151 len++;
152 }
153 return len;
154}
155
175[[nodiscard]] static ra8_err_t ospirw_sci_write(const uint8_t* data, uint32_t len)
176{
177 return ra8_board_uart_console_write(data, (size_t)len);
178}
179
198[[nodiscard]] static ra8_err_t ospirw_print(const char* text)
199{
200 return ospirw_sci_write((const uint8_t*)text, ospirw_str_len(text));
201}
202
221[[nodiscard]] static ra8_err_t ospirw_print_dec(uint32_t value)
222{
223 uint8_t scratch[k_ospirw_dec_chars_u32] = {};
224 uint8_t out[k_ospirw_dec_chars_u32] = {};
225 uint8_t count = 0U;
226 uint32_t v = value;
227 if (v == 0U) {
228 out[0] = (uint8_t)'0';
229 return ospirw_sci_write(out, 1U);
230 }
231 while (v != 0U) {
232 if (count >= (uint8_t)k_ospirw_dec_chars_u32) {
233 break;
234 }
235 scratch[count] = (uint8_t)((uint8_t)'0' + (uint8_t)(v % k_ospirw_dec_radix));
236 v = v / k_ospirw_dec_radix;
237 count++;
238 }
239 for (uint8_t i = 0U; i < count; i++) {
240 out[i] = scratch[count - 1U - i];
241 }
242 return ospirw_sci_write(out, (uint32_t)count);
243}
244
264[[nodiscard]] static ra8_err_t ospirw_print_hex(uint32_t value, uint8_t digits)
265{
266 uint8_t out[k_ospirw_hex_chars_u32] = {};
267 uint8_t width = digits;
268 if (width > (uint8_t)k_ospirw_hex_chars_u32) {
269 width = (uint8_t)k_ospirw_hex_chars_u32;
270 }
271 for (uint8_t i = 0U; i < width; i++) {
272 const uint8_t shift = (uint8_t)((width - 1U - i) * k_ospirw_nibble_bits);
273 out[i] = ospirw_nibble_to_hex((value >> shift) & k_ospirw_nibble_mask);
274 }
275 return ospirw_sci_write(out, (uint32_t)width);
276}
277
297[[nodiscard]] static ra8_err_t ospirw_print_fail(const char* what, ra8_err_t err)
298{
299 ra8_err_t e = ospirw_print("ra8d2 ospirw: FAIL ");
300 if (e != k_ra8_ok) {
301 return e;
302 }
303 e = ospirw_print(what);
304 if (e != k_ra8_ok) {
305 return e;
306 }
307 e = ospirw_print(" err=0x");
308 if (e != k_ra8_ok) {
309 return e;
310 }
311 e = ospirw_print_hex((uint32_t)err, (uint8_t)k_ospirw_hex_chars_u32);
312 if (e != k_ra8_ok) {
313 return e;
314 }
315 return ospirw_print("\r\n");
316}
317
318/* -------------------------------------------------------------------------- */
319/* Host side: ra8_usb_hmsc enumerate + WRITE(10) then read-verify */
320/* -------------------------------------------------------------------------- */
321
344[[nodiscard]] static ra8_err_t ospirw_write_disk(uint32_t lun)
345{
346 static uint8_t s_wbuf[k_ospirw_burst_bytes] = {};
347 for (uint32_t blk = 0U; blk < (uint32_t)k_ospirw_sectors;
348 blk += (uint32_t)k_ospirw_burst_blocks) {
349 for (uint32_t s = 0U; s < (uint32_t)k_ospirw_burst_blocks; s++) {
350 ospirw_pattern_fill(lun, blk + s, &s_wbuf[s * (uint32_t)k_ospirw_block_size]);
351 }
352 const ra8_err_t err =
353 ra8_usb_hmsc_write10((uint8_t)lun, blk, (uint16_t)k_ospirw_burst_blocks, s_wbuf);
354 if (err != k_ra8_ok) {
355 (void)ospirw_print_fail("WRITE(10)", err);
356 return err;
357 }
358 }
359 return k_ra8_ok;
360}
361
384[[nodiscard]] static ra8_err_t ospirw_verify_one(uint32_t lun)
385{
386 static uint8_t s_burst[k_ospirw_burst_bytes] = {};
387 static uint8_t s_expect[k_ospirw_block_size] = {};
388
389 uint32_t block_count = 0U;
390 uint32_t block_size = 0U;
391 ra8_err_t err = ra8_usb_hmsc_read_capacity((uint8_t)lun, &block_count, &block_size);
392 if (err != k_ra8_ok) {
393 (void)ospirw_print_fail("read_capacity", err);
394 return err;
395 }
396 if (block_count != (uint32_t)k_ospirw_sectors) {
397 (void)ospirw_print_fail("capacity mismatch", k_ra8_err_invalid_size);
399 }
400 for (uint32_t blk = 0U; blk < (uint32_t)k_ospirw_sectors;
401 blk += (uint32_t)k_ospirw_burst_blocks) {
402 err = ra8_usb_hmsc_read10((uint8_t)lun, blk, (uint16_t)k_ospirw_burst_blocks, s_burst);
403 if (err != k_ra8_ok) {
404 (void)ospirw_print_fail("READ(10)", err);
405 return err;
406 }
407 for (uint32_t s = 0U; s < (uint32_t)k_ospirw_burst_blocks; s++) {
408 ospirw_pattern_fill(lun, blk + s, s_expect);
409 const uint32_t boff = s * (uint32_t)k_ospirw_block_size;
410 if (memcmp(&s_burst[boff], s_expect, (size_t)k_ospirw_block_size) != 0) {
411 s_dbg_mismatch = (lun << (uint32_t)k_ospirw_mismatch_lun_shift) | (blk + s);
412 (void)ospirw_print_fail("LUN data mismatch", k_ra8_err_invalid_state);
414 }
415 }
416 }
417 return k_ra8_ok;
418}
419
436[[nodiscard]] static ra8_err_t ospirw_print_lun_ok(uint32_t lun)
437{
438 ra8_err_t err = ospirw_print("ra8d2 ospirw: LUN ");
439 if (err != k_ra8_ok) {
440 return err;
441 }
442 err = ospirw_print_dec(lun);
443 if (err != k_ra8_ok) {
444 return err;
445 }
446 return ospirw_print(" OK (64 sectors, write+read verified)\r\n");
447}
448
471{
473 ra8_err_t err = ra8_usb_hmsc_enumerate(device);
474 if (err != k_ra8_ok) {
475 (void)ospirw_print_fail("enumerate", err);
476 (void)ra8_usb_hmsc_close();
477 return err;
478 }
479 s_dbg_max_lun = (uint32_t)device->max_lun;
480 err = ospirw_print("ra8d2 ospirw: enumerated pid=0x");
481 if (err != k_ra8_ok) {
482 return err;
483 }
484 err = ospirw_print_hex((uint32_t)device->product_id, (uint8_t)k_ospirw_hex_chars_u16);
485 if (err != k_ra8_ok) {
486 return err;
487 }
488 err = ospirw_print(", GET_MAX_LUN=");
489 if (err != k_ra8_ok) {
490 return err;
491 }
493 if (err != k_ra8_ok) {
494 return err;
495 }
496 return ospirw_print("\r\n");
497}
498
516[[nodiscard]] static ra8_err_t ospirw_host_pass(void)
517{
519 ra8_err_t err = ospirw_print("ra8d2 ospirw: host up on USB-HS, probing the loop...\r\n");
520 if (err != k_ra8_ok) {
521 return err;
522 }
524 if (err != k_ra8_ok) {
525 (void)ospirw_print_fail("host init", err);
526 return err;
527 }
528
529 ra8_usb_hmsc_device_t device = {};
530 err = ospirw_host_enumerate(&device);
531 if (err != k_ra8_ok) {
532 return err;
533 }
534
536 s_dbg_luns_ok = 0U;
537 for (uint32_t lun = 0U; lun < (uint32_t)k_ospirw_count; lun++) {
538 err = ospirw_write_disk(lun);
539 if (err != k_ra8_ok) {
540 (void)ra8_usb_hmsc_close();
541 return err;
542 }
543 err = ospirw_verify_one(lun);
544 if (err != k_ra8_ok) {
545 (void)ra8_usb_hmsc_close();
546 return err;
547 }
549 err = ospirw_print_lun_ok(lun);
550 if (err != k_ra8_ok) {
551 return err;
552 }
553 }
554
557 err = ospirw_print("ra8d2 ospirw: USB SELFTEST WRITABLE-OSPI PASS\r\n");
558 if (err != k_ra8_ok) {
559 return err;
560 }
562 return k_ra8_ok;
563}
564
566{
567 (void)arg;
568
570 for (;;) {
571 const ra8_err_t err = ospirw_host_pass();
572 if (err == k_ra8_ok) {
573 break;
574 }
576 }
577 while (1) {
579 }
580}
581
582#endif /* !RA8_OFF_TARGET */
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_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ 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.
@ k_ra8_usb_speed_hs
High-Speed controller (USBHS @ 0x40351000).
Native USB host-side MSC (Mass Storage Class) class layer.
ra8_err_t ra8_usb_hmsc_read_capacity(uint8_t target_lun, uint32_t *block_count, uint32_t *block_size)
Issue a SCSI READ CAPACITY(10) (opcode 0x25) over BBB.
ra8_err_t ra8_usb_hmsc_read10(uint8_t target_lun, uint32_t lba, uint16_t block_count, uint8_t *out_buf)
Issue a SCSI READ(10) (opcode 0x28) over BBB.
ra8_err_t ra8_usb_hmsc_enumerate(ra8_usb_hmsc_device_t *out_device)
Enumerate the attached MSC device end to end (polled).
ra8_err_t ra8_usb_hmsc_close(void)
Tear down the host-MSC driver and release the controller.
ra8_err_t ra8_usb_hmsc_init(ra8_usb_speed_t speed)
Bring up the host-MSC driver on a chosen USB controller.
ra8_err_t ra8_usb_hmsc_write10(uint8_t target_lun, uint32_t lba, uint16_t block_count, const uint8_t *in_buf)
Issue a SCSI WRITE(10) (opcode 0x2A) over BBB.
#define tx_thread_sleep
unsigned long ULONG
ThreadX-compatible unsigned long (host stub).
Snapshot of the attached MSC device, passed to the attach callback.
uint8_t max_lun
Get-Max-LUN response (0..15).
uint16_t product_id
idProduct from device descriptor.
static uint8_t ospirw_nibble_to_hex(uint32_t nibble)
Format one nibble (0..15) into an uppercase hex character.
static ra8_err_t ospirw_print_lun_ok(uint32_t lun)
Print "LUN n OK" for the verified writable unit.
static ra8_err_t ospirw_print_fail(const char *what, ra8_err_t err)
Print "FAIL <what> err=0xNNNNNNNN" on its own line.
static ra8_err_t ospirw_host_pass(void)
One full host-side pass: enumerate, WRITE(10) then verify.
static ra8_err_t ospirw_print_hex(uint32_t value, uint8_t digits)
Print a value as fixed-width uppercase hex.
static uint32_t ospirw_str_len(const char *text)
Bounded ASCII string length (cap k_ospirw_print_cap).
static ra8_err_t ospirw_print_dec(uint32_t value)
Print a uint32_t as ASCII decimal.
static ra8_err_t ospirw_host_enumerate(ra8_usb_hmsc_device_t *device)
Enumerate the looped device and print its PID + GET_MAX_LUN.
static void ospirw_pattern_fill(uint32_t lun, uint32_t lba, UCHAR *out)
Fill one 512-byte sector with this LUN/LBA's deterministic bytes.
VOID ospirw_host_worker(ULONG arg)
Host-side worker: retry the full pass until it succeeds.
static ra8_err_t ospirw_sci_write(const uint8_t *data, uint32_t len)
Push a literal block over the BSP UART console (SCI8) polled.
static ra8_err_t ospirw_verify_one(uint32_t lun)
Read + verify one LUN's full sector range against its pattern.
static ra8_err_t ospirw_print(const char *text)
Print a NUL-terminated ASCII string over the console.
static ra8_err_t ospirw_write_disk(uint32_t lun)
WRITE(10) the per-LBA pattern across the whole OSPI window.
Shared tunables + host-side worker seam for the writable-OSPI self-loop.
@ k_ospirw_idle_ticks
Parked-loop back-off (ticks).
@ k_ospirw_retry_ticks
Pause between ladder retries.
@ k_ospirw_boot_wait_ticks
Host start delay (1 ms ticks).
@ k_ospirw_print_cap
Bound for console-string scans.
@ k_ospirw_nibble_mask
4-bit nibble mask.
@ k_ospirw_dec_radix
Base for decimal conversion.
@ k_ospirw_phase_pass
All LUNs verified.
@ k_ospirw_phase_init
ra8_usb_hmsc_init issued.
@ k_ospirw_phase_verify
Reading + checking LUNs.
@ k_ospirw_phase_enum
Enumerating.
@ k_ospirw_burst_bytes
8 x 512 B burst buffer.
@ k_ospirw_no_mismatch
Probe: no mismatch.
@ k_ospirw_byte_mask
Byte mask.
@ k_ospirw_pat_lun_mul
Per-LUN pattern multiplier.
@ k_ospirw_pat_bias
Pattern constant bias.
@ k_ospirw_mismatch_lun_shift
s_dbg_mismatch: LUN in bits 31:24.
@ k_ospirw_block_size
SCSI logical block size.
@ k_ospirw_burst_blocks
Blocks per READ(10) burst.
@ k_ospirw_count
Logical units exposed (single writable).
@ k_ospirw_sectors
512-byte sectors (OSPI window = 32 KiB).
@ k_ospirw_pat_lba_mul
Per-LBA pattern multiplier.
@ k_ospirw_dec_chars_u32
Max digits for a 32-bit count.
@ k_ospirw_nibble_bits
Bits per hex nibble.
@ k_ospirw_hex_chars_u16
16-bit value -> "ABCD".
@ k_ospirw_hex_digit_split
Threshold between '0-9'/'A-F'.
@ k_ospirw_hex_chars_u32
32-bit value -> "ABCDEF01".
static volatile uint32_t s_dbg_phase
Host-ladder phase marker (wlun_phase_t).
static volatile uint32_t s_dbg_luns_ok
Sectors that read back correctly after the write pass.
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.
static volatile uint32_t s_dbg_max_lun
Device-reported GET_MAX_LUN value (expect 0, single LUN).