ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
main.c
Go to the documentation of this file.
1
49
50#include <stddef.h>
51#include <stdint.h>
52
53#include "ra8_board_ek_ra8d2.h"
54#include "ra8_boot_entry.h"
55#include "ra8_cgc.h"
56#include "ra8_err.h"
57#include "ra8_eth_gptp.h"
58#include "ra8_isr.h"
59#include "ra8_mstp.h"
60#include "ra8_time.h"
61
63typedef enum : uint32_t {
64 k_gptp_baud = 115200U,
67 k_gptp_base_sec = 1000000000U
69
76typedef enum : uint64_t {
77 k_gptp_sec_flatten_max = 18446744073ULL,
79
81typedef enum : uint32_t {
84 k_gptp_ns_per_ms = 1000000U,
85 k_gptp_ns_per_sec = 1000000000U
87
89typedef enum : uint8_t {
93
94/* Console line fragments (kept short so each write is one shift-register
95 * fill; the periodic log is the only output path). */
96static const uint8_t k_gptp_ipv_prefix[] = "gptp: ipv=";
97static const uint8_t k_gptp_time_prefix[] = "gptp: t=";
98static const uint8_t k_gptp_time_dot[] = ".";
99static const uint8_t k_gptp_adv_prefix[] = "gptp: adv_ns=";
100static const uint8_t k_gptp_sys_prefix[] = " sys_ms=";
101static const uint8_t k_gptp_crlf[] = "\r\n";
102static const uint8_t k_gptp_verdict_pass[] = "gptp: clock PASS\r\n";
103static const uint8_t k_gptp_verdict_fail[] = "gptp: clock FAIL\r\n";
104
120static void gptp_panic_halt(void)
121{
122 while (1) {
123 __asm__ volatile("wfi");
124 }
125}
126
145static void gptp_write(const uint8_t* data, uint32_t len)
146{
147 (void)ra8_board_uart_console_write(data, (size_t)len);
148}
149
169static void gptp_write_u64(uint64_t val)
170{
171 uint8_t buf[k_gptp_dec_u64_max];
172 uint8_t tmp[k_gptp_dec_u64_max];
173 uint32_t n = 0U;
174 uint64_t v = val;
175 if (v == 0U) {
176 buf[0] = (uint8_t)'0';
177 gptp_write(buf, 1U);
178 return;
179 }
180 while (v != 0U) {
181 tmp[n] = (uint8_t)('0' + (uint8_t)(v % (uint64_t)k_gptp_radix));
182 v = v / (uint64_t)k_gptp_radix;
183 n++;
184 }
185 for (uint32_t i = 0U; i < n; i++) {
186 buf[i] = tmp[n - 1U - i];
187 }
188 gptp_write(buf, n);
189}
190
209static void gptp_log_time(uint64_t sec, uint32_t nsec)
210{
211 gptp_write(k_gptp_time_prefix, (uint32_t)(sizeof(k_gptp_time_prefix) - 1U));
212 gptp_write_u64(sec);
213 gptp_write(k_gptp_time_dot, (uint32_t)(sizeof(k_gptp_time_dot) - 1U));
214 gptp_write_u64((uint64_t)nsec);
215 gptp_write(k_gptp_crlf, (uint32_t)(sizeof(k_gptp_crlf) - 1U));
216}
217
242static uint64_t gptp_flatten_ns(uint64_t sec, uint32_t nsec)
243{
244 if (sec > (uint64_t)k_gptp_sec_flatten_max) {
245 return UINT64_MAX;
246 }
247 return (sec * (uint64_t)k_gptp_ns_per_sec) + (uint64_t)nsec;
248}
249
270static bool gptp_probe_presence(void)
271{
272 uint32_t version = 0U;
273 const ra8_err_t err = ra8_eth_gptp_ip_version(&version);
274 gptp_write(k_gptp_ipv_prefix, (uint32_t)(sizeof(k_gptp_ipv_prefix) - 1U));
275 gptp_write_u64((uint64_t)version);
276 gptp_write(k_gptp_crlf, (uint32_t)(sizeof(k_gptp_crlf) - 1U));
277 if (err != k_ra8_ok) {
278 return false;
279 }
280 return version != 0U;
281}
282
306static bool gptp_advance_ok(uint64_t advance_ns, uint32_t elapsed_ms)
307{
308 if (elapsed_ms == 0U) {
309 return false;
310 }
311 const uint64_t expected_ns = (uint64_t)elapsed_ms * (uint64_t)k_gptp_ns_per_ms;
312 const uint64_t band_ns =
313 (expected_ns * (uint64_t)k_gptp_tolerance_pct) / (uint64_t)k_gptp_pct_full;
314 if (advance_ns > (expected_ns + band_ns)) {
315 return false;
316 }
317 return advance_ns >= (expected_ns - band_ns);
318}
319
335static bool gptp_measure(void)
336{
337 uint64_t sec0 = 0U;
338 uint32_t nsec0 = 0U;
339 uint64_t sec1 = 0U;
340 uint32_t nsec1 = 0U;
341 bool ok = true;
342
343 const uint32_t ms0 = ra8_time_ms();
344 if (ra8_eth_gptp_get_time(k_ra8_gptp_timer_0, &sec0, &nsec0) != k_ra8_ok) {
345 ok = false;
346 }
348 if (ra8_eth_gptp_get_time(k_ra8_gptp_timer_0, &sec1, &nsec1) != k_ra8_ok) {
349 ok = false;
350 }
351 const uint32_t elapsed_ms = ra8_time_ms() - ms0;
352
353 gptp_log_time(sec0, nsec0);
354 gptp_log_time(sec1, nsec1);
355
356 const uint64_t ns0 = gptp_flatten_ns(sec0, nsec0);
357 const uint64_t ns1 = gptp_flatten_ns(sec1, nsec1);
358 const uint64_t advance_ns = (ns1 > ns0) ? (ns1 - ns0) : 0ULL;
359
360 gptp_write(k_gptp_adv_prefix, (uint32_t)(sizeof(k_gptp_adv_prefix) - 1U));
361 gptp_write_u64(advance_ns);
362 gptp_write(k_gptp_sys_prefix, (uint32_t)(sizeof(k_gptp_sys_prefix) - 1U));
363 gptp_write_u64((uint64_t)elapsed_ms);
364 gptp_write(k_gptp_crlf, (uint32_t)(sizeof(k_gptp_crlf) - 1U));
365
366 if (!gptp_advance_ok(advance_ns, elapsed_ms)) {
367 ok = false;
368 }
369 return ok;
370}
371
392static bool gptp_run_cycle(void)
393{
394 bool ok = true;
395 if (!gptp_probe_presence()) {
396 ok = false;
397 }
398 if (!gptp_measure()) {
399 ok = false;
400 }
401 return ok;
402}
403
419static void gptp_setup_or_halt(void)
420{
421 uint32_t cpuclk0_hz = 0U;
422 if (ra8_cgc_init() != k_ra8_ok) {
424 }
427 }
428 if (ra8_mstp_init() != k_ra8_ok) {
430 }
431 if (ra8_time_init(cpuclk0_hz) != k_ra8_ok) {
433 }
436 }
439 }
440 if (ra8_cgc_eswclk_init() != k_ra8_ok) {
442 }
443}
444
465[[nodiscard]] static ra8_err_t gptp_arm(void)
466{
467 uint32_t eswclk_hz = 0U;
468 const ra8_err_t hz_err = ra8_cgc_eswclk_hz(&eswclk_hz);
469 if (hz_err != k_ra8_ok) {
470 return hz_err;
471 }
472 const ra8_eth_gptp_cfg_t cfg = {.clk_hz = eswclk_hz};
473 const ra8_err_t init_err = ra8_eth_gptp_init(&cfg);
474 if (init_err != k_ra8_ok) {
475 return init_err;
476 }
477 const ra8_err_t off_err =
479 if (off_err != k_ra8_ok) {
480 return off_err;
481 }
483}
484
485void main(void)
486{
489
490 if (gptp_arm() != k_ra8_ok) {
492 }
493
494 while (1) {
495 const bool healthy = gptp_run_cycle();
496 if (healthy) {
497 gptp_write(k_gptp_verdict_pass, (uint32_t)(sizeof(k_gptp_verdict_pass) - 1U));
498 } else {
499 gptp_write(k_gptp_verdict_fail, (uint32_t)(sizeof(k_gptp_verdict_fail) - 1U));
500 }
502 break;
503 }
505 }
507}
void main(void)
Secure fallback main entry point.
Definition main.c:37
static const uint8_t k_gptp_sys_prefix[]
Definition main.c:100
static const uint8_t k_gptp_ipv_prefix[]
Definition main.c:96
static void gptp_write(const uint8_t *data, uint32_t len)
Write a byte span to the SCI8 console, discarding the status.
Definition main.c:145
gptp_fmt_t
Formatting and arithmetic constants.
Definition main.c:81
@ k_gptp_dec_u64_max
Max decimal digits for a uint64_t.
Definition main.c:83
@ k_gptp_ns_per_sec
Nanoseconds in one second.
Definition main.c:85
@ k_gptp_ns_per_ms
Nanoseconds in one millisecond.
Definition main.c:84
@ k_gptp_radix
Decimal serialiser radix.
Definition main.c:82
static const uint8_t k_gptp_verdict_fail[]
Definition main.c:103
static bool gptp_probe_presence(void)
Read the IP-version word and require it to be nonzero.
Definition main.c:270
static const uint8_t k_gptp_adv_prefix[]
Definition main.c:99
static const uint8_t k_gptp_time_dot[]
Definition main.c:98
static const uint8_t k_gptp_time_prefix[]
Definition main.c:97
static void gptp_write_u64(uint64_t val)
Log one unsigned 64-bit value as decimal ASCII.
Definition main.c:169
static const uint8_t k_gptp_crlf[]
Definition main.c:101
static const uint8_t k_gptp_verdict_pass[]
Definition main.c:102
static bool gptp_advance_ok(uint64_t advance_ns, uint32_t elapsed_ms)
Decide whether a measured advance matches the SysTick window.
Definition main.c:306
static bool gptp_measure(void)
Sample the counter twice around a SysTick-timed window.
Definition main.c:335
static uint64_t gptp_flatten_ns(uint64_t sec, uint32_t nsec)
Flatten a GPTP sample to nanoseconds.
Definition main.c:242
static void gptp_log_time(uint64_t sec, uint32_t nsec)
Log one gptp: t= line – seconds, a dot, then nanoseconds.
Definition main.c:209
static void gptp_setup_or_halt(void)
Core bring-up: CGC -> ESWCLK -> MSTP -> TIME -> console + LED.
Definition main.c:419
static bool gptp_run_cycle(void)
Run one cycle: presence probe plus one advance measurement.
Definition main.c:392
gptp_const_t
Demo tunables.
Definition main.c:63
@ k_gptp_base_sec
Epoch seconds loaded into the offset.
Definition main.c:67
@ k_gptp_period_ms
Idle time between measurement cycles.
Definition main.c:65
@ k_gptp_window_ms
Measurement window, timed on SysTick.
Definition main.c:66
@ k_gptp_baud
SCI8 console baud.
Definition main.c:64
gptp_flatten_limit_t
Largest seconds value that can be flattened to nanoseconds.
Definition main.c:76
@ k_gptp_sec_flatten_max
floor(2^64 - 1 / 1e9).
Definition main.c:77
static void gptp_panic_halt(void)
Park forever after a fatal init error.
Definition main.c:120
static ra8_err_t gptp_arm(void)
Programme the GPTP timer from the live ESWCLK and start it.
Definition main.c:465
gptp_band_t
Accuracy band the measured advance must fall inside.
Definition main.c:89
@ k_gptp_pct_full
Denominator for the percentage above.
Definition main.c:91
@ k_gptp_tolerance_pct
Allowed drift vs SysTick, in percent.
Definition main.c:90
Board-support layer for the Renesas EK-RA8D2 v1 evaluation kit.
ra8_err_t ra8_board_led_toggle(ra8_board_led_id_t led)
Toggle led's output state.
ra8_err_t ra8_board_led_init(ra8_board_led_id_t led)
Configure led as a digital output, initial level low (off).
@ k_ra8_board_led1
LED1, BLUE, P600 (jumper E27).
ra8_err_t ra8_board_uart_console_write(const uint8_t *data, size_t len)
Polled blocking write to the J-Link OB VCOM console.
ra8_err_t ra8_board_uart_console_init(uint32_t baud)
Configure SCI8 + PD02/PD03 as the debug-console UART.
Boot entry points shared between a vector table and its startup code.
High-level Clock Generation Circuit driver.
ra8_err_t ra8_cgc_eswclk_hz(uint32_t *out_hz)
Query the current ESWCLK (Ethernet Switch clock) frequency.
ra8_err_t ra8_cgc_get_clock_hz(ra8_clock_id_t id, uint32_t *out_hz)
Query the current frequency of a clock-tree domain.
Definition ra8_cgc.c:132
ra8_err_t ra8_cgc_eswclk_init(void)
Bring up the Ethernet Switch Module (ESWM / RMAC) clock.
@ k_ra8_clock_id_cpuclk0
Cortex-M85 CPUCLK0.
Definition ra8_cgc.h:70
ra8_err_t ra8_cgc_init(void)
Configure the clock tree to a safe default.
Definition ra8_cgc.c:727
Error Code Definitions for ra8-firmware.
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
Ethernet Generic PTP Timer (GPTP) driver – HUM Ch 35.
ra8_err_t ra8_eth_gptp_ip_version(uint32_t *out_version)
Read the read-only PTPIPV IP-version word.
ra8_err_t ra8_eth_gptp_timer_enable(ra8_gptp_timer_idx_t timer)
Start one timer unit (PTPTMEC.TEq).
ra8_err_t ra8_eth_gptp_get_time(ra8_gptp_timer_idx_t timer, uint64_t *out_sec, uint32_t *out_nsec)
Read one timer unit's 78-bit GPTP time.
ra8_err_t ra8_eth_gptp_set_offset(ra8_gptp_timer_idx_t timer, uint64_t sec, uint32_t nsec)
Load one timer unit's additive 78-bit offset.
ra8_err_t ra8_eth_gptp_init(const ra8_eth_gptp_cfg_t *cfg)
Power up the GPTP block and programme both timers' increment.
@ k_ra8_gptp_timer_0
Timer unit 0 (registers at +0x0020).
NVIC + ICU IELSR allocator.
void ra8_isr_globals_enable(void)
Globally enable maskable interrupts (PRIMASK = 0).
Definition ra8_isr.c:439
Ref-counted Module Stop Control wrapper for the RA8D2.
ra8_err_t ra8_mstp_init(void)
Re-establish the ra8_mstp ref-count table from current hardware state.
Definition ra8_mstp.c:291
SysTick-based tick counter, delay and timestamp helpers.
ra8_err_t ra8_time_init(uint32_t cpu_hz)
Initialise SysTick for a 1 kHz tick interrupt.
Definition ra8_time.c:59
void ra8_delay_ms(uint32_t ms)
Busy-wait for at least ms milliseconds.
Definition ra8_time.c:129
uint32_t ra8_time_ms(void)
Get the current 1 kHz tick count.
Definition ra8_time.c:108
Static configuration for ra8_eth_gptp_init.