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

ULPT0-underflow wake from Software Standby (LPSCR.LPMD = 0x5). 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_elc_regs.h"
#include "ra8_err.h"
#include "ra8_isr.h"
#include "ra8_lpm.h"
#include "ra8_lpm_regs.h"
#include "ra8_time.h"
#include "ra8_ulpt.h"
Include dependency graph for main.c:

Go to the source code of this file.

Enumerations

enum  lus_const_t : uint32_t {
  k_lus_baud = 115200U ,
  k_lus_period_ticks = 0x4000U ,
  k_lus_tcstf_poll_limit = 0x100000U
}
 Demo tunables. More...
enum  lus_chan_t : uint8_t { k_lus_channel = 0U }
 ULPT channel selector. More...

Functions

static void internal_lus_panic_halt (void)
 Park the processor after an unrecoverable setup or arm failure.
static void internal_lus_ulpt_isr (void *ctx)
 ULPT0 underflow interrupt service routine.
static ra8_err_t internal_lus_wait_count_started (uint8_t channel)
 Spin until the ULPT count operation has actually started.
static void internal_lus_setup_or_halt (void)
 Bring CGC + SysTick + SCI8 + ULPT + LPM block up.
static ra8_err_t internal_lus_arm_wake (void)
 Wire the ULPT0 underflow as a Software-Standby wake source.
void main (void)
 The application entry point Reset_Handler hands control to.

Variables

static const uint8_t s_lus_boot_msg [] = "lpm_ulpt: boot\r\n"
 Boot banner emitted once before the first standby entry.
static const uint8_t s_lus_wake_msg [] = "lpm_ulpt: wake\r\n"
 Wake banner and per-underflow HIL gate string.
volatile uint32_t g_lpm_ulpt_wake_count = 0U
 Liveness counter – bumped in the ULPT0 underflow ISR.

Detailed Description

ULPT0-underflow wake from Software Standby (LPSCR.LPMD = 0x5).

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

Deep-idle foundation demo: the CPU spends almost all of its time in Software Standby (every clock domain gated except LOCO and the always-on wake detectors) and is woken purely by the on-chip Ultra-Low-Power Timer, with no off-chip crystal in the loop.

Why ULPT and not the RTC: with ULPTMR1.TCK1 = 0 the ULPT counts from ULPTLCLK – the LOCO-derived 32.768 kHz clock (HUM Table 9.2 p 320) – which keeps running through Software Standby while LOCOCR.LCSTP = 0 (HUM Table 11.3 footnote *2 p 433). LOCO is internal, so unlike the RTC alarm (which depends on the bare-board sub-clock crystal) this wake source does not rely on the intermittent SOSC.

The wake path that the earlier ULPT standby attempt was missing: on the RA8D2 a Software-Standby wake needs BOTH halves of the ICU wired, not just the WUPEN bit.

  1. ra8_isr_register(k_ra8_elc_event_ulpt0_ulpti, ...) links the ULPT0 underflow event into an ICU IELSRn slot and enables the matching NVIC line – HUM 11.6.2.1 (p 482): "corresponding IELSRn register must be set before executing a WFI instruction", and Table 11.3 footnote *28 (p 434): the interrupt "must be enabled by NVIC_ISERn".
  2. ra8_lpm_arm_wupen1_bits(k_ra8_lpm_wupen1_ulpt0u) arms the async WUPEN1.ULP0U standby-cancel detector (HUM Ch 14.2.20 p 552). ULPT0_ULPTI is a valid SSTBY cancel source per Table 11.4 (p 434).

Boot flow:

  1. CGC + SysTick + UART (SCI8) + ULPT + LPM bring-up.
  2. ra8_isr_register the ULPT0 underflow + arm WUPEN1.ULP0U.
  3. Emit boot banner "lpm_ulpt: boot\r\n".
  4. Loop: start ULPT0 (0.5 s), ra8_lpm_enter_sleep Software Standby, and on the underflow wake print "lpm_ulpt: wake\r\n".

Unlike lpm_software_standby_demo (RTC / SOSC), the wake here runs off LOCO, so the periodic "lpm_ulpt: wake" banner is a real, bench-gatable wake signal (see hil.conf).

Since
0.1.0

Definition in file main.c.

Enumeration Type Documentation

◆ lus_chan_t

