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

Safe LVD / PVD VCC-monitor demo for the 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_lvd.h"
#include "ra8_mstp.h"
#include "ra8_system_regs.h"
#include "ra8_time.h"
Include dependency graph for main.c:

Go to the source code of this file.

Enumerations

enum  lvd_demo_config_t : uint32_t {
  k_lvd_demo_baud = 115200U ,
  k_lvd_demo_period_ms = 1000U ,
  k_lvd_demo_stab_ms = 1U
}
 Compile-time settings. More...

Functions

static void internal_lvd_demo_panic_halt (void)
 Park the processor after a fatal initialization failure.
static void internal_lvd_demo_setup_or_halt (void)
 Bring CGC, SysTick, console, LEDs, and MSTP support up.
static ra8_err_t internal_lvd_demo_configure (void)
 Configure PVD1 as a flags-only 2.80 V monitor (no reset / NMI).
static ra8_err_t internal_lvd_demo_sample (uint8_t *out_ok)
 Read PVD1SR once and fold it into the "healthy rail" verdict.
void main (void)
 The application entry point Reset_Handler hands control to.

Variables

static const char * s_tag = "lvd_demo"
 Diagnostic / log tag.
static const uint8_t s_lvd_demo_ok_msg [] = "lvd: pvd1 thr=2.80V mon=above det=0 ok=Y\r\n"
 Output line tags (2.80 V == k_ra8_lvd_pvdlvl_2_80v).
static const uint8_t s_lvd_demo_bad_msg [] = "lvd: pvd1 thr=2.80V mon=below ok=N\r\n"
volatile uint32_t g_lvd_ok = 0U
 1 when the last read showed VCC above Vdetm with no latched crossing.
volatile uint32_t g_lvd_mon_above = 0U
 Last PVD1SR.MON value (1 = VCC above the 2.80 V threshold).
volatile uint32_t g_lvd_det = 0U
 Last PVD1SR.DET value (1 = a Vdetm crossing was latched).
volatile uint32_t g_lvd_cfg_err = 0U
 Non-zero if ra8_lvd_channel_init rejected the configuration.
volatile uint32_t g_lvd_heartbeat = 0U
 Bumps once per main-loop pass – liveness for headless probes.

Detailed Description

Safe LVD / PVD VCC-monitor demo for the EK-RA8D2.

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

The Programmable Voltage Detection (PVD, a.k.a. LVD) block continuously compares VCC against a programmable threshold Vdetm and exposes the result through PVD1SR.MON (current level) and PVD1SR.DET (a latched crossing). This demo configures voltage monitor 1 (PVD1) in the safest possible mode – k_ra8_lvd_response_none: flags only, with no reset, NMI, or maskable interrupt wired up – so observing a brown-out can never reset or brick the board. The threshold is set low (2.80 V) so a healthy 3.3 V rail reads MON = above, DET = 0.

Bring-up: CGC + SysTick + console + LEDs. PVD1 is configured once (the PVD control registers sit behind PRCR.PRC3, so the demo unlocks that protection group around ra8_lvd_channel_init and re-locks it after). Once a second the loop reads PVD1SR and reports "lvd: pvd1 thr=2.80V mon=above det=0 ok=Y\r\n" on the J-Link OB CDC channel.

LED1 toggles on every healthy read; LED2 toggles when VCC is reported below threshold or a crossing is latched. The g_lvd_* globals mirror the result for headless probing (HIL / board emulator).

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

Note
Headless-emulator status. tools/ra8_emulator models the PVD status (board_periph_lvd.c): PVD1SR.MON reads "above threshold" with DET clear – the steady state of a healthy 3.3 V rail – so the banner reports mon=above ok=Y and the ra8_emulator_smoke.sh gate keys on it. Confirmed on a real EK-RA8D2 (2026-06-28): the analog comparator (not a synthesised status bit) drives MON above the threshold and the HIL gate is green. See README.md for details.
Since
0.1.0

Definition in file main.c.

Enumeration Type Documentation

◆ lvd_demo_config_t

enum lvd_demo_config_t : uint32_t

Compile-time settings.

Enumerator
k_lvd_demo_baud 

Console baud rate.

k_lvd_demo_period_ms 

Delay between monitor reads.

k_lvd_demo_stab_ms 

t_d(E-A) settle before 1st read.

Definition at line 62 of file main.c.

Function Documentation

◆ internal_lvd_demo_configure()

ra8_err_t internal_lvd_demo_configure ( void )
staticnodiscard

Configure PVD1 as a flags-only 2.80 V monitor (no reset / NMI).

Unlocks PRCR.PRC3 (the PVD protection group), runs the HUM Table 8.4 setup through ra8_lvd_channel_init with response = none so neither a reset nor an interrupt is ever armed, then re-locks PRCR. The digital filter is left off to avoid a LOCO dependency. g_lvd_cfg_err latches a non-zero code if the descriptor is rejected.

