ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
usb_selftest_ospi_format.c
Go to the documentation of this file.
1
26
27#include <stdint.h>
28#include <string.h>
29
30#include "ra8_board_ek_ra8d2.h"
31#include "ra8_err.h"
32#include "ra8_xspi.h"
34
35#ifndef RA8_OFF_TARGET
36
37#include "tx_api.h"
38#include "ux_api.h"
39#include "ux_device_class_storage.h"
40
41/* -------------------------------------------------------------------------- */
42/* J-Link probe */
43/* -------------------------------------------------------------------------- */
44
46static volatile uint32_t s_dbg_read_calls;
47
48/* -------------------------------------------------------------------------- */
49/* FAT16 synthesis static data (identical layout to usb_msc_mram) */
50/* -------------------------------------------------------------------------- */
51
53static const UCHAR s_fat_oem_name[8] = {'R', 'A', '8', 'D', '2', 'F', 'W', ' '};
54
56static const UCHAR s_fat_volume_label[11] = {'R', 'A', '8', 'D', '2', ' ', 'O', 'S', 'P', 'I', ' '};
57
59static const UCHAR s_fat_fs_type[8] = {'F', 'A', 'T', '1', '6', ' ', ' ', ' '};
60
62static const UCHAR s_fat_file_name[11] = {'O', 'S', 'P', 'I', ' ', ' ', ' ', ' ', 'B', 'I', 'N'};
63
64/* -------------------------------------------------------------------------- */
65/* FAT16 synthesis (identical layout to usb_msc_mram) */
66/* -------------------------------------------------------------------------- */
67
84static void selftest_put16(UCHAR* dst, uint16_t value)
85{
86 dst[0] = (UCHAR)(value & (uint16_t)k_byte_mask);
87 dst[1] = (UCHAR)((value >> (uint16_t)k_byte_shift) & (uint16_t)k_byte_mask);
88}
89
106static void selftest_put32(UCHAR* dst, uint32_t value)
107{
108 selftest_put16(dst, (uint16_t)(value & (uint32_t)k_word_mask));
109 selftest_put16(dst + 2U, (uint16_t)(value >> (uint32_t)k_word_shift));
110}
111
128static void selftest_fat_fill_boot(UCHAR* out)
129{
130 out[k_bpb_off_jmp] = (UCHAR)k_boot_jmp0;
131 out[k_bpb_off_jmp + 1U] = (UCHAR)k_boot_jmp1;
132 out[k_bpb_off_jmp + 2U] = (UCHAR)k_boot_jmp2;
133 (void)memcpy(&out[k_bpb_off_oem], s_fat_oem_name, sizeof(s_fat_oem_name));
135 out[k_bpb_off_spc] = 1U;
137 out[k_bpb_off_nfats] = (UCHAR)k_fat_num_fats;
140 out[k_bpb_off_media] = (UCHAR)k_boot_media;
145 out[k_bpb_off_bootsig] = (UCHAR)k_boot_ext_sig;
148 (void)memcpy(&out[k_bpb_off_fstype], s_fat_fs_type, sizeof(s_fat_fs_type));
149 out[k_boot_sig_lo_off] = (UCHAR)k_boot_sig_lo;
150 out[k_boot_sig_hi_off] = (UCHAR)k_boot_sig_hi;
151}
152
172static void selftest_fat_fill_fat(uint32_t fat_sector, UCHAR* out)
173{
174 const uint32_t first_entry = fat_sector * (uint32_t)k_fat_entries_per_sec;
175 for (uint32_t j = 0U; j < (uint32_t)k_fat_entries_per_sec; j++) {
176 const uint32_t entry = first_entry + j;
177 uint16_t value = 0U;
178 if (entry == 0U) {
179 value = (uint16_t)k_fat_entry0;
180 } else if (entry == 1U) {
181 value = (uint16_t)k_fat_eoc;
182 } else if (entry < (uint32_t)k_fat_last_data_clus) {
183 value = (uint16_t)(entry + 1U);
184 } else if (entry == (uint32_t)k_fat_last_data_clus) {
185 value = (uint16_t)k_fat_eoc;
186 } else {
187 value = 0U;
188 }
189 selftest_put16(&out[j * 2U], value);
190 }
191}
192
211static void selftest_fat_fill_root(uint32_t root_sector, UCHAR* out)
212{
213 if (root_sector != 0U) {
214 return;
215 }
216 /* Entry 0: volume label. */
217 (void)memcpy(&out[0], s_fat_volume_label, (size_t)k_dir_name_bytes);
218 out[k_dir_off_attr] = (UCHAR)k_dir_attr_volume;
219 /* Entry 1: MRAM.BIN, read-only, cluster 2, 1 MiB. */
220 UCHAR* entry = &out[k_dir_entry_bytes];
221 (void)memcpy(entry, s_fat_file_name, (size_t)k_dir_name_bytes);
222 entry[k_dir_off_attr] = (UCHAR)k_dir_attr_read_only;
224 selftest_put32(&entry[k_dir_off_size], (uint32_t)k_ospi_bytes);
225}
226
227void selftest_pattern_fill(uint32_t win_sector, UCHAR* out)
228{
229 for (uint32_t i = 0U; i < (uint32_t)k_selftest_block_size; i++) {
230 const uint32_t v = (win_sector * (uint32_t)k_ospi_pat_smul) + (i * (uint32_t)k_ospi_pat_imul) +
231 (uint32_t)k_ospi_pat_bias;
232 out[i] = (UCHAR)(v & (uint32_t)k_ospi_pat_mask);
233 }
234}
235
257static void selftest_fat_fill_sector(uint32_t lba, UCHAR* out)
258{
259 (void)memset(out, 0, (size_t)k_selftest_block_size);
260 if (lba == 0U) {
262 return;
263 }
264 if (lba < (uint32_t)k_fat_root_lba) {
265 selftest_fat_fill_fat(lba - (uint32_t)k_fat_fat_lba, out);
266 return;
267 }
268 if (lba < (uint32_t)k_fat_data_lba) {
269 selftest_fat_fill_root(lba - (uint32_t)k_fat_root_lba, out);
270 return;
271 }
272 const uint32_t cluster = (lba - (uint32_t)k_fat_data_lba) + (uint32_t)k_fat_first_cluster;
273 if (cluster <= (uint32_t)k_fat_last_data_clus) {
274 const uint32_t win_sector = cluster - (uint32_t)k_fat_first_cluster;
275 const uint32_t flash_addr =
276 (uint32_t)k_ospi_test_offset + (win_sector * (uint32_t)k_selftest_block_size);
278 flash_addr,
279 out,
280 (uint32_t)k_selftest_block_size);
281 }
282}
283
284/* -------------------------------------------------------------------------- */
285/* Storage class media callbacks (read / write / status) */
286/* -------------------------------------------------------------------------- */
287
289 ULONG lun,
290 UCHAR* data_pointer,
291 ULONG number_blocks,
292 ULONG lba,
293 ULONG* media_status)
294{
295 (void)storage;
296 (void)lun;
298 if ((lba + number_blocks) > (ULONG)k_fat_total_sectors) {
299 *media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(k_scsi_sense_illegal_request,
302 return UX_ERROR;
303 }
304 for (ULONG i = 0UL; i < number_blocks; i++) {
305 selftest_fat_fill_sector((uint32_t)(lba + i), &data_pointer[i * (ULONG)k_selftest_block_size]);
306 }
307 *media_status = 0UL;
309 return UX_SUCCESS;
310}
311
313 ULONG lun,
314 UCHAR* data_pointer,
315 ULONG number_blocks,
316 ULONG lba,
317 ULONG* media_status)
318{
319 (void)storage;
320 (void)lun;
321 (void)data_pointer;
322 (void)number_blocks;
323 (void)lba;
324 *media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(k_scsi_sense_data_protect,
327 return UX_ERROR;
328}
329
330UINT selftest_msc_status(VOID* storage, ULONG lun, ULONG media_id, ULONG* media_status)
331{
332 (void)storage;
333 (void)lun;
334 (void)media_id;
335 *media_status = 0UL;
336 return UX_SUCCESS;
337}
338
339/* -------------------------------------------------------------------------- */
340/* Console helpers (SCI8 -> J-Link OB CDC) */
341/* -------------------------------------------------------------------------- */
342
361static uint8_t selftest_nibble_to_hex(uint32_t nibble)
362{
363 if (nibble < k_selftest_hex_digit_split) {
364 return (uint8_t)((uint8_t)'0' + (uint8_t)nibble);
365 }
366 return (uint8_t)((uint8_t)'A' + (uint8_t)nibble - (uint8_t)k_selftest_hex_digit_split);
367}
368
387static uint32_t selftest_str_len(const char* text)
388{
389 uint32_t len = 0U;
390 while (len < (uint32_t)k_selftest_print_cap) {
391 if (text[len] == '\0') {
392 break;
393 }
394 len++;
395 }
396 return len;
397}
398
418[[nodiscard]] static ra8_err_t selftest_sci_write(const uint8_t* data, uint32_t len)
419{
420 return ra8_board_uart_console_write(data, (size_t)len);
421}
422
423[[nodiscard]] ra8_err_t selftest_print(const char* text)
424{
425 return selftest_sci_write((const uint8_t*)text, selftest_str_len(text));
426}
427
428[[nodiscard]] ra8_err_t selftest_print_dec(uint32_t value)
429{
430 uint8_t scratch[k_selftest_dec_chars_u32] = {};
431 uint8_t out[k_selftest_dec_chars_u32] = {};
432 uint8_t count = 0U;
433 uint32_t v = value;
434 if (v == 0U) {
435 out[0] = (uint8_t)'0';
436 return selftest_sci_write(out, 1U);
437 }
438 while (v != 0U) {
439 if (count >= (uint8_t)k_selftest_dec_chars_u32) {
440 break;
441 }
442 scratch[count] = (uint8_t)((uint8_t)'0' + (uint8_t)(v % k_selftest_dec_radix));
443 v = v / k_selftest_dec_radix;
444 count++;
445 }
446 for (uint8_t i = 0U; i < count; i++) {
447 out[i] = scratch[count - 1U - i];
448 }
449 return selftest_sci_write(out, (uint32_t)count);
450}
451
452[[nodiscard]] ra8_err_t selftest_print_hex(uint32_t value, uint8_t digits)
453{
454 uint8_t out[k_selftest_hex_chars_u32] = {};
455 uint8_t width = digits;
456 if (width > (uint8_t)k_selftest_hex_chars_u32) {
457 width = (uint8_t)k_selftest_hex_chars_u32;
458 }
459 for (uint8_t i = 0U; i < width; i++) {
460 const uint8_t shift = (uint8_t)((width - 1U - i) * k_selftest_nibble_bits);
461 out[i] = selftest_nibble_to_hex((value >> shift) & k_selftest_nibble_mask);
462 }
463 return selftest_sci_write(out, (uint32_t)width);
464}
465
466[[nodiscard]] ra8_err_t selftest_print_fail(const char* what, ra8_err_t err)
467{
468 ra8_err_t e = selftest_print("ra8d2 selftest: FAIL ");
469 if (e != k_ra8_ok) {
470 return e;
471 }
472 e = selftest_print(what);
473 if (e != k_ra8_ok) {
474 return e;
475 }
476 e = selftest_print(" err=0x");
477 if (e != k_ra8_ok) {
478 return e;
479 }
480 e = selftest_print_hex((uint32_t)err, (uint8_t)k_selftest_hex_chars_u32);
481 if (e != k_ra8_ok) {
482 return e;
483 }
484 return selftest_print("\r\n");
485}
486
487#endif /* !RA8_OFF_TARGET */
@ k_scsi_ascq_none
ASCQ: none.
Definition main.c:147
@ k_scsi_asc_write_protected
ASC: WRITE PROTECTED.
Definition main.c:149
@ k_scsi_sense_illegal_request
Sense key: ILLEGAL REQUEST.
Definition main.c:145
@ k_scsi_sense_data_protect
Sense key: DATA PROTECT.
Definition main.c:148
@ k_scsi_asc_lba_out_of_range
ASC: LBA out of range.
Definition main.c:146
static volatile uint32_t s_dbg_read_calls
Device-side media_read invocations.
Definition main.c:213
Board-support layer for the Renesas EK-RA8D2 v1 evaluation kit.
ra8_err_t ra8_board_led_toggle(ra8_board_led_id_t led)
Toggle led's output state.
@ k_ra8_board_led1
LED1, BLUE, P600 (jumper E27).
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_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
void * memset(void *dst, int value, size_t n)
Fill memory with a constant byte value.
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
@ k_dir_off_attr
MS FAT spec sec 6 "DIR_Attr".
@ k_byte_mask
Byte mask.
@ k_word_mask
Word mask.
unsigned int UINT
ThreadX-compatible unsigned int (host stub).
unsigned long ULONG
ThreadX-compatible unsigned long (host stub).
xSPI / Octo-SPI driver (flash read/program/erase + ID/status)
ra8_err_t ra8_xspi_flash_read(uint8_t instance, uint32_t flash_addr, uint8_t *buf, uint32_t len)
Read len bytes from external flash into buf.
@ k_selftest_hex_digit_split
Threshold between '0-9'/'A-F'.
@ k_selftest_dec_chars_u32
Max digits for a 32-bit count.
@ k_selftest_hex_chars_u32
32-bit value -> "ABCDEF01".
@ k_selftest_nibble_bits
Bits per hex nibble.
@ k_selftest_dec_radix
Base for decimal conversion.
@ k_selftest_nibble_mask
4-bit nibble mask.
static const UCHAR s_fat_oem_name[8]
Boot-sector OEM name (8 bytes, space padded).
static const UCHAR s_fat_fs_type[8]
Filesystem-type tag, 8 bytes space padded.
static const UCHAR s_fat_volume_label[11]
Volume label, 11 bytes space padded (also the root entry).
@ k_boot_sig_hi_off
Signature high-byte offset.
@ k_boot_jmp0
Short JMP opcode.
@ k_boot_num_heads
Geometry filler.
@ k_boot_sig_lo_off
Signature low-byte offset.
@ k_boot_sig_hi
Boot signature high byte.
@ k_boot_jmp1
JMP displacement.
@ k_boot_sig_lo
Boot signature low byte.
@ k_boot_media
Fixed-disk media byte.
@ k_boot_sec_per_trk
Geometry filler.
@ k_boot_ext_sig
Extended boot signature.
@ k_boot_drive_num
BIOS drive number.
@ k_boot_jmp2
NOP.
@ k_boot_volume_id
Arbitrary volume serial.
static const UCHAR s_fat_file_name[11]
8.3 directory name of the exposed file: "MRAM.BIN".
@ k_word_shift
Bits per half-word.
@ k_fat_root_entries
Root directory entries.
@ k_fat_eoc
End-of-chain marker.
@ k_fat_data_lba
First data sector (cluster 2).
@ k_fat_root_lba
First root-directory sector.
@ k_fat_fat_sectors
FAT16 size for 4098 entries.
@ k_fat_fat_lba
First FAT sector.
@ k_fat_first_cluster
FAT data area starts at cluster 2.
@ k_fat_entry0
FAT[0]: media F8 + filler.
@ k_fat_reserved_sectors
Boot sector only.
@ k_fat_entries_per_sec
FAT16 entries per 512-byte sector.
@ k_fat_total_sectors
1 + 17 + 32 + 4096.
@ k_fat_num_fats
Single FAT copy.
@ k_dir_entry_bytes
Directory entry size.
@ k_bpb_off_spt
Sectors per track.
@ k_bpb_off_label
Volume label (11 bytes).
@ k_dir_attr_volume
Volume-label attribute.
@ k_bpb_off_media
Media descriptor.
@ k_bpb_off_bps
Bytes per sector.
@ k_dir_off_size
File size (32-bit LE).
@ k_bpb_off_jmp
Jump instruction.
@ k_bpb_off_heads
Head count.
@ k_bpb_off_oem
OEM name (8 bytes).
@ k_bpb_off_volid
Volume serial (4 bytes).
@ k_bpb_off_bootsig
Extended boot signature.
@ k_bpb_off_fatsz16
Sectors per FAT.
@ k_bpb_off_rsvd
Reserved sector count.
@ k_bpb_off_drvnum
Drive number.
@ k_bpb_off_fstype
Filesystem type (8 bytes).
@ k_bpb_off_rootent
Root entry count.
@ k_dir_name_bytes
8.3 name field length.
@ k_byte_shift
Bits per byte for LE packing.
@ k_dir_off_cluster_lo
First cluster (low word).
@ k_bpb_off_nfats
Number of FATs.
@ k_bpb_off_spc
Sectors per cluster.
@ k_bpb_off_totsec16
Total sectors (16-bit).
@ k_dir_attr_read_only
Read-only attribute.
@ k_selftest_block_size
SCSI logical block size (bytes).
@ k_selftest_print_cap
Bound for console-string scans.
ra8_err_t selftest_print_hex(uint32_t value, uint8_t digits)
Print a value as fixed-width uppercase hex.
static uint32_t selftest_str_len(const char *text)
Bounded ASCII string length (cap k_selftest_print_cap).
UINT selftest_msc_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status)
Storage media-status callback.
static void selftest_put16(UCHAR *dst, uint16_t value)
Write a 16-bit value little-endian into a byte buffer.
static uint8_t selftest_nibble_to_hex(uint32_t nibble)
Format one nibble (0..15) into an uppercase hex character.
static void selftest_fat_fill_root(uint32_t root_sector, UCHAR *out)
Synthesize one root-directory sector.
ra8_err_t selftest_print_fail(const char *what, ra8_err_t err)
Print "FAIL <what> err=0xNNNNNNNN" on its own line.
static void selftest_fat_fill_sector(uint32_t lba, UCHAR *out)
Synthesize one 512-byte sector of the read-only volume.
static ra8_err_t selftest_sci_write(const uint8_t *data, uint32_t len)
Push a literal block over SCI8 polled.
UINT selftest_msc_read(VOID *storage, ULONG lun, UCHAR *data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status)
Storage media-read callback: synthesize sectors over MRAM.
void selftest_pattern_fill(uint32_t win_sector, UCHAR *out)
Compute the deterministic pattern for one window data sector.
static void selftest_fat_fill_boot(UCHAR *out)
Synthesize the FAT16 boot sector (MS FAT spec 1.03 sec 3.1).
ra8_err_t selftest_print(const char *text)
Print a NUL-terminated ASCII string over the console.
static void selftest_fat_fill_fat(uint32_t fat_sector, UCHAR *out)
Synthesize one FAT16 sector of the cluster chain.
UINT selftest_msc_write(VOID *storage, ULONG lun, UCHAR *data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status)
Storage media-write callback: always rejects (write-protected).
static void selftest_put32(UCHAR *dst, uint32_t value)
Write a 32-bit value little-endian into a byte buffer.
ra8_err_t selftest_print_dec(uint32_t value)
Print a uint32_t as ASCII decimal.
Shared constants + step prototypes for the OSPI USB self-loop app.
@ k_fat_last_data_clus
Last cluster of MRAM.BIN.
@ k_ospi_pat_bias
Constant bias.
@ k_ospi_pat_mask
Byte mask.
@ k_ospi_pat_smul
Per-sector multiplier.
@ k_ospi_pat_imul
Per-byte multiplier.
@ k_ospi_bytes
1 MiB exposed window size.
@ k_ospi_test_offset
1 MiB into the chip (scratch).
@ k_ospi_instance
xSPI controller instance.