enum lus_chan_t : uint8_t

ULPT channel selector.

Enumerator
k_lus_channel 

ULPT0 (its underflow is the wake source).

Definition at line 78 of file main.c.

◆ lus_const_t

enum lus_const_t : uint32_t

Demo tunables.

Enumerator
k_lus_baud 

SCI8 console baud rate.

k_lus_period_ticks 

Lus period ticks.

k_lus_tcstf_poll_limit 

Lus tcstf poll limit.

Definition at line 66 of file main.c.

Function Documentation

◆ internal_lus_arm_wake()

ra8_err_t internal_lus_arm_wake ( void )
staticnodiscard

Wire the ULPT0 underflow as a Software-Standby wake source.

Both halves of the RA8D2 wake path are required (see file header): the IELSRn/NVIC link via ra8_isr_register AND the async WUPEN1.ULP0U detector via ra8_lpm_arm_wupen1_bits.

MC/DC:
Compound decision: ra8_isr_init != ok || ra8_isr_register != ok || ra8_lpm_arm_wupen1_bits != ok. Three atomic conditions x N+1 = 4 vectors – the all-ok runtime path plus each step's error path (covered in the host unit test).
Returns
k_ra8_ok on success, else the first failing step's error.
Return values
k_ra8_okBoth NVIC event routing and asynchronous wake detection are armed.
Precondition
internal_lus_setup_or_halt has run; interrupts not yet enabled.
LPM block initialised so WUPEN writes take effect.
Postcondition
On success ULPT0_ULPTI vectors to internal_lus_ulpt_isr and WUPEN1.ULP0U is asserted.
On failure, no later arm step is attempted.
Note
Must run before global interrupts are enabled.
Since
0.1.0

Definition at line 285 of file main.c.

References internal_lus_ulpt_isr(), k_ra8_elc_event_ulpt0_ulpti, k_ra8_isr_prio_default, k_ra8_lpm_wupen1_ulpt0u, k_ra8_ok, RA8_INTERNAL, ra8_isr_init(), ra8_isr_register(), and ra8_lpm_arm_wupen1_bits().

Referenced by main().

◆ internal_lus_panic_halt()

void internal_lus_panic_halt ( void )
static

Park the processor after an unrecoverable setup or arm failure.

Enters a permanent wait loop so register and counter state remains available to a debugger without continuing into standby.

Precondition
Reset startup initialized the exception and stack environment.
The caller has determined that wake behavior cannot proceed safely.
Postcondition
Control never returns to the caller.
No further standby transition is requested by the application.
Note
An interrupt can wake one iteration, but the terminal loop resumes.
Since
0.1.0

Definition at line 127 of file main.c.

References RA8_INTERNAL.

Referenced by internal_lus_setup_or_halt(), and main().

◆ internal_lus_setup_or_halt()

void internal_lus_setup_or_halt ( void )
static

Bring CGC + SysTick + SCI8 + ULPT + LPM block up.

Same shape as lpm_software_standby_demo but swaps the RTC for the ULPT. The SCI8 J-Link console (PD02 TXD / PD03 RXD) is brought up via the EK-RA8D2 board-support console API.

Precondition
IRQs disabled (Reset_Handler default).
Reset_Handler has copied .data and zeroed .bss.
Postcondition
On success every sub-system is armed; on failure the function panic-halts and never returns.
LPM block has LPSCR.LPMD = 0 (System Active) until ra8_lpm_enter_sleep is called.
Note
Single-shot boot helper; it is not reentrant.
Since
0.1.0

Definition at line 222 of file main.c.

References internal_lus_panic_halt(), k_lus_baud, k_ra8_clock_id_cpuclk0, k_ra8_lpm_clock_loco, k_ra8_lpm_dcssmode_128us, k_ra8_lpm_ss2lp_default, k_ra8_ok, ra8_board_uart_console_init(), ra8_cgc_get_clock_hz(), ra8_cgc_init(), RA8_INTERNAL, ra8_lpm_init(), ra8_lpm_set_clock_stop(), ra8_time_init(), and ra8_ulpt_init().

Referenced by main().

◆ internal_lus_ulpt_isr()

void internal_lus_ulpt_isr ( void * ctx)
static

ULPT0 underflow interrupt service routine.

