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

USB Audio Class 1.0 device-mode smoke test for EK-RA8D2 (USB-FS, 48 kHz / 16-bit / stereo iso-IN sine generator). More...

#include <stdint.h>
#include "ra8_attributes.h"
#include "ra8_board_ek_ra8d2.h"
#include "ra8_boot_entry.h"
#include "ra8_cgc.h"
#include "ra8_err.h"
#include "ra8_isr.h"
#include "ra8_nsc_comms.h"
#include "ra8_time.h"
#include "ra8_usb.h"
#include "ra8_usb_paud.h"
Include dependency graph for main.c:

Go to the source code of this file.

Enumerations

enum  usb_audio_config_t : uint32_t {
  k_usb_audio_baud = 115200U ,
  k_usb_audio_log_period = 1000U ,
  k_usb_audio_idle_step_ms = 1U
}
 Numeric configuration constants for the demo. More...
enum  usb_audio_format_t : uint32_t {
  k_usb_audio_sample_rate_hz = 48000U ,
  k_usb_audio_channels = 2U ,
  k_usb_audio_bytes_per_samp = 2U ,
  k_usb_audio_lut_samples = 48U ,
  k_usb_audio_lut_bytes = (uint32_t)(48U * 2U * 2U)
}
 Audio format constants used to seed the format shadow. More...
enum  usb_audio_volume_t : int16_t { k_usb_audio_volume_0_db = 0 }
 Q8.8-format volume constant (USB Audio 1.0 sec 5.2.2.4.3.2). More...

Functions

static void internal_usb_audio_panic_halt (void)
 Park the CPU forever in WFI on fatal init failure.
static void internal_usb_audio_log (const char *s)
 Send a NUL-terminated ASCII line over SCI8 (best-effort).
static void internal_usb_audio_u32_to_ascii (uint32_t value, char *buf, uint32_t cap)
 Convert a uint32_t to ASCII decimal in caller-supplied buffer.
static void internal_usb_audio_clocks_or_halt (uint32_t *cpuclk0_hz)
 Bring up clocks, time, GPIO.
static void internal_usb_audio_usb_or_halt (void)
 Bring up USB-FS pin mux + UAC1 class layer + format/volume shadows.
static void internal_usb_audio_setup_or_halt (void)
 Bring up CGC + SysTick + GPIO + SCI8 + USB-FS + UAC1.
static ra8_err_t internal_usb_audio_send_one_frame (void)
 Push one iso frame (1 ms = 48 stereo samples) on PIPE1.
static void internal_usb_audio_log_frames (uint32_t frames)
 Emit one log line announcing the running frame count.
void main (void)
 Application entry.

Variables

static const uint8_t s_usb_audio_sine_lut [k_usb_audio_lut_bytes]
 1 kHz sine LUT, 48 stereo 16-bit samples per cycle.

Detailed Description

USB Audio Class 1.0 device-mode smoke test for EK-RA8D2 (USB-FS, 48 kHz / 16-bit / stereo iso-IN sine generator).

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

Brings the chip up via ra8_cgc_init(), routes the four USB-FS pins to the EK-RA8D2 v1 USB-FS receptacle (J11), brings the device-mode UAC1 stack up via the NSC USB veneers + the ra8_usb_paud class layer, and feeds a precomputed 1 kHz sine wave (48-sample LUT – exactly one cycle at 48 kHz) into the iso-IN endpoint every USB-FS 1 ms frame so the host enumerates the gadget as a UAC1 microphone / headset and renders the test tone.

USB Audio Class 1.0 sec 2.2.5 "Format Type Descriptor" (Type-I PCM 16-bit, 2 channels, 48 kHz) and sec 5.2.3.2.3.1 "Sampling Frequency Control" frame the descriptor + class-request behaviour the driver synthesises around the LUT below.

Pinout (USB-FS, EK-RA8D2 v1)

Net Pin PFS PSEL Notes
USB_FS_VBUS P4_07 k_ra8_psel_usb_fs (0x13) VBUS sense (input).
USB_FS_VBUSEN P5_00 k_ra8_psel_usb_fs (0x13) VBUS-enable drive (output).
USB_FS_DP P8_14 k_ra8_psel_usb_fs (0x13) D+ data line (analog buffer).
USB_FS_DM P8_15 k_ra8_psel_usb_fs (0x13) D- data line (analog buffer).

Pin assignments are copied verbatim from examples/usb_cdc_echo because the EK-RA8D2 v1 board only routes USB-FS to one pad set.

