ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
main.c File Reference

USB MSC device serving the LIVE full-capacity Pmod2 SD card (R/W). More...

#include <stdint.h>
#include "ra8_board_ek_ra8d2.h"
#include "ra8_boot_entry.h"
#include "ra8_cgc.h"
#include "ra8_err.h"
#include "ra8_gpio_constants.h"
#include "ra8_isr.h"
#include "ra8_port_constants.h"
#include "ra8_port_utils.h"
#include "ra8_sdmmc_spi.h"
#include "ra8_time.h"
#include "usb_msc_sdcard_steps.h"
#include "tx_api.h"
#include "ux_dcd_ra8_usb.h"
Include dependency graph for main.c:

Go to the source code of this file.

Functions

void _tx_timer_interrupt (void)
void SysTick_Handler (void)
 Service the SysTick exception selected by the linked application.
static void sdmsc_panic_halt (void)
 Halt forever in WFI – panic stop on init failure.
static ra8_err_t sdmsc_print_card_banner (uint32_t blocks)
 Print "usb_msc_sdcard: card <N> blocks (<M> MiB)" at boot.
static ra8_err_t sdmsc_card_up (uint32_t pclka_hz)
 Bring the live SD card up and latch its full CSD capacity.
static void sdmsc_route_usb_or_halt (void)
 Route the four USB-FS pins for the device role.
static void sdmsc_setup_or_halt (void)
 Bring CGC + USBFS clock + SysTick + SCI8 + LEDs + SD + pins up.
VOID tx_application_define (VOID *first_unused_memory)
 ThreadX application-define hook.
void main (void)
 Application entry: bring the board up, then hand off to ThreadX.

Variables

static volatile bool s_tx_kernel_up = false
 Set in tx_application_define; gates ThreadX tick delivery.
static const ra8_port_pin_t k_sdmsc_pin_fs_vbus = (ra8_port_pin_t)k_ra8_board_usbfs_pin_vbus
 USBFS VBUS sense pin (P4_07, PSEL = usb_fs).
static const ra8_port_pin_t k_sdmsc_pin_fs_vbusen = (ra8_port_pin_t)k_ra8_board_usbfs_pin_vbusen
 USBFS VBUSEN (P5_00) – GPIO LOW for the device role.
static const ra8_port_pin_t k_sdmsc_pin_fs_dp = (ra8_port_pin_t)k_ra8_board_usbfs_pin_dp
 USBFS D+ (P8_14).
static const ra8_port_pin_t k_sdmsc_pin_fs_dm = (ra8_port_pin_t)k_ra8_board_usbfs_pin_dm
 USBFS D- (P8_15).
static volatile uint32_t s_dbg_sd_err
 SD bring-up result: 0 = card enumerated OK, else the error code.
volatile uint32_t s_usb_msc_sdcard_blocks
 Live SD card capacity in 512-byte blocks (0 = no card).
static TX_THREAD s_device_thread
 ThreadX TCB for the USBX device-side worker thread.
static UCHAR s_device_stack [k_sdmsc_thread_stack]
 Stack backing storage for s_device_thread.

Detailed Description

USB MSC device serving the LIVE full-capacity Pmod2 SD card (R/W).

Tag
[Ring 6 / APP] {World: S}

Exposes the Pmod2 SD-over-SPI card as a real, WRITABLE USB drive: plug the board's USB-FS receptacle (J11) into a computer and the card mounts with its actual filesystem and full CSD-derived capacity – copy a book on, eject, done. This is the ingestion transport for the e-reader (drag-a-file UX): no card pulling, no snapshot volume, no synthesized FAT image anywhere.

  • AT BOOT the SCI0 Simple-SPI transport comes up via ra8_sdmmc_spi_transport_sci, ra8_sdmmc_spi_init enumerates the card, and the CSD capacity is latched into s_usb_msc_sdcard_blocks for the MSC LUN geometry. No card -> the FAIL banner prints and the device never attaches (an empty drive is worse than none).
  • USBFS (J11) = DEVICE: a ThreadX + USBX Mass-Storage class exposes ONE writable logical unit spanning the whole card. media-read runs each SCSI READ(10) as one CMD18 multi-block streak (ra8_sdmmc_spi_read_blocks); media-write runs each WRITE(10) chunk as one CMD25 multi-block streak (ra8_sdmmc_spi_write_blocks). IRQ-driven through the port/usbx/ux_dcd_ra8_usb bridge.

SINGLE OWNER WARNING: while a host has this drive mounted, the HOST owns the card. The firmware must not mount or read the card itself concurrently (no shelf scan, no ra8_fs mount) – the only card user after boot is the USBX storage-class thread. Concurrent access would interleave SD commands mid-transaction and corrupt the filesystem.