Real path: ULPT0 counter underflow -> ULPT0_ULPTI ELC event -> IELSRn link -> NVIC pend -> vector 16 + IRQ -> ra8_isr_dispatch -> here. Cancelling Software Standby is handled by the WUPEN1.ULP0U detector + the NVIC pend; this handler only records liveness. The underflow source flag (ULPTCR.TUNF) is cleared by the ra8_ulpt_stop in the main loop's re-arm step, so the ISR stays minimal and allocation-free.

Parameters
[in]ctxUnused registration context.
Precondition
Registered for k_ra8_elc_event_ulpt0_ulpti via ra8_isr_register.
ctx is the unused context registered by this application.
Postcondition
g_lpm_ulpt_wake_count has advanced by exactly one.
No wake-source or timer configuration is modified.
Note
Not re-entrant; a single ULPT channel drives it.
Since
0.1.0

Definition at line 156 of file main.c.

References g_lpm_ulpt_wake_count, and RA8_INTERNAL.

Referenced by internal_lus_arm_wake().

◆ internal_lus_wait_count_started()

ra8_err_t internal_lus_wait_count_started ( uint8_t channel)
staticnodiscard

Spin until the ULPT count operation has actually started.

HUM Section 25.4.7 (p 1214) requires confirming ULPTCR.TCSTF = 1 (count operation started) before entering a standby mode – otherwise the standby transition can gate the sync clock before the counter has begun, leaving it stalled and unable to underflow. ra8_ulpt_start only sets TSTART; this closes the gap from the application side.

Parameters
[in]channelULPT channel index (0 or 1).
Returns
k_ra8_ok once TCSTF = 1, else the status-read error or k_ra8_err_hw_timeout if the bound is reached.
Return values
k_ra8_okThe hardware confirms the count operation started.
k_ra8_err_hw_timeoutThe bounded poll expired before TCSTF asserted.
Precondition
ra8_ulpt_start has set TSTART = 1 on channel.
channel identifies an initialized ULPT instance.
Postcondition
On k_ra8_ok the ULPT counter is confirmed running.
The poll never exceeds k_lus_tcstf_poll_limit status reads.
Note
A HAL status-read error is propagated unchanged.
Since
0.1.0

Definition at line 187 of file main.c.

References k_lus_tcstf_poll_limit, k_ra8_err_hw_timeout, k_ra8_ok, k_ra8_ulpt_bit_tcstf, RA8_INTERNAL, and ra8_ulpt_get_status().

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 302 of file main.c.

References internal_lus_arm_wake(), internal_lus_panic_halt(), internal_lus_setup_or_halt(), internal_lus_wait_count_started(), k_lus_channel, k_lus_period_ticks, k_ra8_ok, k_ra8_sleep_mode_software_std, ra8_board_uart_console_write(), ra8_isr_globals_enable(), ra8_lpm_enter_sleep(), ra8_ulpt_start(), ra8_ulpt_stop(), s_lus_boot_msg, and s_lus_wake_msg.

Variable Documentation

◆ g_lpm_ulpt_wake_count

volatile uint32_t g_lpm_ulpt_wake_count = 0U

Liveness counter – bumped in the ULPT0 underflow ISR.

Incremented from internal_lus_ulpt_isr each time a ULPT0 underflow cancels Software Standby. Exposed (non-static, volatile) so a J-Link session can watch the wake cadence without the UART.

Note
Written only by the ISR; a single 32-bit load elsewhere is atomic on the Cortex-M85.
Warning
Do not modify outside the ISR.
Since
0.1.0

Definition at line 114 of file main.c.

Referenced by internal_lus_ulpt_isr().

◆ s_lus_boot_msg

const uint8_t s_lus_boot_msg[] = "lpm_ulpt: boot\r\n"
static

Boot banner emitted once before the first standby entry.

Provides a deterministic console marker that setup completed.

Note
Immutable bytes written with an explicit compile-time length.
Since
0.1.0

Definition at line 89 of file main.c.

Referenced by main().

◆ s_lus_wake_msg

const uint8_t s_lus_wake_msg[] = "lpm_ulpt: wake\r\n"
static

Wake banner and per-underflow HIL gate string.

Emitted after each standby return to expose ULPT wake liveness.

Note
Immutable bytes written with an explicit compile-time length.
Since
0.1.0

Definition at line 98 of file main.c.

Referenced by main().