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

Complete an esp-hosted RPC round-trip against the ESP32-C6. More...

#include <stdint.h>
#include "c6_fwver.h"
#include "esp_hosted_interface.h"
#include "ra8_board_ek_ra8d2.h"
#include "ra8_boot_entry.h"
#include "ra8_cgc.h"
#include "ra8_err.h"
#include "ra8_esp_hosted_port.h"
#include "ra8_isr.h"
#include "ra8_mstp.h"
#include "ra8_time.h"
#include "tx_api.h"
Include dependency graph for main.c:

Go to the source code of this file.

Enumerations

enum  c6_fwver_pump_budget_t : uint16_t { k_c6_fwver_caps_transfers = 8U }
 Per-phase transaction budgets, so each phase bounds its own wait. More...

Functions

static void c6_fwver_panic_halt (void)
 Park the CPU forever after an unrecoverable bring-up failure.
static void c6_fwver_setup_or_halt (void)
 Bring clocks, module-stop state, SysTick and the console up.
static void c6_fwver_phase_caps (void)
 Send the host-capabilities event and drain the co-processor's.
static void c6_fwver_phase_request (void)
 Send the firmware-version request and pump until it is answered.
static void c6_fwver_heartbeat (bool passed)
 Print a liveness line forever, never returning.
static void c6_fwver_worker_entry (ULONG thread_input)
 Worker thread: report the init, run both phases, judge, heartbeat.
void tx_application_define (void *first_unused_memory)
 ThreadX define hook: bring the port up and start the worker.
void main (void)
 Application entry: clocks, console, banner, then ThreadX.

Variables

static uint32_t s_c6_fwver_cpuclk_hz
 Cached CPUCLK0 rate, used to programme SysTick.
static uint32_t s_c6_fwver_pclka_hz
 Cached PCLKA rate, the SCI baud-clock source the port divides.
static ra8_err_t s_c6_fwver_init_err = k_ra8_err_not_initialized
 Exact result of ra8_esp_hosted_port_init.
static TX_THREAD s_c6_fwver_worker
 Control block of the single application thread.
static CHAR s_c6_fwver_worker_name [] = "c6_fw_version"
 Thread name handed to ThreadX.
static UCHAR s_c6_fwver_worker_stack [k_c6_fwver_worker_stack]
 Stack backing s_c6_fwver_worker.
static uint8_t s_c6_fwver_txbuf [k_c6_fwver_tx_max]
 Staging buffer for the one payload each phase transmits.

Detailed Description

Complete an esp-hosted RPC round-trip against the ESP32-C6.

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

The second application built on port/esp-hosted/, and the one that proves the protocol rather than the wire. c6_spi_probe established the physical link and c6_hosted_init established that the port can clock a framed transaction; both stop at "bytes moved, and their shape is sane". This one sends a request the co-processor must parse and answer, then checks the answer's contents:

  1. bring the port up under ThreadX;
  2. send the ESP_PRIV_IF host-capabilities event the reference host sends first, draining any boot ESP_PRIV_EVENT_INIT the co-processor still holds – whose firmware-version TLV becomes an independent second reading of the answer;
  3. send RPC_ID__Req_GetCoprocessorFwVersion on ESP_SERIAL_IF, protobuf-encoded by the vendored generated codec inside the TLV envelope the serial endpoint expects;
  4. keep clocking transactions until the matching response arrives;
  5. decode it and compare its version against esp_hosted_host_fw_ver.h – the vendored host driver's own version – printing one PASS or FAIL line.
Why that expectation
The co-processor image and the vendored host driver come from one pinned upstream commit, so their versions must agree exactly. Checking the answer against a literal would only prove the co-processor said something; checking it against the host's own version makes the test the host/co-processor version lock, and a vendor bump without a co-processor reflash fails here instead of failing silently in the field.
Bench requirements
SW4 1=OFF 2=OFF 3=ON 4=OFF, the C6 harness on J26, and the C6 powered from its own USB. SW4-3 ON is what connects J26-1..J26-4 to the MCU at all; with it wrong the board and the co-processor both look healthy and the link simply does not exist.
Since
0.1.0

Definition in file main.c.

