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

Module-private surface of the esp-hosted side-band GPIO slice. More...

#include <stdint.h>
#include "esp_hosted_os_abstraction.h"
#include "ra8_attributes.h"
#include "ra8_err.h"
#include "ra8_pin_interface.h"
#include "ra8_port_constants.h"
Include dependency graph for ra8_esp_hosted_gpio_internal.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Enumerations

enum  ra8_esp_hosted_gpio_limits_t : uint8_t {
  k_ra8_esp_hosted_gpio_row_max = 4U ,
  k_ra8_esp_hosted_gpio_poll_ms_default = 2U ,
  k_ra8_esp_hosted_gpio_irq_priority = 6U
}
 Fixed bounds of the side-band GPIO slice. More...

Functions

ra8_err_t priv_ra8_esp_hosted_gpio_bind (hosted_osi_funcs_t *out)
 Populate the eight GPIO slots of the OS-abstraction vtable.
bool priv_ra8_esp_hosted_gpio_decode_pin (const void *gpio_port, uint32_t gpio_num, ra8_port_pin_t *out_pin)
 Decode the vendored (void* port, uint32_t pin) pair into a pin.
void priv_ra8_esp_hosted_gpio_set_pin_interface (const ra8_pin_interface_t *iface)
 Replace the pin driver the slice reads and writes levels through.
const ra8_pin_interface_tpriv_ra8_esp_hosted_gpio_pin_interface (void)
 Report the pin driver currently installed in the slice.
ra8_err_t priv_ra8_esp_hosted_gpio_set_edge_poll_ms (uint16_t period_ms)
 Set the sampling period the software edge detector runs at.
ra8_err_t priv_ra8_esp_hosted_gpio_edge_register (ra8_port_pin_t pin, uint8_t sense, void(*handler)(void *), void *arg)
 Take a pin under software edge detection.
ra8_err_t priv_ra8_esp_hosted_gpio_edge_unregister (ra8_port_pin_t pin)
 Drop a pin from software edge detection.
uint8_t priv_ra8_esp_hosted_gpio_edge_count (void)
 Report how many pins are under software edge detection.
void priv_ra8_esp_hosted_gpio_edge_poll_once (void)
 Sample every polled row once and dispatch the edges seen.
bool priv_ra8_esp_hosted_gpio_edge_seen (uint8_t prev_level, uint8_t now_level, uint8_t sense)
 Decide whether two consecutive samples show the configured edge.

Detailed Description

Module-private surface of the esp-hosted side-band GPIO slice.

Tag
[Ring 4 / PORT] {World: NS}

The vendored esp-hosted core reaches every side-band pin through eight slots of hosted_osi_funcs_t. ra8_esp_hosted_gpio.c fills those slots; ra8_esp_hosted_gpio_edge.c owns the software edge detector the slots fall back on. This header is the seam between those two translation units and the tests, and nothing outside port/esp-hosted/ may include it.

Why a software edge detector exists at all
On this package the ICU external-interrupt inputs are concentrated on port 0, so of the Pmod1 side-band nets only one (P006 -> IRQ11) can raise a hardware edge. ra8_esp_hosted_pin_irq_num reports that per pin, and _h_config_gpio_as_interrupt picks the path accordingly: an ICU channel when one exists, otherwise a row in the polled table below. Both paths deliver the same callback with the same argument, so the vendored driver cannot tell them apart – only the latency differs.
Since
0.1.0

Definition in file ra8_esp_hosted_gpio_internal.h.

Enumeration Type Documentation

◆ ra8_esp_hosted_gpio_limits_t

Fixed bounds of the side-band GPIO slice.

The link uses four side-band nets at most – chip select, HANDSHAKE, DATA_READY and the co-processor reset – and only the ones configured as interrupts take a table row, so four rows can never be exhausted by the vendored driver. The bound is stated anyway because a registration that cannot be recorded must fail loudly rather than be silently dropped.

