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

Cortex-M85 SysTick + DWT cycle-counter timebase implementation. More...

#include "ra8_systick.h"
#include <stdint.h>
#include "ra8_attributes.h"
#include "ra8_check.h"
#include "ra8_err.h"
#include "ra8_log.h"
Include dependency graph for ra8_systick.c:

Go to the source code of this file.

Enumerations

enum  ra8_systick_reg_addr_t : uintptr_t {
  k_ra8_systick_csr = 0xE000E010UL ,
  k_ra8_systick_rvr = 0xE000E014UL ,
  k_ra8_systick_cvr = 0xE000E018UL ,
  k_ra8_dwt_demcr = 0xE000EDFCUL ,
  k_ra8_dwt_ctrl = 0xE0001000UL ,
  k_ra8_dwt_cyccnt = 0xE0001004UL
}
 Arm v8-M SCS timebase register addresses (PPB 0xE000Exxx). More...
enum  ra8_systick_bit_t : uint32_t {
  k_ra8_systick_csr_enable = 0x00000001UL ,
  k_ra8_systick_csr_tickint = 0x00000002UL ,
  k_ra8_systick_csr_clksource = 0x00000004UL ,
  k_ra8_dwt_demcr_trcena = 0x01000000UL ,
  k_ra8_dwt_ctrl_cyccntena = 0x00000001UL
}
 Control bits for SYST_CSR, DEMCR, and DWT_CTRL. More...

Functions

static volatile uint32_t * internal_systick_reg (ra8_systick_reg_addr_t addr)
 Typed pointer to a 32-bit SCS timebase register.
ra8_err_t ra8_systick_reload_for (uint32_t cpu_hz, uint32_t tick_hz, uint32_t *out_reload)
 Compute the SysTick reload for a given core clock and tick rate.
ra8_err_t ra8_systick_configure (uint32_t reload, ra8_systick_clock_source_t src, bool tick_irq)
 Arm and start SysTick with a reload value and clock source.
ra8_err_t ra8_systick_set_reload (uint32_t reload)
 Re-arm SysTick with a new reload, leaving the control bits untouched.
uint32_t ra8_systick_current_value (void)
 Read the live SysTick current-value register (SYST_CVR).
void ra8_dwt_cyccnt_enable (void)
 Enable the DWT free-running cycle counter (DWT_CYCCNT).
void ra8_dwt_cyccnt_reset (void)
 Zero the DWT cycle counter (DWT_CYCCNT).
uint32_t ra8_dwt_cyccnt_read (void)
 Sample the DWT cycle counter (DWT_CYCCNT).

Variables

static const char *const s_tag = "ra8_systick"
 Module log tag.

Detailed Description

Cortex-M85 SysTick + DWT cycle-counter timebase implementation.

Implements ::ra8_systick.h against the Arm v8-M System Control Space (PPB window 0xE000Exxx). SysTick is programmed through SYST_CSR / SYST_RVR / SYST_CVR; the DWT free-running cycle counter is unlocked via DEMCR.TRCENA, started via DWT_CTRL.CYCCNTENA, and sampled from DWT_CYCCNT.

These are Arm-architecture registers, so the inline comments reference the Arm v8-M Architecture Reference Manual (the "Arm v8-M ARM") rather than the RA8D2 Hardware User's Manual. On a host build the SCS window is backed by the fake MMIO map, so the writes are observable to unit tests and the reload / range logic runs exactly as on silicon – there is no RA8_OFF_TARGET guard around the accesses here, unlike a driver that reaches a real peripheral bus.

Since
0.1.0

Definition in file ra8_systick.c.

Enumeration Type Documentation

◆ ra8_systick_bit_t

enum ra8_systick_bit_t : uint32_t

Control bits for SYST_CSR, DEMCR, and DWT_CTRL.

Arm v8-M ARM register descriptions for SYST_CSR, DEMCR, and DWT_CTRL.

Enumerator
k_ra8_systick_csr_enable 

SYST_CSR.ENABLE (bit 0).

k_ra8_systick_csr_tickint 

SYST_CSR.TICKINT (bit 1).

k_ra8_systick_csr_clksource 

SYST_CSR.CLKSOURCE (bit 2).