Enumeration Type Documentation

◆ c6_fwver_pump_budget_t

enum c6_fwver_pump_budget_t : uint16_t

Per-phase transaction budgets, so each phase bounds its own wait.

The capabilities exchange only has to drain whatever the co-processor already queued, so it is short. The request phase has to survive the co-processor scheduling a reply, so it gets the full budget.

Invariant
Both values are non-zero, which c6_fwver_link_pump requires.
k_c6_fwver_caps_transfers is well below k_c6_fwver_max_transfers, so a silent co-processor spends most of its budget where the answer would actually come from.
Example:
(void)c6_fwver_link_pump(..., (uint16_t)k_c6_fwver_caps_transfers, ...);
ra8_err_t c6_fwver_link_pump(uint8_t if_type, uint8_t if_num, const uint8_t *payload, uint16_t payload_len, uint16_t max_transfers, c6_fwver_sink_t sink, c6_fwver_pump_stats_t *stats)
Clock full-duplex transactions until the sink is satisfied.
@ k_c6_fwver_caps_transfers
Transactions the capabilities phase clocks.
Definition main.c:80
See also
c6_fwver_link_pump
Since
0.1.0
Enumerator
k_c6_fwver_caps_transfers 

Transactions the capabilities phase clocks.

Definition at line 79 of file main.c.

Function Documentation

◆ c6_fwver_heartbeat()

void c6_fwver_heartbeat ( bool passed)
static

Print a liveness line forever, never returning.

Parameters
[in]passedVerdict the run reached, echoed on every beat.
Returns
Never returns.
Precondition
The console is up and ThreadX is scheduling.
The verdict has already been printed once.
Postcondition
A line is emitted every k_c6_fwver_heartbeat_ms milliseconds.
No application state is modified beyond the local beat counter.
Note
This is the one deliberately unbounded loop in the application. It exists so a console attached after the run still learns the verdict.
Since
0.1.0

Definition at line 311 of file main.c.

References c6_fwver_put_u32(), c6_fwver_puts(), k_c6_fwver_heartbeat_ms, and tx_thread_sleep.

Referenced by c6_fwver_worker_entry().

◆ c6_fwver_panic_halt()

void c6_fwver_panic_halt ( void )
static

Park the CPU forever after an unrecoverable bring-up failure.

Returns
Never returns.
Precondition
A bring-up step has failed and the application cannot proceed.
The failure was already reported if the console was up.
Postcondition
The CPU is parked in a wait-for-interrupt loop.
No further application state changes.
Note
Never returns; not callable from interrupt context.
Since
0.1.0

Definition at line 173 of file main.c.

Referenced by c6_fwver_setup_or_halt(), and main().

◆ c6_fwver_phase_caps()

void c6_fwver_phase_caps ( void )
static

Send the host-capabilities event and drain the co-processor's.

Returns
Nothing.
Precondition
The port is up and the console is ready.
No other context is driving the SPI bus.
Postcondition
The capabilities event was transmitted, or the reason it was not is on the console.
Any queued boot INIT event has been decoded and reported.
Note
Failure here is reported and not fatal: the RPC exchange does not depend on it, and a bring-up learns more from attempting the next phase than from stopping.
Since
0.1.0

Definition at line 228 of file main.c.

References c6_fwver_dispatch(), c6_fwver_link_pump(), c6_fwver_print_pump(), c6_fwver_priv_host_caps(), c6_fwver_put_u32(), c6_fwver_puts(), k_c6_fwver_caps_transfers, k_c6_fwver_tx_max, k_ra8_ok, ra8_err_to_str(), and s_c6_fwver_txbuf.

Referenced by c6_fwver_worker_entry().

◆ c6_fwver_phase_request()

void c6_fwver_phase_request ( void )
static

Send the firmware-version request and pump until it is answered.

Returns
Nothing.
Precondition
The port is up and the console is ready.
The capabilities phase has finished, so the bus is free.
Postcondition
The request was transmitted, or the reason it was not is on the console.
The response, if one arrived, has been recorded for the verdict.
Note
The pump stops as soon as the RPC layer accepts the response, so a healthy link spends only the transactions it needs.
Since
0.1.0