Invariant
k_ra8_esp_hosted_gpio_row_max is the exact row count of the edge table; priv_ra8_esp_hosted_gpio_edge_count never exceeds it.
k_ra8_esp_hosted_gpio_poll_ms_default is non-zero, so the detector can always arm a legal ThreadX timer.
Example:
static_assert(k_ra8_esp_hosted_gpio_row_max >= 2U, "handshake + data ready");
@ k_ra8_esp_hosted_gpio_row_max
Rows in the polled edge table; also the registration ceiling.
See also
priv_ra8_esp_hosted_gpio_edge_register
Since
0.1.0
Enumerator
k_ra8_esp_hosted_gpio_row_max 

Rows in the polled edge table; also the registration ceiling.

k_ra8_esp_hosted_gpio_poll_ms_default 

Sampling period used until priv_ra8_esp_hosted_gpio_set_edge_poll_ms runs.

k_ra8_esp_hosted_gpio_irq_priority 

NVIC priority given to a hardware side-band edge.

Definition at line 64 of file ra8_esp_hosted_gpio_internal.h.

Function Documentation

◆ priv_ra8_esp_hosted_gpio_bind()

ra8_err_t priv_ra8_esp_hosted_gpio_bind ( hosted_osi_funcs_t * out)
nodiscard

Populate the eight GPIO slots of the OS-abstraction vtable.

Writes _h_config_gpio, _h_config_gpio_as_interrupt, _h_teardown_gpio_interrupt, _h_read_gpio, _h_write_gpio, _h_pull_gpio, _h_hold_gpio and _h_get_host_wakeup_or_reboot_reason into out. No other slot is touched, so the RTOS and transport slices may fill theirs before or after this call in any order.

Parameters
[out]outVtable to populate; must be non-null. Only the eight GPIO rows are written.
Returns
ra8_err_t Error code.
Return values
k_ra8_okThe eight rows are populated.
k_ra8_err_null_ptrout was null.
Precondition
out points at storage that out-lives the vendored core.
The pin map in ra8_esp_hosted_pins.h describes the live harness.
Postcondition
The eight GPIO rows of out are non-null.
No non-GPIO row of out is modified.
Note
Not thread-safe; call once from the port's bring-up path.
Warning
Binding does not claim a pin. Pins are claimed lazily by the slots, which is what lets a failed bring-up leave none stranded.
Example:
ra8_err_t priv_ra8_esp_hosted_gpio_bind(hosted_osi_funcs_t *out)
Populate the eight GPIO slots of the OS-abstraction vtable.
hosted_osi_funcs_t g_hosted_osi_funcs
The OS-abstraction vtable the vendored core calls through.
See also
priv_ra8_esp_hosted_spi_bind
Since
0.1.0

Definition at line 776 of file ra8_esp_hosted_gpio.c.

References internal_config_gpio(), internal_config_gpio_as_interrupt(), internal_hold_gpio(), internal_pull_gpio(), internal_read_gpio(), internal_teardown_gpio_interrupt(), internal_wakeup_reason(), internal_write_gpio(), k_ra8_err_invalid_state, k_ra8_ok, RA8_CHECK_NULL_PTR, RA8_PRIV, and s_tag.

Referenced by priv_ra8_esp_hosted_osi_bind_all().

◆ priv_ra8_esp_hosted_gpio_decode_pin()

bool priv_ra8_esp_hosted_gpio_decode_pin ( const void * gpio_port,
uint32_t gpio_num,
ra8_port_pin_t * out_pin )
nodiscard

Decode the vendored (void* port, uint32_t pin) pair into a pin.

Exact inverse of RA8_ESP_HOSTED_GPIO_PORT / RA8_ESP_HOSTED_GPIO_PIN in port_esp_hosted_host_config.h: the port half is an index carried inside a pointer, so port 0 arrives as a null pointer and must NOT be null-checked – the decoded index is range-checked instead. The pin half arrives as uint32_t, so the vendored -1 "not wired" spelling arrives as 0xFFFFFFFF; that value is rejected explicitly rather than only by the range test, because it is a distinct fact about the harness.

