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

PWM Delay Generation (PDG) bring-up + delay-program demo (EK-RA8D2). 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_check.h"
#include "ra8_err.h"
#include "ra8_isr.h"
#include "ra8_mstp.h"
#include "ra8_pdg.h"
#include "ra8_time.h"
Include dependency graph for main.c:

Go to the source code of this file.

Enumerations

enum  pdg_demo_config_t : uint32_t {
  k_pdg_demo_baud = 115200U ,
  k_pdg_demo_period_ms = 1000U
}
 Compile-time settings. More...
enum  pdg_demo_chan_t : uint8_t {
  k_pdg_demo_channel = 0U ,
  k_pdg_demo_chan_mask = 0x01U ,
  k_pdg_demo_delay_code = 0x40U
}
 PDG channel + delay programmed by this demo. More...

Functions

static void internal_pdg_demo_panic_halt (void)
 Park the processor after a fatal initialization failure.
static void internal_pdg_demo_setup_or_halt (void)
 Bring CGC, SysTick, SCI8, LEDs, and MSTP support up.
static ra8_err_t internal_pdg_demo_configure (void)
 Bring up the PDG DLL on channel 0 and programme a delay code.
static ra8_err_t internal_pdg_demo_sample (uint8_t *out_ok)
 Read the PDG status and fold the bring-up into the verdict.
void main (void)
 The application entry point Reset_Handler hands control to.

Variables

static const char * s_tag = "pdg_demo"
 Diagnostic / log tag.
static const uint8_t s_pdg_demo_ok_msg [] = "pdg: dll=on ch0=on delay=0x40 cfg=ok\r\n"
 Output line tags.
static const uint8_t s_pdg_demo_bad_msg [] = "pdg: cfg=BAD\r\n"
volatile uint32_t g_pdg_cfg_ok = 0U
 1 when the DLL + channel + delay read back as configured.
volatile uint32_t g_pdg_delay_readback = 0U
 Last delay code read back from the PDG temporary register.
volatile uint32_t g_pdg_dll = 0U
 1 when GTDLYCR.DLLEN reads back enabled.
volatile uint32_t g_pdg_heartbeat = 0U
 Bumps once per main-loop pass – liveness for headless probes.

Detailed Description

PWM Delay Generation (PDG) bring-up + delay-program demo (EK-RA8D2).

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

The PDG block adds a fine, DLL-derived delay (DLY[6:0], 1/128 of the GPT core-clock period per step in the 80..160 MHz band) to the rising and falling edges of a GPT32 channel's GTIOCnA / GTIOCnB outputs, so a PWM edge can be nudged with sub-nanosecond resolution. This demo brings the PDG DLL up on channel 0, programs a mid-range delay code (0x40) on the GTIOC0A rising edge, and reports the configured bring-up state.

Bring-up: CGC + SysTick + SCI8 + LEDs + MSTP. Once a second the loop reads the PDG status and reports "pdg: dll=on ch0=on delay=0x40 cfg=ok\r\n" on the J-Link OB CDC channel. LED1 toggles while the configuration reads back clean; LED2 toggles otherwise.

Bare EK-RA8D2 only – no shields or external transceivers.

Note
What headless validation can and cannot show. Validated on a real EK-RA8D2 (2026-06-28): the DLL locks and channel 0 reads back powered and un-bypassed (cfg=ok). The delay code register GTDLYRnA is write- staged but is not read-exposed on silicon – it returns its 0x0000 reset value to both firmware and a J-Link debugger, and FSP never reads it back – so the verdict gates on the bring-up state, not on a delay read-back. The PDG's only other observable, the timing shift of a GPT output edge, needs a logic analyzer / oscilloscope and a running GPT32_0 PWM source to measure (out of scope; see README.md). tools/ra8_emulator shadows GTDLYRnA as plain R/W, which is why a delay read-back appears to work there but not on silicon.
Since
0.1.0

Definition in file main.c.

Enumeration Type Documentation

◆ pdg_demo_chan_t

enum pdg_demo_chan_t : uint8_t

PDG channel + delay programmed by this demo.

Enumerator
k_pdg_demo_channel 

PDG / GPT32 channel 0.

k_pdg_demo_chan_mask 

channel_mask bit 0.

k_pdg_demo_delay_code 

Mid-range DLY[6:0] code (0..7F).

Definition at line 64 of file main.c.

◆ pdg_demo_config_t

enum pdg_demo_config_t : uint32_t

Compile-time settings.