Definition at line 270 of file main.c.

References c6_fwver_dispatch(), c6_fwver_link_pump(), c6_fwver_print_pump(), c6_fwver_put_u32(), c6_fwver_puts(), c6_fwver_rpc_request(), k_c6_fwver_max_transfers, k_c6_fwver_tx_max, k_ra8_ok, ra8_err_to_str(), and s_c6_fwver_txbuf.

Referenced by c6_fwver_worker_entry().

◆ c6_fwver_setup_or_halt()

void c6_fwver_setup_or_halt ( void )
static

Bring clocks, module-stop state, SysTick and the console up.

Returns
Nothing; panic-halts instead of returning on any failure.
Precondition
Reset_Handler has copied .data and zeroed .bss.
SystemInit has completed and the console SCI is unclaimed.
Postcondition
s_c6_fwver_cpuclk_hz and s_c6_fwver_pclka_hz are non-zero and the console transmits at k_c6_fwver_uart_baud, 8N1.
SysTick runs and every peripheral this app uses is out of module-stop.
Note
Never returns on error; a clock failure happens before the console exists, so it is visible only to a debugger.
Since
0.1.0

Definition at line 193 of file main.c.

References c6_fwver_panic_halt(), k_c6_fwver_uart_baud, k_ra8_clock_id_cpuclk0, k_ra8_clock_id_pclka, k_ra8_ok, ra8_board_uart_console_init(), ra8_cgc_get_clock_hz(), ra8_cgc_init(), ra8_mstp_init(), ra8_time_init(), s_c6_fwver_cpuclk_hz, and s_c6_fwver_pclka_hz.

Referenced by main().

◆ c6_fwver_worker_entry()

void c6_fwver_worker_entry ( ULONG thread_input)
static

Worker thread: report the init, run both phases, judge, heartbeat.

Parameters
[in]thread_inputThreadX entry argument; unused.
Returns
Never returns.
Precondition
tx_application_define has recorded s_c6_fwver_init_err.
The console is up.
Postcondition
On a successful init both phases ran and exactly one verdict was printed.
On a failed init no transaction was attempted and the error was named.
Note
The failure path deliberately does not continue: a port that did not come up has an unpopulated vtable, and calling through it would fault rather than report.
Since
0.1.0

Definition at line 338 of file main.c.

References c6_fwver_heartbeat(), c6_fwver_phase_caps(), c6_fwver_phase_request(), c6_fwver_puts(), c6_fwver_rpc_report(), k_c6_fwver_boot_wait_ms, k_ra8_ok, ra8_delay_ms(), ra8_err_to_str(), ra8_esp_hosted_mem_dump(), and s_c6_fwver_init_err.

Referenced by tx_application_define().

◆ main()

void main ( void )

Application entry: clocks, console, banner, then ThreadX.

The application entry point Reset_Handler hands control to.

Precondition
Reset_Handler has copied .data and zeroed .bss.
SystemInit has set VTOR, the FPU and the priority grouping.
Postcondition
The banner was printed exactly once.
Control passed to ThreadX and never came back.
Note
Everything after tx_kernel_enter happens on ThreadX; the panic-halt below is reached only if the kernel refuses to start.
Since
0.1.0

Definition at line 410 of file main.c.

References c6_fwver_panic_halt(), c6_fwver_print_banner(), c6_fwver_puts(), c6_fwver_setup_or_halt(), ra8_isr_globals_enable(), s_c6_fwver_cpuclk_hz, and s_c6_fwver_pclka_hz.

◆ tx_application_define()

void tx_application_define ( void * first_unused_memory)

ThreadX define hook: bring the port up and start the worker.

Parameters
[in]first_unused_memoryFree RAM handed over by the ThreadX port; unused, every object here is static.
Returns
Nothing.
Precondition
tx_kernel_enter has been called and the clock cache is valid.
No vendored esp-hosted entry point has been called yet.
Postcondition
s_c6_fwver_init_err holds the exact port-init result.
Exactly one worker thread was created.
Note
The port creates ThreadX byte pools, mutexes and timers, so its init must run where ThreadX permits object creation – here, not from main.
Since
0.1.0

Definition at line 374 of file main.c.