Verdicts stream over SCI8 (J-Link OB CDC console, 115200) and are mirrored in J-Link-readable probes (s_dbg_*).

Pinout

FS device: P4_07 VBUS sense, P5_00 VBUSEN GPIO LOW (device role), P8_14 D+, P8_15 D- (PSEL usb_fs). Console: PD_02/PD_03 SCI8. microSD: Pmod2 SCI0 Simple-SPI (SCK/CIPO/COPI PSEL sci_async, CS GPIO idle high).

Author
Brighton Sikarskie
Date
2026-07-08
Since
0.1.0

Definition in file main.c.

Function Documentation

◆ _tx_timer_interrupt()

void _tx_timer_interrupt ( void )
extern

◆ main()

void main ( void )

Application entry: bring the board up, then hand off to ThreadX.

The application entry point Reset_Handler hands control to.

The USB clock, pins, console, and the SD card all come up before the kernel so the worker only deals with USB stack bring-up.

Precondition
Reset_Handler copied .data and zeroed .bss.
SystemInit set VTOR, FPU, priority grouping.
Postcondition
On clean entry the CPU stays in tx_kernel_enter forever.
On any HAL init failure the function halts in WFI.
Note
Single entry point; not re-entrant.
Since
0.1.0

Definition at line 415 of file main.c.

References ra8_isr_globals_enable(), sdmsc_panic_halt(), and sdmsc_setup_or_halt().

◆ sdmsc_card_up()

ra8_err_t sdmsc_card_up ( uint32_t pclka_hz)
staticnodiscard

Bring the live SD card up and latch its full CSD capacity.

Routes the Pmod2 pins + opens SCI0 Simple-SPI through the ra8_sdmmc_spi_transport_sci factory, runs the SD identification sequence (ra8_sdmmc_spi_init: CMD0/CMD8/ACMD41/CMD58/CMD9, then the clock escalates to data speed), and stores the 512-byte block count in s_usb_msc_sdcard_blocks. Prints the card banner on success and the FAIL diagnostic on any failing step. Never writes the card here.

Returns
ra8_err_t verdict.
Return values
k_ra8_okCard enumerated; the capacity latch is non-zero.
(other)First failing transport / identification step.
Precondition
ra8_cgc_init ran and pclka_hz is the live PCLKA rate.
A card is seated in the Pmod2 slot (else this reports the error).
Postcondition
On success s_usb_msc_sdcard_blocks holds the card capacity.
On failure s_dbg_sd_err records the error and the latch stays 0.
Parameters
[in]pclka_hzLive PCLKA rate (Hz) feeding the SCI baud divider.
Note
Boot context; runs once before the kernel starts.
Since
0.1.0

Definition at line 226 of file main.c.

References k_ra8_board_pmod2_spi_cipo, k_ra8_board_pmod2_spi_copi, k_ra8_board_pmod2_spi_cs, k_ra8_board_pmod2_spi_sck, k_ra8_ok, k_sdmsc_sd_spi_channel, ra8_sdmmc_spi_get_capacity(), ra8_sdmmc_spi_init(), ra8_sdmmc_spi_transport_sci(), s_dbg_sd_err, s_usb_msc_sdcard_blocks, sdmsc_print_card_banner(), and sdmsc_print_fail().

Referenced by sdmsc_setup_or_halt().

◆ sdmsc_panic_halt()

void sdmsc_panic_halt ( void )
static

Halt forever in WFI – panic stop on init failure.

Last-resort stop; only a debugger or reset recovers.

Precondition
Called only after a fatal boot error.
Interrupts may be in any state.
Postcondition
CPU is parked.
No further code runs.
Note
Not reachable post-boot.
Since
0.1.0

Definition at line 155 of file main.c.

Referenced by main(), sdmsc_route_usb_or_halt(), and sdmsc_setup_or_halt().

◆ sdmsc_print_card_banner()

ra8_err_t sdmsc_print_card_banner ( uint32_t blocks)
staticnodiscard

Print "usb_msc_sdcard: card <N> blocks (<M> MiB)" at boot.

Records what the LUN is about to expose; the MiB figure is the block count divided by k_sdmsc_blocks_per_mib.

Parameters
[in]blocksCSD-derived capacity in 512-byte blocks.
Returns
ra8_err_t propagated from the SCI helpers.
Return values
k_ra8_okThe banner is queued.
Precondition
SCI8 init already ran.
blocks is the live card capacity (non-zero).
Postcondition
One ASCII banner line is in the SCI8 TX FIFO.
No other state changes.
Note
Blocking polled TX.
Since
0.1.0

Definition at line 181 of file main.c.

References k_ra8_ok, k_sdmsc_blocks_per_mib, sdmsc_print(), and sdmsc_print_dec().