MC/DC:
Single decision err != k_ra8_ok – 2 vectors (accept on silicon / emulator where args are valid; reject is covered by the host test's bad-arg path). No compound condition.
Returns
ra8_err_tk_ra8_ok or the init error code.
Return values
k_ra8_okPVD1 accepted the requested flags-only configuration.
Precondition
CGC is up; IRQs masked (single-threaded init).
MSTP support has been initialized for peripheral access.
Postcondition
PRCR is re-locked on every return path.
g_lvd_cfg_err records zero or the returned error code.
Note
No reset, NMI, or maskable interrupt response is armed here.
Since
0.1.0

Definition at line 209 of file main.c.

References g_lvd_cfg_err, k_ra8_lvd_ch1, k_ra8_lvd_edge_both, k_ra8_lvd_hysteresis_lvd, k_ra8_lvd_irq_maskable, k_ra8_lvd_loco_div_8, k_ra8_lvd_negate_after_voltage, k_ra8_lvd_pvdlvl_2_80v, k_ra8_lvd_response_none, k_ra8_ok, k_ra8_prcr_unlock_pvd, RA8_INTERNAL, ra8_lvd_channel_init(), ra8_sys_prcr(), and ra8_sys_prcr_lock_all().

Referenced by main().

◆ internal_lvd_demo_panic_halt()

void internal_lvd_demo_panic_halt ( void )
static

Park the processor after a fatal initialization failure.

Executes wait-for-interrupt indefinitely so callers cannot continue with partially initialized clocks, timing, console, or board peripherals.

Precondition
The caller has determined that normal execution cannot continue safely.
No recovery action remains pending in the foreground context.
Postcondition
This function does not return.
The processor remains in a low-activity wait loop.
Note
This terminal path intentionally preserves the original failure state.
Since
0.1.0

Definition at line 138 of file main.c.

References RA8_INTERNAL.

Referenced by internal_lvd_demo_setup_or_halt(), and main().

◆ internal_lvd_demo_sample()

ra8_err_t internal_lvd_demo_sample ( uint8_t * out_ok)
staticnodiscard

Read PVD1SR once and fold it into the "healthy rail" verdict.

A read is "ok" only when VCC is above the threshold (st.above) and no crossing is currently latched (!st.crossed).

Parameters
[out]out_ok1 when the rail is healthy, else 0.
MC/DC:
Decision ok = st.above && !st.crossed (2 conditions). The host test supplies N+1 = 3 vectors: (above=1,crossed=0)->1 control, (above=0,crossed=0)->0 varies above, (above=1,crossed=1)->0 varies crossed.
Returns
ra8_err_t from ra8_lvd_get_status.
Return values
k_ra8_err_null_ptrout_ok was NULL.
Precondition
PVD1 has been configured by internal_lvd_demo_configure.
out_ok addresses writable storage for one verdict byte.
Postcondition
*out_ok is 0 or 1; g_lvd_mon_above / g_lvd_det updated.
On a status-read error, no healthy verdict is reported by the caller.
Note
The verdict requires both an above-threshold level and no latched edge.
Since
0.1.0

Definition at line 259 of file main.c.

References ra8_lvd_status_t::above, ra8_lvd_status_t::crossed, g_lvd_det, g_lvd_mon_above, k_ra8_lvd_ch1, k_ra8_ok, RA8_CHECK_NULL_PTR, RA8_INTERNAL, ra8_lvd_get_status(), and s_tag.

Referenced by main().

◆ internal_lvd_demo_setup_or_halt()

void internal_lvd_demo_setup_or_halt ( void )
static

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

Initializes each prerequisite in dependency order and transfers to internal_lvd_demo_panic_halt immediately if any required operation fails.

Precondition
The function runs during single-threaded startup before application use.
Board registers are accessible through the EK-RA8D2 platform mapping.
Postcondition
On return, timing, console, both LEDs, and MSTP support are initialized.
Any initialization failure prevents a return to the caller.
Note
The helper centralizes the fatal-on-error startup policy for this demo.
Since
0.1.0

Definition at line 158 of file main.c.

References internal_lvd_demo_panic_halt(), k_lvd_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

Definition at line 274 of file main.c.

References g_lvd_heartbeat, g_lvd_ok, internal_lvd_demo_configure(), internal_lvd_demo_panic_halt(), internal_lvd_demo_sample(), internal_lvd_demo_setup_or_halt(), k_lvd_demo_period_ms, k_lvd_demo_stab_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_lvd_demo_bad_msg, and s_lvd_demo_ok_msg.

Variable Documentation

◆ g_lvd_cfg_err

volatile uint32_t g_lvd_cfg_err = 0U

Non-zero if ra8_lvd_channel_init rejected the configuration.

Note
Read externally only.
Since
0.1.0

Definition at line 115 of file main.c.

Referenced by internal_lvd_demo_configure().

◆ g_lvd_det

volatile uint32_t g_lvd_det = 0U

Last PVD1SR.DET value (1 = a Vdetm crossing was latched).

Note
Read externally only.
Since
0.1.0

Definition at line 107 of file main.c.

Referenced by internal_lvd_demo_sample().

◆ g_lvd_heartbeat

volatile uint32_t g_lvd_heartbeat = 0U

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

Note
Read externally only.
Since
0.1.0

Definition at line 123 of file main.c.

Referenced by main().

◆ g_lvd_mon_above

volatile uint32_t g_lvd_mon_above = 0U

Last PVD1SR.MON value (1 = VCC above the 2.80 V threshold).

Note
Read externally only.
Since
0.1.0

Definition at line 99 of file main.c.

Referenced by internal_lvd_demo_sample().

◆ g_lvd_ok

volatile uint32_t g_lvd_ok = 0U

1 when the last read showed VCC above Vdetm with no latched crossing.

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

Definition at line 91 of file main.c.

Referenced by main().

◆ s_lvd_demo_bad_msg

const uint8_t s_lvd_demo_bad_msg[] = "lvd: pvd1 thr=2.80V mon=below ok=N\r\n"
static

Definition at line 83 of file main.c.

Referenced by main().

◆ s_lvd_demo_ok_msg

const uint8_t s_lvd_demo_ok_msg[] = "lvd: pvd1 thr=2.80V mon=above det=0 ok=Y\r\n"
static

Output line tags (2.80 V == k_ra8_lvd_pvdlvl_2_80v).

Definition at line 82 of file main.c.

Referenced by main().

◆ s_tag

const char* s_tag = "lvd_demo"
static

Diagnostic / log tag.

Definition at line 59 of file main.c.