Sequence

  1. ra8_cgc_init() – standard FSP-quickstart clock tree.
  2. ra8_time_init(cpuclk0_hz) for ra8_delay_ms.
  3. ra8_pfs_route_peripheral for the four USB-FS pins.
  4. ra8_gpio_output_init(k_ra8_pin_led1, low) for the heartbeat.
  5. ra8_board_uart_console_init (SCI8, PD_02 / PD_03) at 115200 8N1 for log output.
  6. ra8_nsc_usb_init(k_ra8_usb_speed_fs) – secure veneer to ra8_usb_device_init.
  7. ra8_usb_paud_init(k_ra8_usb_speed_fs) – iso-IN PIPE1 / iso-OUT PIPE2 configured at the FS default 192-byte max-packet (48 kHz stereo 16-bit per USB Audio 1.0 sec 3.7.1).
  8. ra8_usb_paud_set_format – explicit 48 kHz / 2 ch / 16-bit.
  9. ra8_usb_paud_set_volume(0) – 0 dB feature-unit volume (USB Audio 1.0 sec 5.2.2.4.3.2 "Volume Control" Q8.8 = 0).

ra8_nsc_usb_attach(k_ra8_usb_speed_fs, true) – raise D+ pull-up so the host begins enumeration.

  1. Loop: feed 48 samples (one full cycle of the 1 kHz sine LUT) to ra8_usb_paud_send_frame per iteration, log every 1000 frames over SCI8, and toggle LED1 once per log line.
Architectural ring
[Ring 6 / APP] {World: S} – application-layer code that runs in the Secure world.
Author
Brighton Sikarskie
Date
2026-04-29
Since
0.1.0

Definition in file main.c.

Enumeration Type Documentation

◆ usb_audio_config_t

enum usb_audio_config_t : uint32_t

Numeric configuration constants for the demo.

Every literal used by the bring-up path lives here so the magic- number lint never sees a bare integer. The BSP console uses the on-board J-Link OB CDC bridge pins (PD_02 / PD_03) for log output.

Enumerator
k_usb_audio_baud 

J-Link OB CDC log baud.

k_usb_audio_log_period 

Frames per SCI8 log line.

k_usb_audio_idle_step_ms 

USB-FS frame period.

Definition at line 90 of file main.c.

◆ usb_audio_format_t

enum usb_audio_format_t : uint32_t

Audio format constants used to seed the format shadow.

USB Audio 1.0 sec 2.2.5 "Format Type Descriptor" – Type-I PCM, 16-bit sub-frame, 2 channels, 48 kHz. The LUT below stores 48 stereo samples (one full cycle of a 1 kHz tone), which is exactly the FS iso payload of one microframe.

Enumerator
k_usb_audio_sample_rate_hz 

Sample rate (Hz).

k_usb_audio_channels 

Stereo.

k_usb_audio_bytes_per_samp 

16-bit.

k_usb_audio_lut_samples 

48 stereo samples per frame.

k_usb_audio_lut_bytes 

48 samples * 2 ch * 2 bytes = 192 B.

Definition at line 106 of file main.c.

◆ usb_audio_volume_t

enum usb_audio_volume_t : int16_t

Q8.8-format volume constant (USB Audio 1.0 sec 5.2.2.4.3.2).

Enumerator
k_usb_audio_volume_0_db 

0 dB attenuation, full scale.

Definition at line 118 of file main.c.

Function Documentation

◆ internal_usb_audio_clocks_or_halt()

void internal_usb_audio_clocks_or_halt ( uint32_t * cpuclk0_hz)
static

Bring up clocks, time, GPIO.

Panic-halts on any failure.

Initializes the CGC, reads CPUCLK0, starts the timebase, and claims LED1 in the dependency order required by the board support package.

Parameters
[out]cpuclk0_hzReceives CPUCLK0 rate.
Precondition
cpuclk0_hz non-null.
Reset initialization has completed with interrupts still controlled.
Postcondition
CGC + SysTick + LED1 GPIO are usable.
*cpuclk0_hz contains the rate used to configure the timebase.
Note
Any driver error is fail-stop and leaves the CPU parked in WFI.
Since
0.1.0

Definition at line 307 of file main.c.

References internal_usb_audio_panic_halt(), k_ra8_board_led1, k_ra8_clock_id_cpuclk0, k_ra8_ok, ra8_board_led_init(), ra8_cgc_get_clock_hz(), ra8_cgc_init(), RA8_INTERNAL, and ra8_time_init().