Referenced by sdmsc_card_up().

◆ sdmsc_route_usb_or_halt()

void sdmsc_route_usb_or_halt ( void )
static

Route the four USB-FS pins for the device role.

P4_07 VBUS sense, P5_00 VBUSEN GPIO LOW (else peripheral routing forces host VBUSEN and blocks device enum), P8_14/P8_15 data.

Precondition
IOPORT module is reachable.
Called once from sdmsc_setup_or_halt.
Postcondition
FS pins carry the device role.
VBUSEN idles LOW.
Note
Panic-halts on any routing failure.
Since
0.1.0

Definition at line 275 of file main.c.

References k_ra8_level_low, k_ra8_ok, k_ra8_psel_usb_fs, k_sdmsc_pin_fs_dm, k_sdmsc_pin_fs_dp, k_sdmsc_pin_fs_vbus, k_sdmsc_pin_fs_vbusen, ra8_gpio_output_init(), ra8_pfs_route_peripheral(), and sdmsc_panic_halt().

Referenced by sdmsc_setup_or_halt().

◆ sdmsc_setup_or_halt()

void sdmsc_setup_or_halt ( void )
static

Bring CGC + USBFS clock + SysTick + SCI8 + LEDs + SD + pins up.

USBFS needs the 48 MHz PLL2 reference. SCI8 is the J-Link OB CDC console at 115200. The SD card is enumerated pre-kernel (its capacity sizes the MSC LUN); a missing card prints FAIL and leaves the capacity latch 0 – the worker then refuses to attach, but the board stays alive for diagnostics.

Precondition
Reset_Handler finished C runtime init.
SystemInit has run.
Postcondition
Console works; USB-FS pins and clock are live.
s_usb_msc_sdcard_blocks reflects the card probe.
Note
Panic-halts on infrastructure failure; called once from main.
Since
0.1.0

Definition at line 309 of file main.c.

References k_ra8_board_led1, k_ra8_board_led2, k_ra8_clock_id_cpuclk0, k_ra8_clock_id_pclka, k_ra8_ok, k_sdmsc_baud, ra8_board_led_init(), ra8_board_uart_console_init(), ra8_cgc_get_clock_hz(), ra8_cgc_init(), ra8_cgc_usbfs_clock_enable(), ra8_time_init(), sdmsc_card_up(), sdmsc_panic_halt(), and sdmsc_route_usb_or_halt().

Referenced by main().

◆ SysTick_Handler()

void SysTick_Handler ( void )

Service the SysTick exception selected by the linked application.

Service one SysTick event for the core timebase.

Service one SysTick event for the core timebase.

Resolves to the weak core timebase handler unless a strong RTOS or application handler overrides it. The vector table references the selected implementation without owning its subsystem policy.

Precondition
Entered for a SysTick exception with a valid exception frame.
The selected handler's timebase or scheduler state is initialised.
Postcondition
The selected implementation has processed one SysTick event.
The vector table itself remains unchanged.
Note
Runs in handler mode; thread-safety follows the selected implementation.
Since
0.1.0

The weak firmware implementation advances the millisecond counter, then services linked ThreadX and USB hooks when their weak symbols and readiness state permit. The host-test implementation advances only the counter. An application may replace either weak definition with a strong handler.

Precondition
The handler is entered for one SysTick event or a host-test equivalent.
On target, ra8_time_init() configured the SysTick period.
Postcondition
s_tick_ms has advanced by exactly one.
Optional subsystem hooks run only when linked and ready.
Note
IRQ-safe; the weak symbol may be overridden by an application handler.
Since
0.1.0

Service the SysTick exception selected by the linked application.

The weak firmware implementation advances the millisecond counter, then services linked ThreadX and USB hooks when their weak symbols and readiness state permit. The host-test implementation advances only the counter. An application may replace either weak definition with a strong handler.

Precondition
The handler is entered for one SysTick event or a host-test equivalent.
On target, ra8_time_init() configured the SysTick period.
Postcondition
s_tick_ms has advanced by exactly one.
Optional subsystem hooks run only when linked and ready.
Note
IRQ-safe; the weak symbol may be overridden by an application handler.
Since
0.1.0

Service the SysTick exception selected by the linked application.

Precondition
Called from exception context (IPSR == 15).
_tx_initialize_low_level has programmed SysTick.
Postcondition
One ThreadX tick elapsed; PendSV may be pending.

Definition at line 92 of file main.c.

References _tx_timer_interrupt(), ra8_time_on_tick(), s_tx_kernel_up, and ux_dcd_ra8_usb_irq_reenable().

◆ tx_application_define()

VOID tx_application_define ( VOID * first_unused_memory)

ThreadX application-define hook.