Parameters
[in]gpio_portPort index in pointer clothing. Never dereferenced.
[in]gpio_numPin index within the port, or 0xFFFFFFFF for a signal this harness does not wire.
[out]out_pinReceives the packed RA8_PIN(port, pin) value. Untouched on any rejection.
Returns
Whether the pair named a legal RA8 pin.
Return values
true*out_pin holds the packed pin.
falseout_pin was null, the signal is unwired, or an index was out of range.
Precondition
out_pin is writable when non-null.
gpio_port was produced by RA8_ESP_HOSTED_GPIO_PORT.
Postcondition
On false no output is written.
On true the decoded port is <= k_ra8_port_max and the decoded pin is <= k_ra8_pin_max.
Note
Pure function; safe from interrupt context.
MC/DC:
Decision: (gpio_num == unwired) || (port_idx > port_max) || (gpio_num > pin_max) (3 conditions). Vectors: (F,F,F) accepts; (T,F,F), (F,T,F) and (F,F,T) each reject. Pairing the accepting vector with each rejecting one proves that condition's independent influence: N+1 = 4 vectors.
Example:
(uint32_t)H_GPIO_DATA_READY_Pin, &pin)) {
(void)ra8_gpio_read(pin, &level);
}
#define H_GPIO_DATA_READY_Port
Opaque port handle of the DATA_READY input.
#define H_GPIO_DATA_READY_Pin
Pin index of the DATA_READY input, or -1 when it is not wired.
ra8_board_eth_pin_t pin
Pin.
bool priv_ra8_esp_hosted_gpio_decode_pin(const void *gpio_port, uint32_t gpio_num, ra8_port_pin_t *out_pin)
Decode the vendored (void* port, uint32_t pin) pair into a pin.
ra8_port_pin_t
Packed (port << 8) | pin pin identifier.
@ k_ra8_pin_none
Sentinel: no pin selected.
ra8_err_t ra8_gpio_read(ra8_port_pin_t pin, ra8_level_t *out_level)
Read a previously-configured input.
Definition gpio.c:210
See also
priv_ra8_esp_hosted_gpio_bind
Since
0.1.0

Definition at line 212 of file ra8_esp_hosted_gpio.c.

References k_ra8_esp_hosted_gpio_pin_unwired, k_ra8_pin_max, k_ra8_port_max, RA8_PIN, and RA8_PRIV.

Referenced by internal_config_gpio(), internal_config_gpio_as_interrupt(), internal_hold_gpio(), internal_pull_gpio(), internal_read_gpio(), internal_teardown_gpio_interrupt(), and internal_write_gpio().

◆ priv_ra8_esp_hosted_gpio_edge_count()

uint8_t priv_ra8_esp_hosted_gpio_edge_count ( void )
nodiscard

Report how many pins are under software edge detection.

Reads the table occupancy. Exists so the port and the tests can assert the detector's state – in particular that teardown emptied it – without reaching into the module's storage.

Returns
Occupied rows, 0 .. k_ra8_esp_hosted_gpio_row_max.
Return values
0No pin is polled; the periodic timer is not running.
Precondition
None; safe to call before any registration.
The caller tolerates a value a concurrent registration may stale.
Postcondition
No module state is modified.
The result never exceeds k_ra8_esp_hosted_gpio_row_max.
Note
Safe from interrupt context.
Example:
uint8_t priv_ra8_esp_hosted_gpio_edge_count(void)
Report how many pins are under software edge detection.
See also
priv_ra8_esp_hosted_gpio_edge_register
Since
0.1.0

Definition at line 381 of file ra8_esp_hosted_gpio_edge.c.

References k_ra8_esp_hosted_gpio_edge_one_row, k_ra8_esp_hosted_gpio_row_max, RA8_PRIV, and s_rows.

Referenced by priv_ra8_esp_hosted_gpio_edge_unregister().

◆ priv_ra8_esp_hosted_gpio_edge_poll_once()

void priv_ra8_esp_hosted_gpio_edge_poll_once ( void )

Sample every polled row once and dispatch the edges seen.

The body of the periodic timer, exposed so tests drive it directly rather than waiting on a kernel tick. For each occupied row it reads the pin through the injected pin interface, asks priv_ra8_esp_hosted_gpio_edge_seen whether the configured edge occurred, stores the new level and, when it did, calls the row's handler. A read that fails leaves the stored level untouched so a transient failure cannot manufacture an edge on the next pass.

