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
46
47#include <stdint.h>
48#include <string.h>
49
50#include "ra8_board_ek_ra8d2.h"
51#include "ra8_boot_entry.h"
52#include "ra8_cgc.h"
53#include "ra8_err.h"
54#include "ra8_isr.h"
55#include "ra8_time.h"
56
57/*
58 * The host unit-test build (RA8_OFF_TARGET) does not link the
59 * ThreadX / LevelX vendor trees, so `tx_api.h` and `lx_api.h` are
60 * unreachable when clang-tidy walks this file. Pull them in only on
61 * the cross-compile target.
62 */
63#ifndef RA8_OFF_TARGET
64#include "lx_api.h"
66#include "tx_api.h"
67#endif
68
72typedef enum : uint32_t {
75
76typedef enum : uint32_t {
78 k_demo_baud = 115200U,
79
82
85
88
91
94
97
101
102#ifndef RA8_OFF_TARGET
103/* LevelX state. ThreadX requires statically-allocated control blocks
104 * (NASA Power of 10 Rule 3 -- no dynamic memory). */
105static LX_NOR_FLASH s_nor_flash;
106
107/* LevelX logical-sector scratch buffer (512 bytes, ULONG-aligned). */
109
110/* ThreadX worker thread. */
113#endif /* !RA8_OFF_TARGET */
114
133static void demo_panic_halt(void)
134{
136 while (1) {
137 __asm__ volatile("wfi");
138 }
139}
140
149static void demo_setup_or_halt(void)
150{
151 uint32_t cpuclk0_hz = 0U;
152
153 if (ra8_cgc_init() != k_ra8_ok) {
155 }
158 }
159 if (ra8_time_init(cpuclk0_hz) != k_ra8_ok) {
161 }
164 }
165}
166
177static void demo_print(const char* s)
178{
179 if (s == (const char*)0) {
180 return;
181 }
182 size_t len = strlen(s);
183 (void)ra8_board_uart_console_write((const uint8_t*)s, len);
184}
185
196static void demo_print_u32(uint32_t value)
197{
198 /* Largest uint32_t = 4294967295 -> 10 chars + NUL. */
199 char buf[k_demo_u32_buf_size];
200 uint32_t i = (uint32_t)sizeof(buf);
201 buf[--i] = '\0';
202 if (value == 0U) {
203 buf[--i] = '0';
204 } else {
205 while ((value != 0U) && (i > 0U)) {
206 buf[--i] = (char)('0' + (value % k_demo_radix_dec));
207 value /= k_demo_radix_dec;
208 }
209 }
210 demo_print(&buf[i]);
211}
212
213#ifndef RA8_OFF_TARGET
225static void demo_print_stat(const char* label, ULONG value)
226{
227 demo_print(" ");
228 demo_print(label);
229 demo_print(": ");
230 demo_print_u32((uint32_t)value);
231 demo_print("\r\n");
232}
233
242static void demo_lx_format_or_panic(void)
243{
244 static CHAR s_flash_name[] = "ra8_xspi_nor";
245
246 UINT status =
247 lx_nor_flash_format(&s_nor_flash, s_flash_name, lx_nor_driver_ra8_xspi_initialize, LX_NULL);
248 if (status != LX_SUCCESS) {
249 demo_print("[lx] format failed\r\n");
251 }
252 status = lx_nor_flash_open(&s_nor_flash, s_flash_name, lx_nor_driver_ra8_xspi_initialize);
253 if (status != LX_SUCCESS) {
254 demo_print("[lx] open failed\r\n");
256 }
257}
258
273static UINT demo_heartbeat(uint32_t counter)
274{
275 /* Stamp the counter into the first ULONG of the scratch buffer. */
276 s_demo_sector_io[0] = (ULONG)counter;
277 UINT status =
278 lx_nor_flash_sector_write(&s_nor_flash, (ULONG)k_demo_sector_index, &s_demo_sector_io[0]);
279 if (status != LX_SUCCESS) {
280 return status;
281 }
282 /* Wipe the buffer before read-back so we know the value really came
283 * out of flash. */
284 s_demo_sector_io[0] = 0U;
285 status = lx_nor_flash_sector_read(&s_nor_flash, (ULONG)k_demo_sector_index, &s_demo_sector_io[0]);
286 return status;
287}
288
297static void demo_print_wear_stats(void)
298{
299 demo_print("[lx] wear stats:\r\n");
300 demo_print_stat("write_requests ", s_nor_flash.lx_nor_flash_write_requests);
301 demo_print_stat("read_requests ", s_nor_flash.lx_nor_flash_read_requests);
302 demo_print_stat("minimum_erase_count ", s_nor_flash.lx_nor_flash_minimum_erase_count);
303 demo_print_stat("maximum_erase_count ", s_nor_flash.lx_nor_flash_maximum_erase_count);
304 demo_print_stat("free_physical_sectors", s_nor_flash.lx_nor_flash_free_physical_sectors);
305 demo_print_stat("mapped_phys_sectors ", s_nor_flash.lx_nor_flash_mapped_physical_sectors);
306 demo_print_stat("obsolete_phys_sectors", s_nor_flash.lx_nor_flash_obsolete_physical_sectors);
307 demo_print_stat("phys_block_allocates ", s_nor_flash.lx_nor_flash_physical_block_allocates);
308 demo_print_stat("sector_cache_hits ", s_nor_flash.lx_nor_flash_sector_mapping_cache_hits);
309 demo_print_stat("sector_cache_misses ", s_nor_flash.lx_nor_flash_sector_mapping_cache_misses);
310#ifndef LX_NOR_DISABLE_EXTENDED_CACHE
311 demo_print_stat("extended_cache_hits ", s_nor_flash.lx_nor_flash_extended_cache_hits);
312 demo_print_stat("extended_cache_misses", s_nor_flash.lx_nor_flash_extended_cache_misses);
313#endif
314}
315
336static void demo_report_rw_once(uint32_t counter, uint32_t readback)
337{
338 if (counter != 1U) {
339 return;
340 }
341 if (readback == counter) {
342 demo_print("[lx] sector rw verified readback=");
343 demo_print_u32(readback);
344 demo_print("\r\n");
345 } else {
346 demo_print("[lx] sector rw MISMATCH\r\n");
347 }
348}
349
361static void demo_thread_entry(ULONG thread_input)
362{
363 (void)thread_input;
364
365 demo_print("[lx] booting xSPI flash\r\n");
366 /* The LevelX NOR driver owns OCTA bus bring-up: lx_nor_flash_format ->
367 * lx_nor_driver_ra8_xspi_initialize -> priv_bus_init_once routes the
368 * pins, runs the 8D/1S software-reset recovery, calls ra8_xspi_init,
369 * and probes RDID exactly once. Doing it here as well double-routes
370 * the PFS pins (the validator rejects the second route with
371 * k_ra8_err_gpio_conflict), so the driver's initialize bails before
372 * wiring the sector buffer and format returns LX_NO_MEMORY. Let the
373 * driver be the single owner. */
374 demo_print("[lx] formatting + opening LevelX partition\r\n");
376
377 demo_print("[lx] heartbeat begins\r\n");
378 uint32_t counter = 0U;
379 while (counter < (uint32_t)k_demo_burnin_writes) {
380 counter++;
381 UINT status = demo_heartbeat(counter);
382 if (status != LX_SUCCESS) {
383 demo_print("[lx] heartbeat I/O error at #");
384 demo_print_u32(counter);
385 demo_print("\r\n");
386 break;
387 }
388 demo_report_rw_once(counter, (uint32_t)s_demo_sector_io[0]);
389 /* Print every 100 cycles so the SCI8 stream stays readable. */
390 if ((counter % k_lx_log_every_n) == 0U) {
391 demo_print("[lx] cycle #");
392 demo_print_u32(counter);
393 demo_print(" readback=");
394 demo_print_u32((uint32_t)s_demo_sector_io[0]);
395 demo_print("\r\n");
396 }
397 /* Sleep ``k_demo_tick_ms`` between writes so a human can watch
398 * the flash actually being beat on. ThreadX's tick rate is set by
399 * ``port/threadx/inc/tx_user.h``; one tick is one millisecond at the
400 * project default of ``TX_TIMER_TICKS_PER_SECOND = 1000``. */
402 }
403
404 demo_print("[lx] burn-in complete\r\n");
406
407 (void)lx_nor_flash_close(&s_nor_flash);
408 demo_print("[lx] done\r\n");
409}
410
422void tx_application_define(void* first_unused_memory)
423{
424 static CHAR s_thread_name[] = "lx_demo";
425
426 (void)first_unused_memory;
427
428 lx_nor_flash_initialize();
429
433 0U,
435 (ULONG)sizeof(s_demo_stack),
436 8U, /* priority */
437 8U, /* preempt threshold */
440}
441#endif /* !RA8_OFF_TARGET */
442
451void main(void)
452{
455 demo_print("[lx] booting ThreadX + LevelX...\r\n");
456
457#ifndef RA8_OFF_TARGET
458 /* Hands control over to ThreadX permanently. */
459 tx_kernel_enter();
460#endif
461
462 /* Should never return. */
464}
void main(void)
Secure fallback main entry point.
Definition main.c:37
static TX_THREAD s_demo_thread
Definition main.c:237
demo_config_t
Compile-time settings for the HTTPS client demo.
Definition main.c:87
@ k_demo_thread_stack
Demo thread stack.
Definition main.c:89
@ k_demo_baud
Demo baud.
Definition main.c:88
static UCHAR s_demo_stack[k_demo_thread_stack]
Definition main.c:238
void tx_application_define(void *first_unused_memory)
ThreadX system-define hook: build worker thread + byte pool.
Definition main.c:942
@ k_demo_tick_ms
Battery decrement period.
Definition main.c:84
static LX_NOR_FLASH s_nor_flash
LevelX control block (statically allocated – NASA P10 Rule 3).
Definition main.c:76
static void demo_print(const char *msg)
Print a NUL-terminated string on the demo's UART stream.
Definition main.c:100
static void demo_setup_or_halt(void)
Bring up CGC + SysTick + the SCI8 console; halt forever on any failure.
Definition main.c:123
static void demo_panic_halt(void)
Halt forever in WFI – used as a panic stop on init failure.
Definition main.c:93
static CHAR s_thread_name[]
Definition main.c:212
static void demo_thread_entry(ULONG thread_input)
ThreadX worker entry: PSA + NetX up, connect, run the TLS session.
Definition main.c:731
static void demo_print_wear_stats(void)
Dump LevelX's wear-levelling statistics to SCI8.
Definition main.c:297
static void demo_print_u32(uint32_t value)
Print an unsigned 32-bit integer in decimal to SCI8.
Definition main.c:196
static UINT demo_heartbeat(uint32_t counter)
Run one heartbeat: program counter into sector 0 + read back.
Definition main.c:273
lx_log_pace_t
Compile-time settings for the LevelX wear-levelling demo.
Definition main.c:72
@ k_lx_log_every_n
Log once every N loop iterations.
Definition main.c:73
static ULONG s_demo_sector_io[k_demo_sector_bytes/sizeof(ULONG)]
Definition main.c:108
static void demo_print_stat(const char *label, ULONG value)
Print one labelled ULONG LevelX statistic line over SCI8.
Definition main.c:225
@ k_demo_burnin_writes
Number of heartbeats before printing wear-levelling stats.
Definition main.c:87
@ k_demo_sector_bytes
LevelX bytes per logical sector (= 512).
Definition main.c:93
@ k_demo_sector_index
LevelX logical sector the heartbeat counter is stored in.
Definition main.c:84
@ k_demo_u32_buf_size
Buffer size for demo_print_u32 (10 digits + sign + NUL).
Definition main.c:99
@ k_demo_radix_dec
Decimal radix used by demo_print_u32.
Definition main.c:96
static void demo_report_rw_once(uint32_t counter, uint32_t readback)
Emit a one-shot HIL success banner after the first verified heartbeat.
Definition main.c:336
static void demo_lx_format_or_panic(void)
Format + open the LevelX partition.
Definition main.c:242
LevelX NOR-flash driver shim that bridges LevelX onto the RA8 ra8_xspi HAL (EK-RA8D2 ISSI IS25LX512M ...
UINT lx_nor_driver_ra8_xspi_initialize(LX_NOR_FLASH *nor_flash)
LevelX NOR driver-initialise entry point bridging onto ra8_xspi.
Board-support layer for the Renesas EK-RA8D2 v1 evaluation kit.
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.
ra8_err_t ra8_board_uart_console_flush(void)
Block until every byte queued on the J-Link OB VCOM console has finished clocking out on the wire.
Boot entry points shared between a vector table and its startup code.
High-level Clock Generation Circuit driver.
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
@ 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
size_t strlen(const char *s)
Calculate string length.
NVIC + ICU IELSR allocator.
void ra8_isr_globals_enable(void)
Globally enable maskable interrupts (PRIMASK = 0).
Definition ra8_isr.c:439
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
unsigned int UINT
ThreadX-compatible unsigned int (host stub).
#define tx_thread_create
#define tx_thread_sleep
#define TX_NO_TIME_SLICE
char CHAR
ThreadX-compatible CHAR (host stub).
#define TX_AUTO_START
unsigned long ULONG
ThreadX-compatible unsigned long (host stub).
Opaque thread stand-in for the host build.