Spawns the device worker.

One worker at priority 8 (above the USBX class threads it creates). Sets s_tx_kernel_up so SysTick may feed ThreadX from here on.

Parameters
[in]first_unused_memorySentinel (unused; static stacks).
Precondition
Called from tx_kernel_enter after scheduler init.
Static stacks are reserved at file scope.
Postcondition
One auto-start worker thread is queued.
s_tx_kernel_up is true.
Note
Called once at boot; not thread-safe.
Since
0.1.0

Definition at line 382 of file main.c.

References k_sdmsc_dev_priority, k_sdmsc_thread_stack, s_device_stack, s_device_thread, s_device_thread_name, s_tx_kernel_up, sdmsc_device_worker(), TX_AUTO_START, TX_NO_TIME_SLICE, and tx_thread_create.

Variable Documentation

◆ k_sdmsc_pin_fs_dm

const ra8_port_pin_t k_sdmsc_pin_fs_dm = (ra8_port_pin_t)k_ra8_board_usbfs_pin_dm
static

USBFS D- (P8_15).

Definition at line 116 of file main.c.

Referenced by sdmsc_route_usb_or_halt().

◆ k_sdmsc_pin_fs_dp

const ra8_port_pin_t k_sdmsc_pin_fs_dp = (ra8_port_pin_t)k_ra8_board_usbfs_pin_dp
static

USBFS D+ (P8_14).

Definition at line 113 of file main.c.

Referenced by sdmsc_route_usb_or_halt().

◆ k_sdmsc_pin_fs_vbus

const ra8_port_pin_t k_sdmsc_pin_fs_vbus = (ra8_port_pin_t)k_ra8_board_usbfs_pin_vbus
static

USBFS VBUS sense pin (P4_07, PSEL = usb_fs).

Definition at line 107 of file main.c.

Referenced by sdmsc_route_usb_or_halt().

◆ k_sdmsc_pin_fs_vbusen

const ra8_port_pin_t k_sdmsc_pin_fs_vbusen = (ra8_port_pin_t)k_ra8_board_usbfs_pin_vbusen
static

USBFS VBUSEN (P5_00) – GPIO LOW for the device role.

Definition at line 110 of file main.c.

Referenced by sdmsc_route_usb_or_halt().

◆ s_dbg_sd_err

volatile uint32_t s_dbg_sd_err
static

SD bring-up result: 0 = card enumerated OK, else the error code.

Definition at line 123 of file main.c.

Referenced by microsd_sd_snapshot(), and sdmsc_card_up().

◆ s_device_stack

UCHAR s_device_stack[k_sdmsc_thread_stack]
static

Stack backing storage for s_device_thread.

Since
0.1.0

Definition at line 363 of file main.c.

◆ s_device_thread

TX_THREAD s_device_thread
static

ThreadX TCB for the USBX device-side worker thread.

Note
Single-writer (worker only).
Since
0.1.0

Definition at line 356 of file main.c.

◆ s_tx_kernel_up

volatile bool s_tx_kernel_up = false
static

Set in tx_application_define; gates ThreadX tick delivery.

main() starts SysTick before tx_kernel_enter and the SD card bring-up window is long (the ACMD41 ready-poll takes ms), so the tick fires pre-kernel; feeding _tx_timer_interrupt into ThreadX's zeroed timer state bus-faults. Gate it until the kernel runs.

Note
Single-writer (tx_application_define); read by the ISR.
Warning
Do not set manually – the kernel must own its timer state.
Since
0.1.0

Definition at line 89 of file main.c.

◆ s_usb_msc_sdcard_blocks

volatile uint32_t s_usb_msc_sdcard_blocks

Live SD card capacity in 512-byte blocks (0 = no card).

Defined in main.c and stamped once during the pre-kernel SD bring-up from ra8_sdmmc_spi_get_capacity (CSD-derived). Read by the worker in usb_msc_sdcard_steps.c to size the MSC LUN and by the media callbacks to bounds-check every SCSI request.

Note
Single-writer at boot; read-only afterwards.
Warning
Do not modify after the USBX class registers – the LUN geometry is latched from this value.
Since
0.1.0

Stamped here once during the pre-kernel SD bring-up from ra8_sdmmc_spi_get_capacity (CSD-derived) and consumed by the worker + media callbacks in usb_msc_sdcard_steps.c.

Note
Single-writer at boot; read-only afterwards.
Warning
Do not modify after the USBX class registers – the LUN geometry is latched from this value.
Since
0.1.0

Definition at line 136 of file main.c.

Referenced by sdmsc_card_up(), sdmsc_class_register(), sdmsc_device_worker(), sdmsc_msc_read(), sdmsc_msc_write(), and sdmsc_print_ready().