Precondition
A pin interface is installed (one always is).
Row handlers do not block and do not re-enter this function.
Postcondition
Every occupied row's stored level matches its last good read.
One handler call was made per row that showed its configured edge.
Note
Runs from timer context in production; must not block.
MC/DC:
Decision: if (row->used && read_ok) (2 conditions). Vectors: used=T read_ok=T dispatches; used=F read_ok=T skips; used=T read_ok=F skips. Vectors 1+2 prove used influences the outcome independently, 1+3 do the same for read_ok: N+1 = 3 vectors.
Example:
void priv_ra8_esp_hosted_gpio_edge_poll_once(void)
Sample every polled row once and dispatch the edges seen.
See also
priv_ra8_esp_hosted_gpio_edge_seen
Since
0.1.0

Definition at line 467 of file ra8_esp_hosted_gpio_edge.c.

References ra8_esp_hosted_gpio_edge_row::arg, ra8_esp_hosted_gpio_edge_row::handler, internal_sample(), k_ra8_esp_hosted_gpio_edge_low, k_ra8_esp_hosted_gpio_row_max, ra8_esp_hosted_gpio_edge_row::last_level, ra8_esp_hosted_gpio_edge_row::pin, priv_ra8_esp_hosted_gpio_edge_seen(), RA8_PRIV, s_rows, ra8_esp_hosted_gpio_edge_row::sense, and ra8_esp_hosted_gpio_edge_row::used.

Referenced by internal_timer_expiry().

◆ priv_ra8_esp_hosted_gpio_edge_register()

ra8_err_t priv_ra8_esp_hosted_gpio_edge_register ( ra8_port_pin_t pin,
uint8_t sense,
void(* handler )(void *),
void * arg )
nodiscard

Take a pin under software edge detection.

Configures the pin as an input, records the level it starts at so the first sample cannot report a phantom edge, and arms the shared periodic timer if this is the first row. The row stores the vendored callback and its argument verbatim, so a polled pin and an ICU-served pin deliver identical calls.

Parameters
[in]pinPacked pin to watch; must be a legal RA8 pin.
[in]senseEdge selector using the ra8_icu_irqmd_t encoding: 0 falling, 1 rising, 2 both, 3 low level.
[in]handlerCallback invoked on a detected edge; must be non-null and must not block.
[in]argOpaque argument handed back to handler.
Returns
ra8_err_t Error code.
Return values
k_ra8_okThe pin is being sampled.
k_ra8_err_null_ptrhandler was null.
k_ra8_err_invalid_argsense was outside 0..3.
k_ra8_err_existsThe pin already has a row.
k_ra8_err_no_memThe table is full.
k_ra8_err_rtos_errorThe periodic timer would not arm.
k_ra8_err_gpio_conflictThe pin is owned by another module.
Precondition
The ThreadX kernel is running.
handler tolerates being called from timer context.
Postcondition
On success priv_ra8_esp_hosted_gpio_edge_count has grown by one.
On any failure no row is added and no pin is left claimed by this call.
Note
Not thread-safe with respect to the timer callback.
Warning
Detection latency is bounded by the sampling period, not by the pin: an edge shorter than one period can be missed entirely.
Example:
(void)priv_ra8_esp_hosted_gpio_edge_register(pin, 1U, gpio_hs_isr_handler, nullptr);
ra8_err_t priv_ra8_esp_hosted_gpio_edge_register(ra8_port_pin_t pin, uint8_t sense, void(*handler)(void *), void *arg)
Take a pin under software edge detection.
See also
priv_ra8_esp_hosted_gpio_edge_unregister
Since
0.1.0

Definition at line 405 of file ra8_esp_hosted_gpio_edge.c.

References internal_find(), internal_sample(), internal_timer_arm(), k_ra8_err_exists, k_ra8_err_invalid_arg, k_ra8_err_no_mem, k_ra8_err_null_ptr, k_ra8_esp_hosted_gpio_edge_low, k_ra8_esp_hosted_gpio_row_max, k_ra8_icu_irqmd_low, k_ra8_ok, k_ra8_pull_none, pin, ra8_gpio_input_init(), ra8_gpio_release(), ra8_log_error_val, RA8_PRIV, s_rows, and s_tag.

Referenced by internal_config_gpio_as_interrupt().

