ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
main.c
Go to the documentation of this file.
1
49
50#include <stdint.h>
51#include <string.h>
52
53#include "ra8_board_ek_ra8d2.h"
54#include "ra8_boot_entry.h"
55#include "ra8_cgc.h"
56#include "ra8_err.h"
57#include "ra8_gpio_constants.h"
58#include "ra8_isr.h"
59#include "ra8_port_constants.h"
60#include "ra8_port_utils.h"
61#include "ra8_time.h"
62#include "ra8_usb.h"
63#include "usb_msc_mram_steps.h"
64
65#ifndef RA8_OFF_TARGET
66#include "tx_api.h"
67#include "ux_api.h"
68#include "ux_dcd_ra8_usb.h"
69#include "ux_device_class_storage.h"
70#include "ux_device_stack.h"
71
72/* Strong SysTick override: route the tick into BOTH the ra8_time millisecond
73 * counter (for ra8_delay_ms) AND ThreadX's timer (for tx_thread_sleep and
74 * semaphore timeouts). The default weak ra8_time SysTick handler only advances
75 * the ms counter; without _tx_timer_interrupt ThreadX time never advances and
76 * tx_thread_sleep / USBX class-thread scheduling stall. The project's
77 * tx_initialize_low_level.S configures SysTick but relies on the application
78 * to publish the handler. */
79
80extern void _tx_timer_interrupt(void);
81void SysTick_Handler(void);
83{
86 /* Re-enable the USB IRQ at the NVIC level: the bridge's storm guard
87 * masks it to break the USBFS event-less interrupt storm, and this
88 * 1 ms pulse is its recovery clock -- a masked line is re-enabled
89 * within one period so real USB events are never lost. */
91}
92#endif
93
94/* -------------------------------------------------------------------------- */
95/* Pinout (FSP-aligned, EK-RA8D2 v1 User's Manual) */
96/* -------------------------------------------------------------------------- */
97
108
109/* -------------------------------------------------------------------------- */
110/* Tunables */
111/* -------------------------------------------------------------------------- */
112
119
121typedef enum : uint8_t {
125
126#ifndef RA8_OFF_TARGET
127
128/* -------------------------------------------------------------------------- */
129/* ThreadX worker + USBX pool storage */
130/* -------------------------------------------------------------------------- */
131
139
146
155
156/* SCSI INQUIRY strings -- 8 / 16 / 4 byte fields per SBC-3. */
157static UCHAR s_msc_vendor_id[] = "RA8D2 ";
158static UCHAR s_msc_product_id[] = "MRAM 1MiB (RO) ";
159static UCHAR s_msc_product_rev[] = "0001";
160
161/* -------------------------------------------------------------------------- */
162/* USB descriptors (DEVICE + CONFIG + MSC interface + endpoints) */
163/* -------------------------------------------------------------------------- */
164
165/* Single-interface MSC config: bulk-only transport, SCSI command set.
166 * Class = 0x08 (Mass Storage), SubClass = 0x06 (SCSI transparent),
167 * Protocol = 0x50 (BBB / Bulk-Only). EP1 IN + EP2 OUT, 64-byte MPS.
168 *
169 * Layout per USB Mass Storage Class Bulk-Only Transport (BBB) rev 1.0
170 * sec 4 + USB 2.0 sec 9.6.
171 *
172 * Total config-blob length:
173 * 9 (config) + 9 (interface) + 7 (EP IN) + 7 (EP OUT) = 32 bytes.
174 */
175static UCHAR s_device_framework_fs[] = {
176 /* Device descriptor (USB 2.0 sec 9.6.1) -- 18 bytes.
177 * bcdUSB = 0x0200 (USB 2.0); hosts may reject USB 1.1 for
178 * modern composite/class drivers. */
179 0x12U,
180 0x01U,
181 0x00U,
182 0x02U,
183 0x00U, /* class = per-interface */
184 0x00U,
185 0x00U,
186 0x40U,
187 0x09U,
188 0x12U,
189 0x0CU, /* PID = 0x000C (pid.codes test). */
190 0x00U,
191 0x00U,
192 0x01U,
193 0x01U,
194 0x02U,
195 0x03U,
196 0x01U,
197 /* Configuration descriptor (32 bytes total).
198 * bmAttributes = 0x80 (bus-powered); 0xC0 (self-powered)
199 * with bMaxPower=100mA is self-contradictory. */
200 0x09U,
201 0x02U,
202 0x20U,
203 0x00U,
204 0x01U,
205 0x01U,
206 0x00U,
207 0x80U,
208 0x32U,
209 /* Interface descriptor -- MSC, SCSI, BBB. */
210 0x09U,
211 0x04U,
212 0x00U,
213 0x00U,
214 0x02U,
215 0x08U,
216 0x06U,
217 0x50U,
218 0x00U,
219 /* Bulk-IN endpoint (EP1 IN, 64-byte MPS). */
220 0x07U,
221 0x05U,
222 0x81U,
223 0x02U,
224 0x40U,
225 0x00U,
226 0x00U,
227 /* Bulk-OUT endpoint (EP2 OUT, 64-byte MPS). */
228 0x07U,
229 0x05U,
230 0x02U,
231 0x02U,
232 0x40U,
233 0x00U,
234 0x00U,
235};
236
244static UCHAR s_string_framework[] = {
245 /* idx 1: "Brighton Sikarskie". */
246 0x09U,
247 0x04U,
248 0x01U,
249 0x12U,
250 'B',
251 'r',
252 'i',
253 'g',
254 'h',
255 't',
256 'o',
257 'n',
258 ' ',
259 'S',
260 'i',
261 'k',
262 'a',
263 'r',
264 's',
265 'k',
266 'i',
267 'e',
268 /* idx 2: "EK-RA8D2 MRAM". */
269 0x09U,
270 0x04U,
271 0x02U,
272 0x0DU,
273 'E',
274 'K',
275 '-',
276 'R',
277 'A',
278 '8',
279 'D',
280 '2',
281 ' ',
282 'M',
283 'R',
284 'A',
285 'M',
286 /* idx 3: serial. */
287 0x09U,
288 0x04U,
289 0x03U,
290 0x08U,
291 '0',
292 '0',
293 '0',
294 '0',
295 '0',
296 '0',
297 '0',
298 '1',
299};
300
301/* USBX LANGID descriptor 0x0409 (English-US), little-endian byte pair. */
302typedef enum : uint8_t {
306
313
314/* -------------------------------------------------------------------------- */
315/* Storage class media callbacks (read / write / status) */
316/* -------------------------------------------------------------------------- */
317
343static volatile uint32_t s_dbg_read_calls;
344static volatile uint32_t s_dbg_read_last_lba;
345static volatile uint32_t s_dbg_read_last_n;
346
347static UINT demo_msc_read(VOID* storage,
348 ULONG lun,
349 UCHAR* data_pointer,
350 ULONG number_blocks,
351 ULONG lba,
352 ULONG* media_status)
353{
354 (void)storage;
355 (void)lun;
357 s_dbg_read_last_lba = (uint32_t)lba;
358 s_dbg_read_last_n = (uint32_t)number_blocks;
359 if ((lba + number_blocks) > (ULONG)k_fat_total_sectors) {
360 *media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(k_scsi_sense_illegal_request,
363 return UX_ERROR;
364 }
365 for (ULONG i = 0UL; i < number_blocks; i++) {
366 demo_fat_fill_sector((uint32_t)(lba + i), &data_pointer[i * (ULONG)k_demo_block_size]);
367 }
368 *media_status = 0UL;
370 return UX_SUCCESS;
371}
372
394static UINT demo_msc_write(VOID* storage,
395 ULONG lun,
396 UCHAR* data_pointer,
397 ULONG number_blocks,
398 ULONG lba,
399 ULONG* media_status)
400{
401 (void)storage;
402 (void)lun;
403 (void)data_pointer;
404 (void)number_blocks;
405 (void)lba;
406 *media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(k_scsi_sense_data_protect,
409 return UX_ERROR;
410}
411
429static UINT demo_msc_status(VOID* storage, ULONG lun, ULONG media_id, ULONG* media_status)
430{
431 (void)storage;
432 (void)lun;
433 (void)media_id;
434 *media_status = 0UL;
435 return UX_SUCCESS;
436}
437
438/* -------------------------------------------------------------------------- */
439/* Worker thread: bring USBX up + run the storage class */
440/* -------------------------------------------------------------------------- */
441
457{
458 if (_ux_system_initialize(s_usbx_pool, k_demo_usbx_pool_bytes, UX_NULL, 0) != UX_SUCCESS) {
459 return UX_ERROR;
460 }
461 return _ux_device_stack_initialize((UCHAR*)UX_NULL,
462 0,
464 sizeof(s_device_framework_fs),
466 sizeof(s_string_framework),
469 UX_NULL);
470}
471
487{
488 UX_SLAVE_CLASS_STORAGE_PARAMETER msc_params;
489 (void)memset(&msc_params, 0, sizeof(msc_params));
490 msc_params.ux_slave_class_storage_parameter_number_lun = 1UL;
491 msc_params.ux_slave_class_storage_parameter_vendor_id = s_msc_vendor_id;
492 msc_params.ux_slave_class_storage_parameter_product_id = s_msc_product_id;
493 msc_params.ux_slave_class_storage_parameter_product_rev = s_msc_product_rev;
494
495 msc_params.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba =
497 msc_params.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length =
499 msc_params.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type =
500 UX_SLAVE_CLASS_STORAGE_MEDIA_FAT_DISK;
501 msc_params.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag =
502 UX_SLAVE_CLASS_STORAGE_MEDIA_IS_REMOVABLE;
503 msc_params.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read_only_flag =
504 UX_TRUE;
505 msc_params.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read =
507 msc_params.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write =
509 msc_params.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status =
511
512 static UCHAR s_class_name[] = "ux_slave_class_storage";
513
514 return _ux_device_stack_class_register(s_class_name,
515 _ux_device_class_storage_entry,
516 1,
517 0,
518 &msc_params);
519}
520
521static VOID demo_worker(ULONG arg)
522{
523 (void)arg;
524
525 if (demo_usbx_stack_up() != UX_SUCCESS) {
526 return;
527 }
528 if (demo_msc_class_register() != UX_SUCCESS) {
529 return;
530 }
532 return;
533 }
535 return;
536 }
537
538 /* Idle. USBX runs the SCSI/BBB state machine on its own threads. */
539 while (1) {
541 }
542}
543
544/* -------------------------------------------------------------------------- */
545/* ThreadX kernel entry: spawn the worker */
546/* -------------------------------------------------------------------------- */
547
559VOID tx_application_define(VOID* first_unused_memory)
560{
561 static CHAR s_thread_name[] = "usb_msc_mram";
562
563 (void)first_unused_memory;
567 0UL,
570 8U, /* priority */
571 8U, /* preempt threshold */
574}
575#endif /* !RA8_OFF_TARGET */
576
577/* -------------------------------------------------------------------------- */
578/* Startup helpers */
579/* -------------------------------------------------------------------------- */
580
590static void demo_panic_halt(void)
591{
592 while (1) {
593 __asm__ volatile("wfi");
594 }
595}
596
610[[nodiscard]] static ra8_err_t demo_pins_init(void)
611{
613 if (err != k_ra8_ok) {
614 return err;
615 }
616 /* VBUSEN as GPIO output LOW for USB device mode. Peripheral routing
617 * forces VBUSEN HIGH (host mode) which blocks device enumeration. */
619 if (err != k_ra8_ok) {
620 return err;
621 }
623 if (err != k_ra8_ok) {
624 return err;
625 }
626 return ra8_pfs_route_peripheral(k_demo_pin_dm, k_ra8_psel_usb_fs, "usb_msc_mram.dm");
627}
628
640void main(void)
641{
642 uint32_t cpuclk0_hz = 0U;
643
644 if (ra8_cgc_init() != k_ra8_ok) {
646 }
647 /* Bring up PLL2 -> USBCKCR / USBCKDIVCR so USBFS sees a spec-compliant
648 * 48 MHz reference (PLL2P 240 MHz / 5). Must run BEFORE any caller
649 * releases MSTPB11 (USBFS) -- the SREQ -> SRDY handshake silently
650 * hangs otherwise (HUM Ch 9 "Clock selection switching procedure"
651 * step 1). Without this the SIE never sees a 48 MHz clock and the
652 * host never enumerates the device. */
655 }
658 }
659 if (ra8_time_init(cpuclk0_hz) != k_ra8_ok) {
661 }
664 }
665 if (demo_pins_init() != k_ra8_ok) {
667 }
668
670
671#ifndef RA8_OFF_TARGET
672 /* tx_kernel_enter is __noreturn -- it never comes back. */
673 tx_kernel_enter();
674#endif
675
677}
void main(void)
Secure fallback main entry point.
Definition main.c:37
static TX_THREAD s_demo_thread
Definition main.c:237
@ k_demo_thread_stack
Demo thread stack.
Definition main.c:89
static UCHAR s_demo_stack[k_demo_thread_stack]
Definition main.c:238
void tx_application_define(void *first_unused_memory)
ThreadX system-define hook: build worker thread + byte pool.
Definition main.c:942
void _tx_timer_interrupt(void)
void SysTick_Handler(void)
SysTick exception handler – tail-calls the ThreadX timer.
Definition main.c:146
static UCHAR s_msc_product_id[]
Definition main.c:197
static UCHAR s_string_framework[]
USBX string descriptor table (vendor / product / serial).
Definition main.c:299
scsi_sense_code_t
SCSI sense triple for an unsupported / out-of-range request.
Definition main.c:144
@ 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 UCHAR s_usbx_pool[k_wlun_usbx_pool_bytes]
USBX memory pool (USBX uses tx_byte_pool internally).
Definition main.c:193
usb_langid_byte_t
Definition main.c:358
@ k_usb_langid_en_us_lo
LANGID 0x0409 low byte.
Definition main.c:359
@ k_usb_langid_en_us_hi
LANGID 0x0409 high byte.
Definition main.c:360
static UCHAR s_device_framework_fs[]
Definition main.c:234
static UCHAR s_msc_product_rev[]
Definition main.c:198
static UCHAR s_language_id_framework[]
USBX language-id table – US English.
Definition main.c:368
static volatile uint32_t s_dbg_read_calls
Device-side media_read invocations.
Definition main.c:213
static UCHAR s_msc_vendor_id[]
Definition main.c:196
static void demo_panic_halt(void)
Halt forever in WFI – used as a panic stop on init failure.
Definition main.c:93
static const ra8_port_pin_t k_demo_pin_vbus
USB_FS VBUS pin, packed ra8_port_pin_t.
Definition main.c:153
static ra8_err_t demo_pins_init(void)
Route the four USB-FS pins to the USBFS controller.
Definition main.c:491
static const ra8_port_pin_t k_demo_pin_dp
USB_FS D+ pin, packed ra8_port_pin_t.
Definition main.c:157
static const ra8_port_pin_t k_demo_pin_vbusen
USB_FS VBUSEN pin, packed ra8_port_pin_t.
Definition main.c:155
static const ra8_port_pin_t k_demo_pin_dm
USB_FS D- pin, packed ra8_port_pin_t.
Definition main.c:159
static CHAR s_thread_name[]
Definition main.c:212
static UINT demo_usbx_stack_up(void)
Brings USBX system + device stack up with the FS framework.
Definition main.c:481
@ k_demo_idle_ticks
Idle back-off when no class active.
Definition main.c:122
@ k_demo_usbx_pool_bytes
USBX pool: 32 KiB; CDC-ACM enum exhausts 16 KiB.
Definition main.c:120
static VOID demo_worker(ULONG arg)
Worker thread entry.
Definition main.c:602
static UINT demo_msc_read(VOID *storage, ULONG lun, UCHAR *data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status)
Storage media-read callback.
Definition main.c:361
static UINT demo_msc_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status)
Storage media-status callback.
Definition main.c:452
static UINT demo_msc_class_register(void)
Registers the Mass-Storage class with one LUN backed by s_ramdisk.
Definition main.c:509
@ k_demo_block_size
SCSI logical block size (bytes).
Definition main.c:123
static UINT demo_msc_write(VOID *storage, ULONG lun, UCHAR *data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status)
Storage media-write callback.
Definition main.c:411
static volatile uint32_t s_dbg_read_last_lba
Most recent starting LBA.
Definition main.c:344
static volatile uint32_t s_dbg_read_last_n
Most recent block count.
Definition main.c:345
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.
ra8_err_t ra8_board_led_init(ra8_board_led_id_t led)
Configure led as a digital output, initial level low (off).
@ k_ra8_board_led1
LED1, BLUE, P600 (jumper E27).
@ k_ra8_board_usbfs_pin_dm
P8_15 D-.
@ k_ra8_board_usbfs_pin_vbusen
P5_00 VBUSEN GPIO.
@ k_ra8_board_usbfs_pin_vbus
P4_07 VBUS sense.
@ k_ra8_board_usbfs_pin_dp
P8_14 D+.
Boot entry points shared between a vector table and its startup code.
High-level Clock Generation Circuit driver.
ra8_err_t ra8_cgc_get_clock_hz(ra8_clock_id_t id, uint32_t *out_hz)
Query the current frequency of a clock-tree domain.
Definition ra8_cgc.c:132
@ k_ra8_clock_id_cpuclk0
Cortex-M85 CPUCLK0.
Definition ra8_cgc.h:70
ra8_err_t ra8_cgc_init(void)
Configure the clock tree to a safe default.
Definition ra8_cgc.c:727
ra8_err_t ra8_cgc_usbfs_clock_enable(void)
Bring up the USB-FS module clock (USBCKCR / USBCKDIVCR).
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.
PSEL codes for peripheral pin routing on the RA8D2.
@ k_ra8_psel_usb_fs
10011b: USB Full-Speed.
NVIC + ICU IELSR allocator.
void ra8_isr_globals_enable(void)
Globally enable maskable interrupts (PRIMASK = 0).
Definition ra8_isr.c:439
Typed Port / Pin Constants for the RA8D2 IOPORT Module.
ra8_port_pin_t
Packed (port << 8) | pin pin identifier.
@ k_ra8_level_low
Drive or read 0.
High-level GPIO helpers on top of the PORT + PFS register layer.
ra8_err_t ra8_gpio_output_init(ra8_port_pin_t pin, ra8_level_t init_level)
Configure a pin as a digital output and drive it to an initial level.
Definition gpio.c:88
ra8_err_t ra8_pfs_route_peripheral(ra8_port_pin_t pin, ra8_psel_t psel, const char *owner)
Route a pin to a non-IRQ peripheral function via PFS.PSEL.
Definition gpio.c:238
void ux_dcd_ra8_usb_irq_reenable(void)
Storm-guard recovery: zero the run counter and re-enable the USB IRQ.
SysTick-based tick counter, delay and timestamp helpers.
ra8_err_t ra8_time_init(uint32_t cpu_hz)
Initialise SysTick for a 1 kHz tick interrupt.
Definition ra8_time.c:59
void ra8_time_on_tick(void)
SysTick IRQ handler – called from the vector table.
Definition ra8_time.c:170
Native USB controller driver public API (device + host modes).
ra8_err_t ra8_usb_device_attach(ra8_usb_speed_t speed, bool attached)
Raise / drop the D+ pull-up to advertise the device to the host.
@ k_ra8_usb_speed_fs
Full-Speed controller (USBFS @ 0x40250000).
unsigned int UINT
ThreadX-compatible unsigned int (host stub).
#define tx_thread_create
#define tx_thread_sleep
#define TX_NO_TIME_SLICE
char CHAR
ThreadX-compatible CHAR (host stub).
#define TX_AUTO_START
unsigned long ULONG
ThreadX-compatible unsigned long (host stub).
Opaque thread stand-in for the host build.
scsi_wp_sense_t
SCSI sense triple for a write to the protected medium.
@ k_fat_total_sectors
1 + 17 + 32 + 4096.
Shared geometry constants + FAT16 sector-synthesis prototype.
void demo_fat_fill_sector(uint32_t lba, UCHAR *out)
Synthesize one 512-byte sector of the read-only volume.
USBX device-controller-driver (DCD) bridge to ra8_usb.
ra8_err_t ux_dcd_ra8_usb_initialize(ra8_usb_speed_t speed)
Register the ra8_usb bridge as the active USBX DCD.