Enumerator
k_pdg_demo_baud 

SCI8 baud rate.

k_pdg_demo_period_ms 

Delay between reports.

Definition at line 58 of file main.c.

Function Documentation

◆ internal_pdg_demo_configure()

ra8_err_t internal_pdg_demo_configure ( void )
staticnodiscard

Bring up the PDG DLL on channel 0 and programme a delay code.

Configures the 80..160 MHz FRANGE band, enables PDG channel 0, then writes a mid-range delay (0x40) onto the GTIOC0A rising edge. The code lands in the PDG temporary register and would propagate to the live delay on the next GPT overflow/underflow once a GPT32_0 PWM source is running (out of scope here – see the bench plan).

MC/DC:
Single decision err != k_ra8_ok per call – no compound condition.
Returns
ra8_err_t from ra8_pdg_init / ra8_pdg_set_delay.
Return values
k_ra8_okThe DLL and channel accepted the requested delay setup.
Precondition
CGC + MSTP up; IRQs masked or single-threaded init.
The GPT32 clock falls within the selected PDG frequency range.
Postcondition
PDG DLL enabled, channel 0 un-bypassed, delay code staged.
A failed initialization prevents the delay write from being attempted.
Note
The staged delay becomes live only when the associated GPT updates it.
Since
0.1.0

Definition at line 188 of file main.c.

References k_pdg_demo_chan_mask, k_pdg_demo_channel, k_pdg_demo_delay_code, k_ra8_ok, k_ra8_pdg_edge_rising, k_ra8_pdg_frange_80_160_mhz, k_ra8_pdg_pin_a, RA8_INTERNAL, ra8_pdg_init(), and ra8_pdg_set_delay().

Referenced by main().

◆ internal_pdg_demo_panic_halt()

void internal_pdg_demo_panic_halt ( void )
static

Park the processor after a fatal initialization failure.

Executes wait-for-interrupt indefinitely to prevent application progress with incomplete clock, timing, console, LED, or MSTP setup.

Precondition
The caller has determined that safe initialization cannot be completed.
No foreground recovery operation remains to be performed.
Postcondition
This function does not return.
The processor remains in a low-activity wait loop.
Note
This terminal path preserves the first initialization failure state.
Since
0.1.0

Definition at line 119 of file main.c.

References RA8_INTERNAL.

Referenced by internal_pdg_demo_setup_or_halt(), and main().

◆ internal_pdg_demo_sample()

ra8_err_t internal_pdg_demo_sample ( uint8_t * out_ok)
staticnodiscard

Read the PDG status and fold the bring-up into the verdict.

Reads the staged delay for emulator visibility and the full PDG status for the silicon-observable DLL, power, and bypass verdict.

Parameters
[out]out_ok1 when the DLL is enabled and channel 0 is powered and un-bypassed (the software-observable bring-up). The delay code is staged by internal_pdg_demo_configure but is not read-exposed on silicon, so it is not part of the verdict.
MC/DC:
Decision ok = dll && powered && bypass_off (3 conditions). The host test supplies N+1 = 4 vectors, varying each condition independently.
Returns
ra8_err_t from the status accessors.
Return values
k_ra8_okBoth status reads completed and out_ok was populated.
k_ra8_err_null_ptrout_ok was NULL.
Precondition
internal_pdg_demo_configure succeeded.
out_ok addresses writable storage for one verdict byte.
Postcondition
g_pdg_delay_readback / g_pdg_dll updated.
On success, out_ok contains exactly zero or one.
Note
Delay-code readback is diagnostic only because silicon does not expose it.
Since
0.1.0

Definition at line 231 of file main.c.

References ra8_pdg_status_full_t::dll_enabled, g_pdg_delay_readback, g_pdg_dll, k_pdg_demo_channel, k_ra8_ok, k_ra8_pdg_edge_rising, k_ra8_pdg_pin_a, ra8_pdg_status_full_t::per_channel_bypass_off, ra8_pdg_status_full_t::per_channel_powered, RA8_CHECK_NULL_PTR, RA8_INTERNAL, ra8_pdg_get_delay(), ra8_pdg_get_status_full(), and s_tag.

Referenced by main().

◆ internal_pdg_demo_setup_or_halt()

void internal_pdg_demo_setup_or_halt ( void )
static

Bring CGC, SysTick, SCI8, LEDs, and MSTP support up.

Initializes all PDG-demo prerequisites in dependency order and transfers to internal_pdg_demo_panic_halt on the first failure.

