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
45
46#include <stdint.h>
47#include <string.h>
48
49#include "ra8_board_ek_ra8d2.h"
50#include "ra8_boot_entry.h"
51#include "ra8_cgc.h"
52#include "ra8_err.h"
53#include "ra8_gpio_constants.h"
54#include "ra8_isr.h"
55#include "ra8_port_constants.h"
56#include "ra8_port_utils.h"
57#include "ra8_time.h"
58#include "ra8_usb.h"
59
60#ifndef RA8_OFF_TARGET
61#include "tx_api.h"
62#include "ux_api.h"
63#include "ux_dcd_ra8_usb.h"
64#include "ux_device_class_storage.h"
65#include "ux_device_stack.h"
66
67/* Strong SysTick override: route the tick into BOTH the ra8_time millisecond
68 * counter (for ra8_delay_ms) AND ThreadX's timer (for tx_thread_sleep and
69 * semaphore timeouts). The default weak ra8_time SysTick handler only advances
70 * the ms counter; without _tx_timer_interrupt ThreadX time never advances and
71 * tx_thread_sleep / USBX class-thread scheduling stall. The project's
72 * tx_initialize_low_level.S configures SysTick but relies on the application
73 * to publish the handler. */
74
75extern void _tx_timer_interrupt(void);
76void SysTick_Handler(void);
78{
81 /* Re-enable the USB IRQ at the NVIC level: the bridge's storm guard
82 * masks it to break the USBFS event-less interrupt storm, and this
83 * 1 ms pulse is its recovery clock -- a masked line is re-enabled
84 * within one period so real USB events are never lost. */
86}
87#endif
88
89/* -------------------------------------------------------------------------- */
90/* Pinout (FSP-aligned, EK-RA8D2 v1 User's Manual) */
91/* -------------------------------------------------------------------------- */
92
103
104/* -------------------------------------------------------------------------- */
105/* Tunables */
106/* -------------------------------------------------------------------------- */
107
114
128
129#ifndef RA8_OFF_TARGET
130
131/* -------------------------------------------------------------------------- */
132/* ThreadX worker + USBX pool storage */
133/* -------------------------------------------------------------------------- */
134
142
149
158
168
169/* SCSI INQUIRY strings -- 8 / 16 / 4 byte fields per SBC-3. */
170static UCHAR s_msc_vendor_id[] = "RA8D2 ";
171static UCHAR s_msc_product_id[] = "USBX RAM Disk ";
172static UCHAR s_msc_product_rev[] = "0001";
173
174/* -------------------------------------------------------------------------- */
175/* USB descriptors (DEVICE + CONFIG + MSC interface + endpoints) */
176/* -------------------------------------------------------------------------- */
177
178/* Single-interface MSC config: bulk-only transport, SCSI command set.
179 * Class = 0x08 (Mass Storage), SubClass = 0x06 (SCSI transparent),
180 * Protocol = 0x50 (BBB / Bulk-Only). EP1 IN + EP2 OUT, 64-byte MPS.
181 *
182 * Layout per USB Mass Storage Class Bulk-Only Transport (BBB) rev 1.0
183 * sec 4 + USB 2.0 sec 9.6.
184 *
185 * Total config-blob length:
186 * 9 (config) + 9 (interface) + 7 (EP IN) + 7 (EP OUT) = 32 bytes.
187 */
188static UCHAR s_device_framework_fs[] = {
189 /* Device descriptor (USB 2.0 sec 9.6.1) -- 18 bytes.
190 * bcdUSB = 0x0200 (USB 2.0); hosts may reject USB 1.1 for
191 * modern composite/class drivers. */
192 0x12U,
193 0x01U,
194 0x00U,
195 0x02U,
196 0x00U, /* class = per-interface */
197 0x00U,
198 0x00U,
199 0x40U,
200 0x09U,
201 0x12U,
202 0x0BU, /* PID = 0x000B (pid.codes test). */
203 0x00U,
204 0x00U,
205 0x01U,
206 0x01U,
207 0x02U,
208 0x03U,
209 0x01U,
210 /* Configuration descriptor (32 bytes total).
211 * bmAttributes = 0x80 (bus-powered); 0xC0 (self-powered)
212 * with bMaxPower=100mA is self-contradictory. */
213 0x09U,
214 0x02U,
215 0x20U,
216 0x00U,
217 0x01U,
218 0x01U,
219 0x00U,
220 0x80U,
221 0x32U,
222 /* Interface descriptor -- MSC, SCSI, BBB. */
223 0x09U,
224 0x04U,
225 0x00U,
226 0x00U,
227 0x02U,
228 0x08U,
229 0x06U,
230 0x50U,
231 0x00U,
232 /* Bulk-IN endpoint (EP1 IN, 64-byte MPS). */
233 0x07U,
234 0x05U,
235 0x81U,
236 0x02U,
237 0x40U,
238 0x00U,
239 0x00U,
240 /* Bulk-OUT endpoint (EP2 OUT, 64-byte MPS). */
241 0x07U,
242 0x05U,
243 0x02U,
244 0x02U,
245 0x40U,
246 0x00U,
247 0x00U,
248};
249
257static UCHAR s_string_framework[] = {
258 /* idx 1: "Brighton Sikarskie". */
259 0x09U,
260 0x04U,
261 0x01U,
262 0x12U,
263 'B',
264 'r',
265 'i',
266 'g',
267 'h',
268 't',
269 'o',
270 'n',
271 ' ',
272 'S',
273 'i',
274 'k',
275 'a',
276 'r',
277 's',
278 'k',
279 'i',
280 'e',
281 /* idx 2: "EK-RA8D2 RAM Disk". */
282 0x09U,
283 0x04U,
284 0x02U,
285 0x11U,
286 'E',
287 'K',
288 '-',
289 'R',
290 'A',
291 '8',
292 'D',
293 '2',
294 ' ',
295 'R',
296 'A',
297 'M',
298 ' ',
299 'D',
300 'i',
301 's',
302 'k',
303 /* idx 3: serial. */
304 0x09U,
305 0x04U,
306 0x03U,
307 0x08U,
308 '0',
309 '0',
310 '0',
311 '0',
312 '0',
313 '0',
314 '0',
315 '1',
316};
317
318/* USBX LANGID descriptor 0x0409 (English-US), little-endian byte pair. */
319typedef enum : uint8_t {
323
330
331/* -------------------------------------------------------------------------- */
332/* Storage class media callbacks (read / write / status) */
333/* -------------------------------------------------------------------------- */
334
361static UINT demo_msc_read(VOID* storage,
362 ULONG lun,
363 UCHAR* data_pointer,
364 ULONG number_blocks,
365 ULONG lba,
366 ULONG* media_status)
367{
368 (void)storage;
369 (void)lun;
370 if ((lba + number_blocks) > (ULONG)k_demo_block_count) {
371 *media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(k_scsi_sense_illegal_request,
374 return UX_ERROR;
375 }
376 (void)memcpy(data_pointer,
378 number_blocks * (ULONG)k_demo_block_size);
379 *media_status = 0UL;
381 return UX_SUCCESS;
382}
383
408/* cppcheck-suppress-begin [constParameterCallback] -- USBX's
409 * ux_slave_class_storage_media_write function-pointer signature takes
410 * non-const UCHAR*; we cannot const-qualify the parameter. */
411static UINT demo_msc_write(VOID* storage,
412 ULONG lun,
413 UCHAR* data_pointer,
414 ULONG number_blocks,
415 ULONG lba,
416 ULONG* media_status)
417{
418 (void)storage;
419 (void)lun;
420 if ((lba + number_blocks) > (ULONG)k_demo_block_count) {
421 *media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(k_scsi_sense_illegal_request,
424 return UX_ERROR;
425 }
427 data_pointer,
428 number_blocks * (ULONG)k_demo_block_size);
429 *media_status = 0UL;
431 return UX_SUCCESS;
432}
433/* cppcheck-suppress-end [constParameterCallback] */
434
452static UINT demo_msc_status(VOID* storage, ULONG lun, ULONG media_id, ULONG* media_status)
453{
454 (void)storage;
455 (void)lun;
456 (void)media_id;
457 *media_status = 0UL;
458 return UX_SUCCESS;
459}
460
461/* -------------------------------------------------------------------------- */
462/* Worker thread: bring USBX up + run the storage class */
463/* -------------------------------------------------------------------------- */
464
480{
481 if (_ux_system_initialize(s_usbx_pool, k_demo_usbx_pool_bytes, UX_NULL, 0) != UX_SUCCESS) {
482 return UX_ERROR;
483 }
484 return _ux_device_stack_initialize((UCHAR*)UX_NULL,
485 0,
487 sizeof(s_device_framework_fs),
489 sizeof(s_string_framework),
492 UX_NULL);
493}
494
510{
511 UX_SLAVE_CLASS_STORAGE_PARAMETER msc_params;
512 (void)memset(&msc_params, 0, sizeof(msc_params));
513 msc_params.ux_slave_class_storage_parameter_number_lun = 1UL;
514 msc_params.ux_slave_class_storage_parameter_vendor_id = s_msc_vendor_id;
515 msc_params.ux_slave_class_storage_parameter_product_id = s_msc_product_id;
516 msc_params.ux_slave_class_storage_parameter_product_rev = s_msc_product_rev;
517
518 msc_params.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba =
520 msc_params.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length =
522 msc_params.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type =
523 UX_SLAVE_CLASS_STORAGE_MEDIA_FAT_DISK;
524 msc_params.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag =
525 UX_SLAVE_CLASS_STORAGE_MEDIA_IS_REMOVABLE;
526 msc_params.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read_only_flag =
527 UX_FALSE;
528 msc_params.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read =
530 msc_params.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write =
532 msc_params.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status =
534
535 static UCHAR s_class_name[] = "ux_slave_class_storage";
536
537 return _ux_device_stack_class_register(s_class_name,
538 _ux_device_class_storage_entry,
539 1,
540 0,
541 &msc_params);
542}
543
544static VOID demo_worker(ULONG arg)
545{
546 (void)arg;
547
548 if (demo_usbx_stack_up() != UX_SUCCESS) {
549 return;
550 }
551 if (demo_msc_class_register() != UX_SUCCESS) {
552 return;
553 }
555 return;
556 }
558 return;
559 }
560
561 /* Idle. USBX runs the SCSI/BBB state machine on its own threads. */
562 while (1) {
564 }
565}
566
567/* -------------------------------------------------------------------------- */
568/* ThreadX kernel entry: spawn the worker */
569/* -------------------------------------------------------------------------- */
570
582VOID tx_application_define(VOID* first_unused_memory)
583{
584 static CHAR s_thread_name[] = "usb_msc_device";
585
586 (void)first_unused_memory;
590 0UL,
593 8U, /* priority */
594 8U, /* preempt threshold */
597}
598#endif /* !RA8_OFF_TARGET */
599
600/* -------------------------------------------------------------------------- */
601/* Startup helpers */
602/* -------------------------------------------------------------------------- */
603
613static void demo_panic_halt(void)
614{
615 while (1) {
616 __asm__ volatile("wfi");
617 }
618}
619
633[[nodiscard]] static ra8_err_t demo_pins_init(void)
634{
636 if (err != k_ra8_ok) {
637 return err;
638 }
639 /* VBUSEN as GPIO output LOW for USB device mode. Peripheral routing
640 * forces VBUSEN HIGH (host mode) which blocks device enumeration. */
642 if (err != k_ra8_ok) {
643 return err;
644 }
646 if (err != k_ra8_ok) {
647 return err;
648 }
650}
651
663void main(void)
664{
665 uint32_t cpuclk0_hz = 0U;
666
667 if (ra8_cgc_init() != k_ra8_ok) {
669 }
670 /* Bring up PLL2 -> USBCKCR / USBCKDIVCR so USBFS sees a spec-compliant
671 * 48 MHz reference (PLL2P 240 MHz / 5). Must run BEFORE any caller
672 * releases MSTPB11 (USBFS) -- the SREQ -> SRDY handshake silently
673 * hangs otherwise (HUM Ch 9 "Clock selection switching procedure"
674 * step 1). Without this the SIE never sees a 48 MHz clock and the
675 * host never enumerates the device. */
678 }
681 }
682 if (ra8_time_init(cpuclk0_hz) != k_ra8_ok) {
684 }
687 }
688 if (demo_pins_init() != k_ra8_ok) {
690 }
691
693
694#ifndef RA8_OFF_TARGET
695 /* tx_kernel_enter is __noreturn -- it never comes back. */
696 tx_kernel_enter();
697#endif
698
700}
void main(void)
Secure fallback main entry point.
Definition main.c:37
static TX_THREAD s_demo_thread
Definition main.c:237
demo_config_t
Compile-time settings for the HTTPS client demo.
Definition main.c:87
@ 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_sense_illegal_request
Sense key: ILLEGAL REQUEST.
Definition main.c:145
@ 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 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
@ k_demo_block_count
Blocks erased/written/read.
Definition main.c:60
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 UCHAR s_ramdisk[k_demo_block_count *k_demo_block_size]
RAM-disk backing store (4 KiB = 8 x 512-byte sectors).
Definition main.c:167
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.
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
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.
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.