ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
usb_selftest_mlun_steps.c
Go to the documentation of this file.
1
30
32
33#include <stdint.h>
34#include <string.h>
35
36#include "ra8_board_ek_ra8d2.h"
37#include "ra8_err.h"
38#include "ra8_usb_hmsc.h"
39
40#ifndef RA8_OFF_TARGET
41
42#include "tx_api.h"
43#include "ux_api.h"
44#include "ux_device_class_storage.h"
45
46/* -------------------------------------------------------------------------- */
47/* J-Link probes (host-ladder side) */
48/* -------------------------------------------------------------------------- */
49
51static volatile uint32_t s_dbg_phase;
53static volatile uint32_t s_dbg_luns_ok;
55static volatile uint32_t s_dbg_max_lun;
57static volatile uint32_t s_dbg_mismatch = (uint32_t)k_mlun_no_mismatch;
59static volatile uint32_t s_dbg_pass_count;
60
61/* -------------------------------------------------------------------------- */
62/* Shared per-(LUN,LBA) pattern */
63/* -------------------------------------------------------------------------- */
64
65void mlun_pattern_fill(uint32_t lun, uint32_t lba, UCHAR* out)
66{
67 for (uint32_t i = 0U; i < (uint32_t)k_mlun_block_size; i++) {
68 const uint32_t v = (lun * (uint32_t)k_mlun_pat_lun_mul) + (lba * (uint32_t)k_mlun_pat_lba_mul) +
69 i + (uint32_t)k_mlun_pat_bias;
70 out[i] = (UCHAR)(v & (uint32_t)k_mlun_byte_mask);
71 }
72}
73
74/* -------------------------------------------------------------------------- */
75/* Console helpers (SCI8 -> J-Link OB CDC) */
76/* -------------------------------------------------------------------------- */
77
96static uint8_t mlun_nibble_to_hex(uint32_t nibble)
97{
98 if (nibble < k_mlun_hex_digit_split) {
99 return (uint8_t)((uint8_t)'0' + (uint8_t)nibble);
100 }
101 return (uint8_t)((uint8_t)'A' + (uint8_t)nibble - (uint8_t)k_mlun_hex_digit_split);
102}
103
122static uint32_t mlun_str_len(const char* text)
123{
124 uint32_t len = 0U;
125 while (len < (uint32_t)k_mlun_print_cap) {
126 if (text[len] == '\0') {
127 break;
128 }
129 len++;
130 }
131 return len;
132}
133
153[[nodiscard]] static ra8_err_t mlun_sci_write(const uint8_t* data, uint32_t len)
154{
155 return ra8_board_uart_console_write(data, (size_t)len);
156}
157
176[[nodiscard]] static ra8_err_t mlun_print(const char* text)
177{
178 return mlun_sci_write((const uint8_t*)text, mlun_str_len(text));
179}
180
199[[nodiscard]] static ra8_err_t mlun_print_dec(uint32_t value)
200{
201 uint8_t scratch[k_mlun_dec_chars_u32] = {};
202 uint8_t out[k_mlun_dec_chars_u32] = {};
203 uint8_t count = 0U;
204 uint32_t v = value;
205 if (v == 0U) {
206 out[0] = (uint8_t)'0';
207 return mlun_sci_write(out, 1U);
208 }
209 while (v != 0U) {
210 if (count >= (uint8_t)k_mlun_dec_chars_u32) {
211 break;
212 }
213 scratch[count] = (uint8_t)((uint8_t)'0' + (uint8_t)(v % k_mlun_dec_radix));
214 v = v / k_mlun_dec_radix;
215 count++;
216 }
217 for (uint8_t i = 0U; i < count; i++) {
218 out[i] = scratch[count - 1U - i];
219 }
220 return mlun_sci_write(out, (uint32_t)count);
221}
222
242[[nodiscard]] static ra8_err_t mlun_print_hex(uint32_t value, uint8_t digits)
243{
244 uint8_t out[k_mlun_hex_chars_u32] = {};
245 uint8_t width = digits;
246 if (width > (uint8_t)k_mlun_hex_chars_u32) {
247 width = (uint8_t)k_mlun_hex_chars_u32;
248 }
249 for (uint8_t i = 0U; i < width; i++) {
250 const uint8_t shift = (uint8_t)((width - 1U - i) * k_mlun_nibble_bits);
251 out[i] = mlun_nibble_to_hex((value >> shift) & k_mlun_nibble_mask);
252 }
253 return mlun_sci_write(out, (uint32_t)width);
254}
255
275[[nodiscard]] static ra8_err_t mlun_print_fail(const char* what, ra8_err_t err)
276{
277 ra8_err_t e = mlun_print("ra8d2 mlun: FAIL ");
278 if (e != k_ra8_ok) {
279 return e;
280 }
281 e = mlun_print(what);
282 if (e != k_ra8_ok) {
283 return e;
284 }
285 e = mlun_print(" err=0x");
286 if (e != k_ra8_ok) {
287 return e;
288 }
289 e = mlun_print_hex((uint32_t)err, (uint8_t)k_mlun_hex_chars_u32);
290 if (e != k_ra8_ok) {
291 return e;
292 }
293 return mlun_print("\r\n");
294}
295
296/* -------------------------------------------------------------------------- */
297/* Host side: ra8_usb_hmsc enumerate + per-LUN read/verify */
298/* -------------------------------------------------------------------------- */
299
322[[nodiscard]] static ra8_err_t mlun_verify_one(uint32_t lun)
323{
324 static uint8_t s_burst[k_mlun_burst_bytes] = {};
325 static uint8_t s_expect[k_mlun_block_size] = {};
326
327 uint32_t block_count = 0U;
328 uint32_t block_size = 0U;
329 ra8_err_t err = ra8_usb_hmsc_read_capacity((uint8_t)lun, &block_count, &block_size);
330 if (err != k_ra8_ok) {
331 (void)mlun_print_fail("read_capacity", err);
332 return err;
333 }
334 if (block_count != (uint32_t)k_mlun_sectors) {
335 (void)mlun_print_fail("capacity mismatch", k_ra8_err_invalid_size);
337 }
338 for (uint32_t blk = 0U; blk < (uint32_t)k_mlun_sectors; blk += (uint32_t)k_mlun_burst_blocks) {
339 err = ra8_usb_hmsc_read10((uint8_t)lun, blk, (uint16_t)k_mlun_burst_blocks, s_burst);
340 if (err != k_ra8_ok) {
341 (void)mlun_print_fail("READ(10)", err);
342 return err;
343 }
344 for (uint32_t s = 0U; s < (uint32_t)k_mlun_burst_blocks; s++) {
345 mlun_pattern_fill(lun, blk + s, s_expect);
346 const uint32_t boff = s * (uint32_t)k_mlun_block_size;
347 if (memcmp(&s_burst[boff], s_expect, (size_t)k_mlun_block_size) != 0) {
348 s_dbg_mismatch = (lun << (uint32_t)k_mlun_mismatch_lun_shift) | (blk + s);
349 (void)mlun_print_fail("LUN data mismatch", k_ra8_err_invalid_state);
351 }
352 }
353 }
354 return k_ra8_ok;
355}
356
373[[nodiscard]] static ra8_err_t mlun_print_lun_ok(uint32_t lun)
374{
375 ra8_err_t err = mlun_print("ra8d2 mlun: LUN ");
376 if (err != k_ra8_ok) {
377 return err;
378 }
379 err = mlun_print_dec(lun);
380 if (err != k_ra8_ok) {
381 return err;
382 }
383 return mlun_print(" OK (256 sectors, pattern verified)\r\n");
384}
385
408{
409 s_dbg_phase = (uint32_t)k_mlun_phase_enum;
410 ra8_err_t err = ra8_usb_hmsc_enumerate(device);
411 if (err != k_ra8_ok) {
412 (void)mlun_print_fail("enumerate", err);
413 (void)ra8_usb_hmsc_close();
414 return err;
415 }
416 s_dbg_max_lun = (uint32_t)device->max_lun;
417 err = mlun_print("ra8d2 mlun: enumerated pid=0x");
418 if (err != k_ra8_ok) {
419 return err;
420 }
421 err = mlun_print_hex((uint32_t)device->product_id, (uint8_t)k_mlun_hex_chars_u16);
422 if (err != k_ra8_ok) {
423 return err;
424 }
425 err = mlun_print(", GET_MAX_LUN=");
426 if (err != k_ra8_ok) {
427 return err;
428 }
430 if (err != k_ra8_ok) {
431 return err;
432 }
433 return mlun_print("\r\n");
434}
435
453[[nodiscard]] static ra8_err_t mlun_host_pass(void)
454{
455 s_dbg_phase = (uint32_t)k_mlun_phase_init;
456 ra8_err_t err = mlun_print("ra8d2 mlun: host up on USB-HS, probing the loop...\r\n");
457 if (err != k_ra8_ok) {
458 return err;
459 }
461 if (err != k_ra8_ok) {
462 (void)mlun_print_fail("host init", err);
463 return err;
464 }
465
466 ra8_usb_hmsc_device_t device = {};
467 err = mlun_host_enumerate(&device);
468 if (err != k_ra8_ok) {
469 return err;
470 }
471
473 s_dbg_luns_ok = 0U;
474 for (uint32_t lun = 0U; lun < (uint32_t)k_mlun_count; lun++) {
475 err = mlun_verify_one(lun);
476 if (err != k_ra8_ok) {
477 (void)ra8_usb_hmsc_close();
478 return err;
479 }
481 err = mlun_print_lun_ok(lun);
482 if (err != k_ra8_ok) {
483 return err;
484 }
485 }
486
487 s_dbg_phase = (uint32_t)k_mlun_phase_pass;
489 err = mlun_print("ra8d2 mlun: USB SELFTEST MULTI-LUN PASS\r\n");
490 if (err != k_ra8_ok) {
491 return err;
492 }
494 return k_ra8_ok;
495}
496
498{
499 (void)arg;
500
502 for (;;) {
503 const ra8_err_t err = mlun_host_pass();
504 if (err == k_ra8_ok) {
505 break;
506 }
508 }
509 while (1) {
511 }
512}
513
514#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.
#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 mlun_nibble_to_hex(uint32_t nibble)
Format one nibble (0..15) into an uppercase hex character.
void mlun_pattern_fill(uint32_t lun, uint32_t lba, UCHAR *out)
Fill one 512-byte sector with this LUN/LBA's deterministic bytes.
static ra8_err_t mlun_print_hex(uint32_t value, uint8_t digits)
Print a value as fixed-width uppercase hex.
VOID mlun_host_worker(ULONG arg)
Host-side worker: retry the full pass until it succeeds.
static ra8_err_t mlun_verify_one(uint32_t lun)
Read + verify one LUN's full sector range against its pattern.
static ra8_err_t mlun_sci_write(const uint8_t *data, uint32_t len)
Push a literal block over SCI8 polled.
static ra8_err_t mlun_print_fail(const char *what, ra8_err_t err)
Print "FAIL <what> err=0xNNNNNNNN" on its own line.
static ra8_err_t mlun_host_enumerate(ra8_usb_hmsc_device_t *device)
Enumerate the looped device and print its PID + GET_MAX_LUN.
static ra8_err_t mlun_print_dec(uint32_t value)
Print a uint32_t as ASCII decimal.
static ra8_err_t mlun_host_pass(void)
One full host-side pass: enumerate, verify both LUNs.
static ra8_err_t mlun_print(const char *text)
Print a NUL-terminated ASCII string over the console.
static uint32_t mlun_str_len(const char *text)
Bounded ASCII string length (cap k_mlun_print_cap).
static ra8_err_t mlun_print_lun_ok(uint32_t lun)
Print "LUN n OK (256 sectors)" for a verified logical unit.
Shared constants + cross-TU prototypes for usb_selftest_mlun.
@ k_mlun_byte_mask
Byte mask.
@ k_mlun_pat_bias
Pattern constant bias.
@ k_mlun_count
Logical units exposed (UX_MAX_SLAVE_LUN).
@ k_mlun_no_mismatch
Probe: no mismatch.
@ k_mlun_pat_lun_mul
Per-LUN pattern multiplier.
@ k_mlun_mismatch_lun_shift
s_dbg_mismatch: LUN in bits 31:24.
@ k_mlun_block_size
SCSI logical block size.
@ k_mlun_pat_lba_mul
Per-LBA pattern multiplier.
@ k_mlun_burst_blocks
Blocks per READ(10) burst.
@ k_mlun_sectors
512-byte sectors per LUN.
@ k_mlun_burst_bytes
8 x 512 B burst buffer.
@ k_mlun_dec_radix
Base for decimal conversion.
@ k_mlun_nibble_mask
4-bit nibble mask.
@ k_mlun_nibble_bits
Bits per hex nibble.
@ k_mlun_hex_chars_u16
16-bit value -> "ABCD".
@ k_mlun_dec_chars_u32
Max digits for a 32-bit count.
@ k_mlun_hex_chars_u32
32-bit value -> "ABCDEF01".
@ k_mlun_hex_digit_split
Threshold between '0-9'/'A-F'.
@ k_mlun_phase_verify
Reading + checking LUNs.
@ k_mlun_phase_enum
Enumerating.
@ k_mlun_phase_pass
All LUNs verified.
@ k_mlun_phase_init
ra8_usb_hmsc_init issued.
@ k_mlun_print_cap
Bound for console-string scans.
@ k_mlun_idle_ticks
Parked-loop back-off (ticks).
@ k_mlun_boot_wait_ticks
Host start delay (1 ms ticks).
@ k_mlun_retry_ticks
Pause between ladder retries.
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).