Precondition
The function runs during single-threaded application startup.
EK-RA8D2 board registers are accessible through the platform mapping.
Postcondition
On return, timing, console, both LEDs, and MSTP support are ready.
Any required initialization failure prevents a return to the caller.
Note
The helper applies the demo's fail-closed startup policy consistently.
Since
0.1.0

Definition at line 139 of file main.c.

References internal_pdg_demo_panic_halt(), k_pdg_demo_baud, k_ra8_board_led1, k_ra8_board_led2, k_ra8_clock_id_cpuclk0, k_ra8_ok, ra8_board_led_init(), ra8_board_uart_console_init(), ra8_cgc_get_clock_hz(), ra8_cgc_init(), RA8_INTERNAL, ra8_mstp_init(), and ra8_time_init().

Referenced by main().

◆ main()

void main ( void )

The application entry point Reset_Handler hands control to.

Returns void, not int. This is a freestanding image: there is no hosted C environment, no process and nothing to report an exit status to. ISO C fixes main at int only for a hosted implementation; for a freestanding one (C23 5.1.2.1) the startup function's name and type are implementation-defined, and this is that definition. Reset_Handler discards no value because there is none to discard, and if main ever does return, startup halts the CPU rather than resuming anything.

The firmware lane is compiled -ffreestanding (see cmake/ra8_add_app.cmake) and the flag and this signature travel together: without it both GCC and clang reject a non-int main (-Wmain / -Wmain-return-type). Do not remove one without the other.

That coupling is why the declaration sits behind __STDC_HOSTED__ == 0, which -ffreestanding sets and a hosted build does not. The guard is not defensive dressing: this header is reachable from host builds (the unit tests compile ra8_core natively), and an unguarded void main(void); makes every hosted translation unit that includes it fail with conflicting types for 'main' against its own ISO int main. The declaration therefore exists exactly where its contract does.