k_ra8_dwt_demcr_trcena 

DEMCR.TRCENA (bit 24).

k_ra8_dwt_ctrl_cyccntena 

DWT_CTRL.CYCCNTENA (bit 0).

Definition at line 58 of file ra8_systick.c.

◆ ra8_systick_reg_addr_t

enum ra8_systick_reg_addr_t : uintptr_t

Arm v8-M SCS timebase register addresses (PPB 0xE000Exxx).

Arm v8-M ARM: SysTick registers live in the System Control Block and DWT registers in the Data Watchpoint and Trace unit. Both are mapped into the fake core window (0xE0000000) on a host build, real PPB on silicon.

Enumerator
k_ra8_systick_csr 

SYST_CSR control and status.

k_ra8_systick_rvr 

SYST_RVR reload value.

k_ra8_systick_cvr 

SYST_CVR current value.

k_ra8_dwt_demcr 

DEMCR: bit 24 TRCENA unlocks DWT.

k_ra8_dwt_ctrl 

DWT_CTRL: bit 0 CYCCNTENA.

k_ra8_dwt_cyccnt 

DWT_CYCCNT free-running counter.

Definition at line 43 of file ra8_systick.c.

Function Documentation

◆ internal_systick_reg()

volatile uint32_t * internal_systick_reg ( ra8_systick_reg_addr_t addr)
inlinestatic

Typed pointer to a 32-bit SCS timebase register.

Trivial address-cast helper shared by every access below, so no register store or load in this file is written as a raw pointer-cast dereference.

Parameters
[in]addrOne of ra8_systick_reg_addr_t.
Returns
Volatile pointer for a single read or write.
Return values
(volatileuint32_t*)addr Always the aliasing register pointer.
Precondition
addr is a valid SCS timebase-register address.
The PPB / fake core window is accessible.
Postcondition
No state changed by forming the pointer.
The returned pointer aliases the live register.
Note
Arm v8-M ARM B11 "System Control Block". Trivially thread-safe.
Since
0.1.0

Definition at line 87 of file ra8_systick.c.

Referenced by ra8_dwt_cyccnt_enable(), ra8_dwt_cyccnt_read(), ra8_dwt_cyccnt_reset(), ra8_systick_configure(), ra8_systick_current_value(), and ra8_systick_set_reload().

◆ ra8_dwt_cyccnt_enable()

void ra8_dwt_cyccnt_enable ( void )

Enable the DWT free-running cycle counter (DWT_CYCCNT).

Sets DEMCR.TRCENA to unlock the DWT unit, then sets DWT_CTRL.CYCCNTENA to start DWT_CYCCNT counting every CPU cycle. Both are read-modify-write so any other trace/debug bits already set are preserved. The counter is PRIMASK-immune: it keeps advancing even while interrupts are globally masked, which is what makes it a usable delay reference in early boot and IRQ-off critical sections.

Precondition
The Cortex-M85 core is running.
The SCS region is accessible.
Postcondition
DEMCR.TRCENA and DWT_CTRL.CYCCNTENA are both set.
DWT_CYCCNT is advancing once per CPU cycle.
Note
Not thread-safe (read-modify-write of two registers); call once at init.
See also
ra8_dwt_cyccnt_read
ra8_dwt_cyccnt_reset
Since
0.1.0

Definition at line 168 of file ra8_systick.c.

References internal_systick_reg(), k_ra8_dwt_ctrl, k_ra8_dwt_ctrl_cyccntena, k_ra8_dwt_demcr, and k_ra8_dwt_demcr_trcena.

Referenced by demo_setup_or_halt(), and ra8_time_init().

◆ ra8_dwt_cyccnt_read()

uint32_t ra8_dwt_cyccnt_read ( void )
nodiscard

Sample the DWT cycle counter (DWT_CYCCNT).

Reads the free-running 32-bit cycle counter. Wraps every 2^32 CPU cycles (~4.3 s at 1 GHz); compare two samples with unsigned subtraction so the elapsed count stays correct across a wrap.