References c6_fwver_puts(), c6_fwver_worker_entry(), k_c6_fwver_edge_poll_ms, k_c6_fwver_sck_hz, k_c6_fwver_worker_prio, k_ra8_board_pmod1_sci_channel, ra8_esp_hosted_port_init(), s_c6_fwver_init_err, s_c6_fwver_pclka_hz, s_c6_fwver_worker, s_c6_fwver_worker_name, s_c6_fwver_worker_stack, TX_AUTO_START, TX_NO_TIME_SLICE, TX_SUCCESS, and tx_thread_create.

Variable Documentation

◆ s_c6_fwver_cpuclk_hz

uint32_t s_c6_fwver_cpuclk_hz
static

Cached CPUCLK0 rate, used to programme SysTick.

Read once during bring-up, before ThreadX starts.

Note
Single-threaded; written once from main.
Warning
Zero until c6_fwver_setup_or_halt has run.
Since
0.1.0

Definition at line 91 of file main.c.

Referenced by c6_fwver_setup_or_halt(), and main().

◆ s_c6_fwver_init_err

ra8_err_t s_c6_fwver_init_err = k_ra8_err_not_initialized
static

Exact result of ra8_esp_hosted_port_init.

Recorded in tx_application_define and reported verbatim by the worker, which is the first context that can print after the init.

Note
Written once before the scheduler starts, read afterwards.
Warning
A non-k_ra8_ok value stops the exchange; the application never continues as though the port had come up.
Since
0.1.0

Definition at line 115 of file main.c.

Referenced by c6_fwver_worker_entry(), and tx_application_define().

◆ s_c6_fwver_pclka_hz

uint32_t s_c6_fwver_pclka_hz
static

Cached PCLKA rate, the SCI baud-clock source the port divides.

Handed to the port as ra8_esp_hosted_port_cfg_t::pclk_hz; a stale value silently mis-programs the SPI bit rate, so it is read from the CGC rather than assumed.

Note
Single-threaded; written once from main.
Warning
Zero until c6_fwver_setup_or_halt has run.
Since
0.1.0

Definition at line 103 of file main.c.

Referenced by c6_fwver_setup_or_halt(), main(), and tx_application_define().

◆ s_c6_fwver_txbuf

uint8_t s_c6_fwver_txbuf[k_c6_fwver_tx_max]
static

Staging buffer for the one payload each phase transmits.

Sized by k_c6_fwver_tx_max, which is two orders of magnitude above the packed request; static because this image has no heap.

Note
Written only by the worker thread.
Warning
Reused between phases; a phase must finish before the next fills it.
Since
0.1.0

Definition at line 161 of file main.c.

Referenced by c6_fwver_phase_caps(), and c6_fwver_phase_request().

◆ s_c6_fwver_worker

TX_THREAD s_c6_fwver_worker
static

Control block of the single application thread.

ThreadX requires statically allocated control blocks, as does NASA Power of 10 Rule 3.

Note
Owned by ThreadX once tx_thread_create succeeds.
Warning
Never reused for a second thread.
Since
0.1.0

Definition at line 126 of file main.c.

Referenced by tx_application_define().

◆ s_c6_fwver_worker_name

CHAR s_c6_fwver_worker_name[] = "c6_fw_version"
static

Thread name handed to ThreadX.

A mutable array rather than a string literal: ThreadX takes a non-const CHAR*, and casting the qualifier away would trip the project's -Wcast-qual.

Note
Read by ThreadX for as long as the thread exists.
Warning
Never modified after creation; ThreadX keeps the pointer.
Since
0.1.0

Definition at line 138 of file main.c.

Referenced by tx_application_define().

◆ s_c6_fwver_worker_stack

UCHAR s_c6_fwver_worker_stack[k_c6_fwver_worker_stack]
static

Stack backing s_c6_fwver_worker.

Sized by k_c6_fwver_worker_stack. The deepest call the worker makes is the generated protobuf decoder, which walks nested messages.

Note
Written only by ThreadX and the worker itself.
Warning
Shrinking this without re-measuring risks a silent overflow.
Since
0.1.0

Definition at line 149 of file main.c.

Referenced by tx_application_define().