Referenced by internal_usb_audio_setup_or_halt().

◆ internal_usb_audio_log()

void internal_usb_audio_log ( const char * s)
static

Send a NUL-terminated ASCII line over SCI8 (best-effort).

Measures the string locally and forwards exactly its payload bytes to the BSP console without a terminator or dynamic allocation.

Parameters
[in]sASCII string (NUL-terminated). May be nullptr.
Precondition
ra8_board_uart_console_init() succeeded for the BSP console.
If non-NULL, s points to a readable NUL-terminated byte sequence.
Postcondition
Bytes have been polled out of TXD8 (or silently discarded on backpressure – this is logging only).
A NULL argument performs no console write.
Note
Console errors are intentionally non-fatal for diagnostic messages.
Since
0.1.0

Definition at line 227 of file main.c.

References ra8_board_uart_console_write(), and RA8_INTERNAL.

Referenced by internal_usb_audio_log_frames(), and main().

◆ internal_usb_audio_log_frames()

void internal_usb_audio_log_frames ( uint32_t frames)
static

Emit one log line announcing the running frame count.

Formats the counter in a bounded stack buffer, emits three string fragments, and toggles the activity LED once.

Parameters
[in]framesFrame counter snapshot.
Precondition
SCI8 is initialized.
LED1 was initialized by the clock/setup stage.
Postcondition
One ASCII line written to SCI8 and LED1 toggled once.
The caller's frame counter is not modified.
Note
Console and LED errors are diagnostic-only and intentionally ignored.
Since
0.1.0

< Decimal buffer for the frame counter.

Definition at line 440 of file main.c.

References internal_usb_audio_log(), internal_usb_audio_u32_to_ascii(), k_ra8_board_led1, ra8_board_led_toggle(), and RA8_INTERNAL.

Referenced by main().

◆ internal_usb_audio_panic_halt()

void internal_usb_audio_panic_halt ( void )
static

Park the CPU forever in WFI on fatal init failure.

Re-enters WFI indefinitely so the failing boot context remains available to a debugger without executing additional peripheral accesses.

Precondition
Called only after a fatal error in boot.
No safe continuation path remains for the current initialization.
Postcondition
CPU is parked; only a debugger or external reset wakes it.
USB and console state remain unchanged after entry.
Note
Logging is avoided because the console itself may have failed.
Since
0.1.0

Definition at line 202 of file main.c.

References RA8_INTERNAL.

Referenced by internal_usb_audio_clocks_or_halt(), internal_usb_audio_setup_or_halt(), internal_usb_audio_usb_or_halt(), and main().

◆ internal_usb_audio_send_one_frame()

ra8_err_t internal_usb_audio_send_one_frame ( void )
staticnodiscard

Push one iso frame (1 ms = 48 stereo samples) on PIPE1.

Submits the immutable interleaved stereo LUT as one bounded UAC1 isochronous frame and returns the class driver's exact status.

Returns
Error code from ra8_usb_paud_send_frame.
Return values
k_ra8_okBytes queued onto iso-IN.
k_ra8_err_invalid_stateDriver not initialized.
k_ra8_err_invalid_argLUT byte count out of range.
Precondition
ra8_usb_paud_init succeeded.
The host-selected audio format matches the fixed LUT geometry.
Postcondition
192 bytes of LUT have been queued onto PIPE1.
On error the LUT and caller-owned USB state are not modified here.
Note
Retry policy belongs to the outer streaming loop.
Since
0.1.0

Definition at line 418 of file main.c.

References k_usb_audio_lut_bytes, RA8_INTERNAL, ra8_usb_paud_send_frame(), and s_usb_audio_sine_lut.

Referenced by main().

◆ internal_usb_audio_setup_or_halt()

void internal_usb_audio_setup_or_halt ( void )
static

Bring up CGC + SysTick + GPIO + SCI8 + USB-FS + UAC1.

Panic-halts on any failure.

Mirrors usb_cdc_echo setup but swaps CDC for the UAC1 audio class. Split into clocks, console, and USB stages so each helper stays inside the NASA-rule-4 line budget.

Precondition
Reset_Handler has initialized data and BSS.
The application is still in single-threaded boot context.
Postcondition
Clocks, LED1, console, and USB audio are initialized on success.
Any setup error parks the CPU before the streaming loop starts.
Note
The local clock-rate value is passed only to the timebase setup path.
Since
0.1.0

Definition at line 386 of file main.c.