Returns
The current DWT_CYCCNT value.
Return values
0..UINT32_MAXCPU cycles counted since the counter was last zeroed, modulo 2^32.
Precondition
ra8_dwt_cyccnt_enable has been called.
The SCS region is accessible.
Postcondition
No architectural state is modified (pure read).
Successive samples are non-decreasing modulo 2^32.
Note
Thread-safe; single-word read of a volatile register.
See also
ra8_dwt_cyccnt_enable
Since
0.1.0

Definition at line 183 of file ra8_systick.c.

References internal_systick_reg(), and k_ra8_dwt_cyccnt.

Referenced by cam_record_sync_sample(), cam_sync_state_init(), demo_emit_measurement(), and ra8_delay_ms().

◆ ra8_dwt_cyccnt_reset()

void ra8_dwt_cyccnt_reset ( void )

Zero the DWT cycle counter (DWT_CYCCNT).

Writes zero to DWT_CYCCNT so a subsequent ra8_dwt_cyccnt_read measures cycles elapsed from this call. Does not enable or disable the counter; ra8_dwt_cyccnt_enable must already have started it for the reset to matter.

Precondition
ra8_dwt_cyccnt_enable has been called (or the counter is otherwise on).
The SCS region is accessible.
Postcondition
DWT_CYCCNT reads approximately zero (it advances immediately after).
No other DWT or DEMCR bit is modified.
Note
Not thread-safe; intended to bracket a measured region.
See also
ra8_dwt_cyccnt_read
Since
0.1.0

Definition at line 176 of file ra8_systick.c.

References internal_systick_reg(), and k_ra8_dwt_cyccnt.

Referenced by demo_emit_measurement().

◆ ra8_systick_configure()

ra8_err_t ra8_systick_configure ( uint32_t reload,
ra8_systick_clock_source_t src,
bool tick_irq )
nodiscard

Arm and start SysTick with a reload value and clock source.

Performs the full bring-up sequence: disable the counter, program SYST_RVR with reload, clear SYST_CVR so counting restarts from the new reload, then write SYST_CSR to enable the counter with the requested clock source and, optionally, the tick interrupt. This is the exact sequence a millisecond timebase performs once at init.

Parameters
[in]reloadSYST_RVR reload value; must be <= k_ra8_systick_rvr_max.
[in]srcCounter clock source (ra8_systick_clock_source_t).
[in]tick_irqWhen true, enable SYST_CSR.TICKINT so the counter reaching zero raises the SysTick exception; when false, the counter free-runs and callers poll ra8_systick_current_value.
Returns
Error code.
Return values
k_ra8_okSysTick armed and counting.
k_ra8_err_out_of_rangereload exceeds k_ra8_systick_rvr_max.
Precondition
reload was produced by ra8_systick_reload_for or is otherwise known to fit the 24-bit field.
The SCS region is accessible (always true on Cortex-M).
Postcondition
On k_ra8_ok, SYST_RVR holds reload and the counter is enabled.
On any error, no SysTick register is modified.
Note
Not thread-safe; intended for single-threaded init or an IRQ-masked critical section.
See also
ra8_systick_set_reload
ra8_systick_reload_for
Since
0.1.0

Definition at line 122 of file ra8_systick.c.

References internal_systick_reg(), k_ra8_err_out_of_range, k_ra8_ok, k_ra8_systick_clk_cpu, k_ra8_systick_csr, k_ra8_systick_csr_clksource, k_ra8_systick_csr_enable, k_ra8_systick_csr_tickint, k_ra8_systick_cvr, k_ra8_systick_rvr, k_ra8_systick_rvr_max, ra8_log_error, and s_tag.

Referenced by demo_setup_or_halt(), and ra8_time_init().

◆ ra8_systick_current_value()

uint32_t ra8_systick_current_value ( void )
nodiscard

Read the live SysTick current-value register (SYST_CVR).

Returns the counter's current value, which counts down from SYST_RVR to zero and reloads. Reading it never clears it (only a write does), so this is a side-effect-free sample of the running counter.

Returns
The 24-bit SYST_CVR value in the low bits of the result.
Return values
0..k_ra8_systick_rvr_maxCurrent down-counter value.
Precondition
SysTick has been configured and is counting.
The SCS region is accessible.
Postcondition
No architectural state is modified (pure read).
Successive samples move monotonically down until the reload wrap.
Note
Thread-safe; single-word read of a volatile register.
Since
0.1.0