Hosted first-party code – everything under tests/ and tools/ – uses the ISO int main(...) contract instead, because it genuinely does run under an OS that reads the exit status. scripts/checks/check_entry_points.py holds each domain to its own contract (#707).

Declared here, once, for the same reason SystemInit is: every vector_table.c used to restate it as a local extern int32_t main(void);, sixteen copies that no compiler ever compared against the definition – and roughly thirty of them had silently drifted out of agreement with the main they called.

Precondition
Reset_Handler has copied .data and zeroed .bss.
SystemInit has configured the clock tree and VTOR.
Postcondition
Control does not return; the image runs until reset or halt.
Any value the application wanted to report has been logged, not returned.
Note
Not thread-safe; single-threaded startup context only.
Warning
Only valid while the translation unit is compiled -ffreestanding. A hosted build rejects this signature.
See also
SystemInit()
Since
0.1.0

The application entry point Reset_Handler hands control to.

Brings up CGC + BSP audio then plays blocks.

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 playback loop forever.
On any HAL init failure the function halts in WFI.
Since
0.1.0

The application entry point Reset_Handler hands control to.

Brings up CGC + GPT triple, runs sweep.

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 sweep loop forever.
On any HAL init failure the function halts in WFI.
Since
0.1.0

The application entry point Reset_Handler hands control to.

Brings up clocks + UART + RMII pins, then ThreadX.

Precondition
Reset_Handler has copied .data and zeroed .bss.
Postcondition
On clean entry the kernel runs the worker thread once.
Since
0.1.0

The application entry point Reset_Handler hands control to.

Brings up clocks + UART, then enters ThreadX.

Precondition
Reset_Handler has copied .data and zeroed .bss.
SystemInit has set VTOR, FPU, and priority grouping.
Postcondition
On clean entry the kernel runs the worker thread forever.
On any HAL init failure the function halts in WFI.
Since
0.1.0

The application entry point Reset_Handler hands control to.

Brings up LED, console, SDHI pins, then ThreadX.

Precondition
Reset_Handler has copied .data + zeroed .bss.
SystemInit has set VTOR, FPU, and priority grouping.
Postcondition
CPUCLK0 is raised to the PLL1 target before the kernel starts.
On clean entry the SD card thread runs forever.
On any HAL init failure the function halts in __WFI.
Since
0.1.0

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

The application entry point Reset_Handler hands control to.

Precondition
SystemInit set VTOR / FPU / priority grouping.

The application entry point Reset_Handler hands control to.

See file header.

Precondition
Boot init has completed.
The secure-boot library's BLXNS into NS image either failed or was skipped (the call site in ra8_trustzone_init is a no-op on host builds).
Postcondition
Diagnostic counter latched, CPU parked in a halt loop.
Function never returns.
Note
Single-threaded entry.
Since
0.1.0

The application entry point Reset_Handler hands control to.

Precondition
Reset_Handler copied .data and zeroed .bss.
SystemInit set VTOR / FPU / priority grouping.
Postcondition
On success g_eoh_chapters / g_eoh_crc hold the parsed results, the banner is emitted, and g_eoh_heartbeat advances once per frame.
On any failure g_eoh_err is non-zero and the CPU parks (no heartbeat).
Since
0.1.0

The application entry point Reset_Handler hands control to.

Precondition
Reset_Handler copied .data and zeroed .bss.
SystemInit set VTOR / FPU / priority grouping.
Postcondition
The chapters/ch0-CRC banner is emitted; the CPU then loops in WFI.
Since
0.1.0

The application entry point Reset_Handler hands control to.

Precondition
Reset_Handler copied .data and zeroed .bss.
SystemInit set VTOR / FPU / priority grouping.
Postcondition
On success the g_etoc_* result globals hold the parsed TOC values, the banner is emitted, and g_etoc_heartbeat advances once per frame.
On any failure g_etoc_err is non-zero and the CPU parks (no heartbeat).
Since
0.1.0

The application entry point Reset_Handler hands control to.

Precondition
Reset_Handler copied .data and zeroed .bss; SystemInit set VTOR/FPU.
Postcondition
The shelf scans on the panel; taps open books, browse, and read.
Since
0.1.0

The application entry point Reset_Handler hands control to.

Precondition
Reset_Handler copied .data and zeroed .bss.
SystemInit set VTOR / FPU / priority grouping.
Postcondition
The slab/arena/tile/vmem banner is emitted; the CPU then loops in WFI.
Since
0.1.0

The application entry point Reset_Handler hands control to.

Precondition
Reset_Handler copied .data and zeroed .bss.
SystemInit set VTOR / FPU / priority grouping.
Postcondition
On success the cache globals are latched and g_pc_heartbeat advances.
On any failure g_pc_err is non-zero and the CPU parks (no heartbeat).
Since
0.1.0

Definition at line 262 of file main.c.

References g_pdg_cfg_ok, g_pdg_heartbeat, internal_pdg_demo_configure(), internal_pdg_demo_panic_halt(), internal_pdg_demo_sample(), internal_pdg_demo_setup_or_halt(), k_pdg_demo_period_ms, k_ra8_board_led1, k_ra8_board_led2, k_ra8_ok, ra8_board_led_toggle(), ra8_board_uart_console_write(), ra8_delay_ms(), ra8_isr_globals_enable(), s_pdg_demo_bad_msg, and s_pdg_demo_ok_msg.

Variable Documentation

◆ g_pdg_cfg_ok

volatile uint32_t g_pdg_cfg_ok = 0U

1 when the DLL + channel + delay read back as configured.

Note
Read externally only (HIL / board emulator).
Since
0.1.0

Definition at line 80 of file main.c.

Referenced by main().

◆ g_pdg_delay_readback

volatile uint32_t g_pdg_delay_readback = 0U

Last delay code read back from the PDG temporary register.

Note
Read externally only.
Since
0.1.0

Definition at line 88 of file main.c.

Referenced by internal_pdg_demo_sample().

◆ g_pdg_dll

volatile uint32_t g_pdg_dll = 0U

1 when GTDLYCR.DLLEN reads back enabled.

Note
Read externally only.
Since
0.1.0

Definition at line 96 of file main.c.

Referenced by internal_pdg_demo_sample().

◆ g_pdg_heartbeat

volatile uint32_t g_pdg_heartbeat = 0U

Bumps once per main-loop pass – liveness for headless probes.

Note
Read externally only.
Since
0.1.0

Definition at line 104 of file main.c.

Referenced by main().

◆ s_pdg_demo_bad_msg

const uint8_t s_pdg_demo_bad_msg[] = "pdg: cfg=BAD\r\n"
static

Definition at line 72 of file main.c.

Referenced by main().

◆ s_pdg_demo_ok_msg

const uint8_t s_pdg_demo_ok_msg[] = "pdg: dll=on ch0=on delay=0x40 cfg=ok\r\n"
static

Output line tags.

Definition at line 71 of file main.c.

Referenced by main().

◆ s_tag

const char* s_tag = "pdg_demo"
static

Diagnostic / log tag.

Definition at line 55 of file main.c.