References internal_usb_audio_clocks_or_halt(), internal_usb_audio_panic_halt(), internal_usb_audio_usb_or_halt(), k_ra8_ok, k_usb_audio_baud, ra8_board_uart_console_init(), and RA8_INTERNAL.

Referenced by main().

◆ internal_usb_audio_u32_to_ascii()

void internal_usb_audio_u32_to_ascii ( uint32_t value,
char * buf,
uint32_t cap )
static

Convert a uint32_t to ASCII decimal in caller-supplied buffer.

Builds digits in reverse order in a fixed local array and copies as many as fit, always terminating a nonzero-capacity destination.

Parameters
[in]valueValue to format.
[out]bufDestination buffer (>= 11 bytes incl. NUL).
[in]capCapacity of buf in bytes.
Precondition
buf != nullptr.
cap >= 11.
Postcondition
buf holds a NUL-terminated decimal representation of value.
No bytes at or beyond buf[cap] are accessed.
Note
Invalid zero-capacity input returns without writing; normal callers satisfy the documented eleven-byte capacity contract.
Since
0.1.0

< Dec radix.

< Maximum digits.

Definition at line 259 of file main.c.

References k_dec_radix, and RA8_INTERNAL.

Referenced by internal_usb_audio_log_frames().

◆ internal_usb_audio_usb_or_halt()

void internal_usb_audio_usb_or_halt ( void )
static

Bring up USB-FS pin mux + UAC1 class layer + format/volume shadows.

Pin-mux first, then ra8_nsc_usb_init to release the MSTP gate, then ra8_usb_paud_init to install the iso-IN / iso-OUT pipes, then ra8_usb_paud_set_format / ra8_usb_paud_set_volume to seed the format + volume shadows, then ra8_nsc_usb_attach to raise the D+ pull-up so the host begins enumeration.

Precondition
Clocks + SCI8 already initialized.
USB device pins are available to the board support package.
Postcondition
USB-FS device-mode UAC1 endpoint is live.
Format and volume shadows contain the demo's fixed audio settings.
Note
D+ attachment is deliberately the final operation so the host cannot enumerate a partially configured audio class.
Since
0.1.0

Definition at line 343 of file main.c.

References internal_usb_audio_panic_halt(), k_ra8_ok, k_ra8_usb_speed_fs, k_usb_audio_bytes_per_samp, k_usb_audio_channels, k_usb_audio_sample_rate_hz, k_usb_audio_volume_0_db, ra8_board_usbhs_device_init(), RA8_INTERNAL, ra8_nsc_usb_attach(), ra8_usb_paud_init(), ra8_usb_paud_set_format(), and ra8_usb_paud_set_volume().

Referenced by internal_usb_audio_setup_or_halt().

◆ main()

void main ( void )

Application entry.

The application entry point Reset_Handler hands control to.

Brings up CGC + USB-FS + UAC1, then enters the iso-IN feed loop forever.

Precondition
Reset_Handler has copied .data and zeroed .bss.
SystemInit has set VTOR, FPU, and priority grouping.
Postcondition
On clean entry the CPU stays in the iso-IN feed loop forever.
On any HAL init failure the function halts in WFI.
Since
0.1.0

Definition at line 464 of file main.c.

References internal_usb_audio_log(), internal_usb_audio_log_frames(), internal_usb_audio_panic_halt(), internal_usb_audio_send_one_frame(), internal_usb_audio_setup_or_halt(), k_ra8_ok, k_usb_audio_idle_step_ms, k_usb_audio_log_period, ra8_delay_ms(), and ra8_isr_globals_enable().

Variable Documentation

◆ s_usb_audio_sine_lut

const uint8_t s_usb_audio_sine_lut[k_usb_audio_lut_bytes]
static

1 kHz sine LUT, 48 stereo 16-bit samples per cycle.

Each entry is interleaved L/R 16-bit little-endian (USB Audio 1.0 sec 2.2.5 Format Type-I sample byte order). The amplitude is 0x4000 (half full-scale) so the host can downstream-mix without clipping. Hand-computed with sin(2*pi*n/48) at integer step 1 of 48; floating-point math is forbidden in this firmware so the LUT is precomputed and stored in MRAM as constant rodata.

Index 0 = sin(0), 12 = sin(pi/2) = +0x4000, 24 = sin(pi) = 0, 36 = sin(3pi/2) = -0x4000, ... back to 0 at index 48.

Definition at line 136 of file main.c.

Referenced by internal_usb_audio_send_one_frame().