◆ priv_ra8_esp_hosted_gpio_edge_seen()

bool priv_ra8_esp_hosted_gpio_edge_seen ( uint8_t prev_level,
uint8_t now_level,
uint8_t sense )
nodiscard

Decide whether two consecutive samples show the configured edge.

The whole decision logic of the software edge detector, kept pure so it can be driven exhaustively without hardware. Edge senses compare the two samples; the low-level sense is not an edge at all and reports on the current sample alone, which matches what the ICU does with k_ra8_icu_irqmd_low.

Parameters
[in]prev_levelLevel recorded by the previous sample: 0 or 1.
[in]now_levelLevel just read: 0 or 1.
[in]senseSelector using the ra8_icu_irqmd_t encoding: 0 falling, 1 rising, 2 both, 3 low level.
Returns
Whether the configured event is present.
Return values
trueThe handler should run.
falseNo event, or sense was outside 0..3.
Precondition
prev_level and now_level are 0 or 1.
sense uses the ICU encoding, not the vendored polarity flags.
Postcondition
No state is modified.
An out-of-range sense reports no event rather than guessing one.
Note
Pure function; safe from interrupt context.
MC/DC:
Every decision here is single-condition, so each needs two vectors: the range guard (sense=3 in range / sense=4 out of range), the level-sense test (sense=3 vs sense<3), the change test (prev==now / prev!=now), the both-edge test (sense=2 / sense!=2) and the rising test (sense=1 / sense=0). Sweeping all four senses across all four (prev, now) pairs covers every one of them.
Example:
if (priv_ra8_esp_hosted_gpio_edge_seen(0U, 1U, 1U)) { handler(arg); }
bool priv_ra8_esp_hosted_gpio_edge_seen(uint8_t prev_level, uint8_t now_level, uint8_t sense)
Decide whether two consecutive samples show the configured edge.
See also
priv_ra8_esp_hosted_gpio_edge_poll_once
Since
0.1.0

Definition at line 182 of file ra8_esp_hosted_gpio_edge.c.

References k_ra8_esp_hosted_gpio_edge_high, k_ra8_esp_hosted_gpio_edge_low, k_ra8_icu_irqmd_both, k_ra8_icu_irqmd_low, and k_ra8_icu_irqmd_rising.

Referenced by priv_ra8_esp_hosted_gpio_edge_poll_once().

◆ priv_ra8_esp_hosted_gpio_edge_unregister()

ra8_err_t priv_ra8_esp_hosted_gpio_edge_unregister ( ra8_port_pin_t pin)
nodiscard

Drop a pin from software edge detection.

Frees the row, releases the pin claim and, when the last row goes, deletes the shared periodic timer so a torn-down port leaves no kernel object running.

Parameters
[in]pinPacked pin previously passed to priv_ra8_esp_hosted_gpio_edge_register.
Returns
ra8_err_t Error code.
Return values
k_ra8_okThe row was freed.
k_ra8_err_not_foundThe pin had no row.
k_ra8_err_rtos_errorThe timer would not stop.
Precondition
The timer callback is not executing.
The pin was registered by this module.
Postcondition
priv_ra8_esp_hosted_gpio_edge_count has fallen by one.
The pin is no longer claimed by this module.
Note
Not thread-safe with respect to the timer callback.
Example:
ra8_err_t priv_ra8_esp_hosted_gpio_edge_unregister(ra8_port_pin_t pin)
Drop a pin from software edge detection.
See also
priv_ra8_esp_hosted_gpio_edge_register
Since
0.1.0

Definition at line 453 of file ra8_esp_hosted_gpio_edge.c.

References internal_find(), internal_timer_disarm(), k_ra8_err_not_found, k_ra8_esp_hosted_gpio_row_max, k_ra8_ok, pin, priv_ra8_esp_hosted_gpio_edge_count(), ra8_gpio_release(), RA8_PRIV, and s_rows.

Referenced by internal_teardown_gpio_interrupt().

◆ priv_ra8_esp_hosted_gpio_pin_interface()

const ra8_pin_interface_t * priv_ra8_esp_hosted_gpio_pin_interface ( void )
nodiscard