Definition at line 161 of file ra8_systick.c.

References internal_systick_reg(), and k_ra8_systick_cvr.

◆ ra8_systick_reload_for()

ra8_err_t ra8_systick_reload_for ( uint32_t cpu_hz,
uint32_t tick_hz,
uint32_t * out_reload )
nodiscard

Compute the SysTick reload for a given core clock and tick rate.

Derives the SYST_RVR reload value as cpu_hz / tick_hz - 1, the pure arithmetic every SysTick consumer needs. Validates that neither input is zero, that the clock is at least one tick period (cpu_hz >= tick_hz), and that the resulting reload fits the 24-bit SYST_RVR field. No register is touched, so this half is fully deterministic and host-testable on its own.

Parameters
[in]cpu_hzCore (SysTick) clock in Hz.
[in]tick_hzDesired tick rate in Hz (e.g. 1000 for a 1 ms tick).
[out]out_reloadOn success, receives the SYST_RVR reload value.
Returns
Error code.
Return values
k_ra8_okReload computed and written to out_reload.
k_ra8_err_null_ptrout_reload is NULL.
k_ra8_err_invalid_argcpu_hz or tick_hz is zero, or cpu_hz is below one tick period.
k_ra8_err_out_of_rangeThe reload exceeds k_ra8_systick_rvr_max (cpu_hz far too high for tick_hz).
Precondition
out_reload is a valid, writable uint32_t.
tick_hz is the rate the caller will actually program.
Postcondition
On k_ra8_ok, *out_reload <= k_ra8_systick_rvr_max.
On any error, out_reload is left unmodified.
Note
Pure function; trivially thread-safe.
Example:
uint32_t reload = 0U;
// 1 GHz core, 1 kHz tick -> reload = 999999.
(void)ra8_systick_reload_for(1000000000U, 1000U, &reload);
ra8_err_t ra8_systick_reload_for(uint32_t cpu_hz, uint32_t tick_hz, uint32_t *out_reload)
Compute the SysTick reload for a given core clock and tick rate.
Definition ra8_systick.c:92
See also
ra8_systick_configure
ra8_systick_set_reload
Since
0.1.0

Definition at line 92 of file ra8_systick.c.

References k_ra8_err_invalid_arg, k_ra8_err_out_of_range, k_ra8_ok, k_ra8_systick_rvr_max, RA8_CHECK_NULL_PTR, ra8_log_error, and s_tag.

Referenced by demo_setup_or_halt().

◆ ra8_systick_set_reload()

ra8_err_t ra8_systick_set_reload ( uint32_t reload)
nodiscard

Re-arm SysTick with a new reload, leaving the control bits untouched.

Writes SYST_RVR with reload and clears SYST_CVR so the next count starts from the new reload. Unlike ra8_systick_configure this does NOT touch SYST_CSR, so the enable / clock-source / tick-interrupt bits already in force are preserved. This is the retune path: adjust the reload for a live clock change without a disable/enable glitch on the running tick.

Parameters
[in]reloadNew SYST_RVR reload value; <= k_ra8_systick_rvr_max.
Returns
Error code.
Return values
k_ra8_okReload re-armed; current value cleared.
k_ra8_err_out_of_rangereload exceeds k_ra8_systick_rvr_max.
Precondition
SysTick has already been configured (its control bits are set).
reload fits the 24-bit SYST_RVR field.
Postcondition
On k_ra8_ok, SYST_RVR holds reload and SYST_CVR reads zero.
On any error, no SysTick register is modified.
Note
Not thread-safe; write from a single context.
See also
ra8_systick_configure
Since
0.1.0

Definition at line 146 of file ra8_systick.c.

References internal_systick_reg(), k_ra8_err_out_of_range, k_ra8_ok, k_ra8_systick_cvr, k_ra8_systick_rvr, k_ra8_systick_rvr_max, ra8_log_error, and s_tag.

Referenced by ra8_threadx_systick_retune().

Variable Documentation

◆ s_tag

const char* const s_tag = "ra8_systick"
static

Module log tag.

Definition at line 33 of file ra8_systick.c.