Report the pin driver currently installed in the slice.

Exists so the edge detector, which lives in its own translation unit, can sample levels through exactly the interface the slots write through. It never returns null: an unset seam reads back as the production instance.

Returns
The installed pin interface.
Return values
non-nullAlways; the production instance when nothing was injected.
Precondition
The slice has been linked against libs/ra8_hal.
The caller does not retain the pointer across a seam swap.
Postcondition
No module state is modified.
The returned interface has non-null read and write rows.
Note
Safe from interrupt context; a single aligned load.
Example:
const ra8_pin_interface_t * priv_ra8_esp_hosted_gpio_pin_interface(void)
Report the pin driver currently installed in the slice.
Vtable for a pin driver.
See also
priv_ra8_esp_hosted_gpio_set_pin_interface
Since
0.1.0

Definition at line 233 of file ra8_esp_hosted_gpio.c.

References g_ra8_gpio_pin_interface, RA8_PRIV, and s_pin_if.

Referenced by internal_config_gpio(), internal_read_gpio(), internal_sample(), and internal_write_gpio().

◆ priv_ra8_esp_hosted_gpio_set_edge_poll_ms()

ra8_err_t priv_ra8_esp_hosted_gpio_set_edge_poll_ms ( uint16_t period_ms)
nodiscard

Set the sampling period the software edge detector runs at.

Applies to the single periodic ThreadX timer shared by every polled row. Changing it while rows are registered re-arms the timer, so the new period takes effect from the next expiry. The port passes ra8_esp_hosted_port_cfg_t::edge_poll_ms here during bring-up.

Parameters
[in]period_msSampling period in milliseconds; must be non-zero, because ThreadX rejects a zero-tick timer.
Returns
ra8_err_t Error code.
Return values
k_ra8_okThe period was accepted.
k_ra8_err_invalid_argperiod_ms was zero.
k_ra8_err_rtos_errorThe timer could not be re-armed.
Precondition
The ThreadX kernel is running when rows are already registered.
period_ms is small enough that an edge cannot be missed; the C6 holds DATA_READY asserted until the frame is taken, so any period shorter than a transaction is safe.
Postcondition
The detector's period reads back as period_ms.
No registered row is lost by the change.
Note
Not thread-safe; call from the port's bring-up path.
Example:
ra8_err_t priv_ra8_esp_hosted_gpio_set_edge_poll_ms(uint16_t period_ms)
Set the sampling period the software edge detector runs at.
See also
priv_ra8_esp_hosted_gpio_edge_poll_once
Since
0.1.0

Definition at line 392 of file ra8_esp_hosted_gpio_edge.c.

References internal_timer_arm(), internal_timer_disarm(), k_ra8_err_invalid_arg, k_ra8_ok, RA8_PRIV, s_poll_ms, and s_timer_live.

Referenced by internal_bring_up().

◆ priv_ra8_esp_hosted_gpio_set_pin_interface()

void priv_ra8_esp_hosted_gpio_set_pin_interface ( const ra8_pin_interface_t * iface)

Replace the pin driver the slice reads and writes levels through.

Dependency-injection seam. Production leaves it at g_ra8_gpio_pin_interface; host tests point it at a recorder so pin levels can be driven without hardware. The interface covers output_init, write, read and toggle only, so input configuration, pin release and interrupt attachment still call the HAL directly – those have no row in ra8_pin_interface_t.

Parameters
[in]ifaceReplacement interface, or null to restore the production instance. Must out-live every later slot call.
Precondition
iface, when non-null, has non-null write and read rows.
No slot call is in flight on another thread.
Postcondition
Later reads and writes go through iface.
Passing null restores the production pin driver.
Note
Not thread-safe; intended for bring-up and for tests.
Warning
Swapping the interface does not re-configure any pin; the rows the previous interface configured stay as they were.
Example:
void priv_ra8_esp_hosted_gpio_set_pin_interface(const ra8_pin_interface_t *iface)
Replace the pin driver the slice reads and writes levels through.
See also
priv_ra8_esp_hosted_gpio_pin_interface
Since
0.1.0

Definition at line 228 of file ra8_esp_hosted_gpio.c.

References RA8_PRIV, and s_pin_if.