|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
Software edge detector for side-band pins the ICU cannot serve. More...
#include <stdint.h>#include "ra8_attributes.h"#include "ra8_err.h"#include "ra8_esp_hosted_gpio_internal.h"#include "ra8_icu_regs.h"#include "ra8_log.h"#include "ra8_pin_interface.h"#include "ra8_port_constants.h"#include "ra8_port_utils.h"#include "tx_api.h"Go to the source code of this file.
Data Structures | |
| struct | ra8_esp_hosted_gpio_edge_row |
| One pin under software edge detection. More... | |
Typedefs | |
| typedef struct ra8_esp_hosted_gpio_edge_row | ra8_esp_hosted_gpio_edge_row_t |
Enumerations | |
| enum | ra8_esp_hosted_gpio_edge_const_t : uint8_t { k_ra8_esp_hosted_gpio_edge_low = 0U , k_ra8_esp_hosted_gpio_edge_high = 1U , k_ra8_esp_hosted_gpio_edge_one_row = 1U } |
| Named constants the detector needs beyond the shared limits. More... | |
Functions | |
| 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. | |
| static uint8_t | internal_find (ra8_port_pin_t pin) |
| Find the row watching a pin. | |
| static bool | internal_sample (ra8_port_pin_t pin, uint8_t *out_level) |
| Read one pin through the slice's injected pin interface. | |
| static void | internal_timer_expiry (ULONG arg) |
| ThreadX expiry function: run one sampling pass. | |
| static ra8_err_t | internal_timer_arm (void) |
| Create the shared periodic timer if it is not already running. | |
| static ra8_err_t | internal_timer_disarm (void) |
| Delete the shared periodic timer if it is running. | |
| uint8_t | priv_ra8_esp_hosted_gpio_edge_count (void) |
| Report how many pins are under software edge detection. | |
| 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. | |
| void | priv_ra8_esp_hosted_gpio_edge_poll_once (void) |
| Sample every polled row once and dispatch the edges seen. | |
Variables | |
| static const char *const | s_tag = "eh_edge" |
| Log tag identifying lines emitted by the software edge detector. | |
| static ra8_esp_hosted_gpio_edge_row_t | s_rows [k_ra8_esp_hosted_gpio_row_max] |
| Every pin currently under software edge detection. | |
| static TX_TIMER | s_timer |
| The one periodic ThreadX timer shared by every polled row. | |
| static bool | s_timer_live |
| True while s_timer has been created and not yet deleted. | |
| static uint16_t | s_poll_ms = (uint16_t)k_ra8_esp_hosted_gpio_poll_ms_default |
| Sampling period in milliseconds, shared by every polled row. | |
| static char | s_tx_name_eh_edge [] = "eh_edge" |
| Writable ThreadX object name for the eh_edge object. | |
Software edge detector for side-band pins the ICU cannot serve.
On this package the ICU external-interrupt inputs are concentrated on port 0, so of the Pmod1 side-band nets only one has a channel. The rest still have to raise the vendored callback, and this file is how: one periodic ThreadX timer samples every registered pin, compares each sample against the level stored from the previous pass, and calls the pin's handler when the configured edge appears.
This is a real detector with a worse latency bound, not a placeholder. The bound is exactly one sampling period – the port's edge_poll_ms, two milliseconds by default – plus the timer thread's own scheduling latency. That is acceptable for this link because the co-processor holds DATA_READY asserted until the host takes the frame and holds HANDSHAKE asserted until the chip select falls, so neither line produces a pulse the sampler can miss; it only produces a later response than an ICU channel would.
Definition in file ra8_esp_hosted_gpio_edge.c.
| typedef struct ra8_esp_hosted_gpio_edge_row ra8_esp_hosted_gpio_edge_row_t |
| enum ra8_esp_hosted_gpio_edge_const_t : uint8_t |
Named constants the detector needs beyond the shared limits.
The two sampled levels are named so the table's stored level reads as a level rather than as an anonymous zero or one, and the timer's name is length-checked against nothing – ThreadX only stores the pointer.
| Enumerator | |
|---|---|
| k_ra8_esp_hosted_gpio_edge_low | Sample read low. |
| k_ra8_esp_hosted_gpio_edge_high | Sample read high. |
| k_ra8_esp_hosted_gpio_edge_one_row | Rows one registration adds. |
Definition at line 84 of file ra8_esp_hosted_gpio_edge.c.
|
static |
Find the row watching a pin.
Linear scan over a table of four; a scan cannot be indexed out of range and beats any structure at this size.
| [in] | pin | Packed pin to look for. |
| k_ra8_esp_hosted_gpio_row_max | The pin is not being sampled. |
pin is a packed RA8_PIN value. Definition at line 227 of file ra8_esp_hosted_gpio_edge.c.
References k_ra8_esp_hosted_gpio_row_max, pin, and s_rows.
Referenced by priv_ra8_esp_hosted_gpio_edge_register(), and priv_ra8_esp_hosted_gpio_edge_unregister().
|
static |
Read one pin through the slice's injected pin interface.
Folds the HAL's ra8_level_t onto the 0/1 the table stores, and reports read failure separately so the caller can leave the stored level alone rather than treat a failed read as a level change.
| [in] | pin | Packed pin to sample. |
| [out] | out_level | Receives 0 or 1; untouched when the read fails. |
| true | *out_level holds the sampled level. |
| false | The pin driver refused; *out_level is unchanged. |
out_level is non-null. Definition at line 262 of file ra8_esp_hosted_gpio_edge.c.
References ra8_pin_interface_t::ctx, k_ra8_esp_hosted_gpio_edge_high, k_ra8_esp_hosted_gpio_edge_low, k_ra8_level_high, k_ra8_level_low, k_ra8_ok, pin, priv_ra8_esp_hosted_gpio_pin_interface(), and ra8_pin_interface_t::read.
Referenced by priv_ra8_esp_hosted_gpio_edge_poll_once(), and priv_ra8_esp_hosted_gpio_edge_register().
|
static |
Create the shared periodic timer if it is not already running.
ThreadX takes the first expiry and the reschedule interval separately; both are the sampling period here, so the very first pass happens one period after the first registration rather than immediately. That is deliberate: the registration has just seeded every row's level from a live read, so a pass at tick zero could only report "no change".
| k_ra8_ok | The timer is running. |
| k_ra8_err_rtos_error | ThreadX refused to create it. |
Definition at line 325 of file ra8_esp_hosted_gpio_edge.c.
References internal_timer_expiry(), k_ra8_err_rtos_error, k_ra8_ok, ra8_log_error_val, s_poll_ms, s_tag, s_timer, s_timer_live, s_tx_name_eh_edge, and TX_SUCCESS.
Referenced by priv_ra8_esp_hosted_gpio_edge_register(), and priv_ra8_esp_hosted_gpio_set_edge_poll_ms().
|
static |
Delete the shared periodic timer if it is running.
Called when the last row goes, so a torn-down port leaves no kernel object behind, and by the period setter so a new period can be re-armed.
| k_ra8_ok | No timer is running. |
| k_ra8_err_rtos_error | ThreadX refused to delete it. |
Definition at line 367 of file ra8_esp_hosted_gpio_edge.c.
References k_ra8_err_rtos_error, k_ra8_ok, ra8_log_error_val, s_tag, s_timer, s_timer_live, and TX_SUCCESS.
Referenced by priv_ra8_esp_hosted_gpio_edge_unregister(), and priv_ra8_esp_hosted_gpio_set_edge_poll_ms().
|
static |
ThreadX expiry function: run one sampling pass.
A one-line shim so the pass itself stays callable from a test without a kernel. It takes ThreadX's ULONG argument and discards it: the pass walks the whole table, so there is nothing per-timer to carry.
| [in] | arg | ThreadX expiry argument; unused. |
Definition at line 295 of file ra8_esp_hosted_gpio_edge.c.
References priv_ra8_esp_hosted_gpio_edge_poll_once().
Referenced by internal_h_timer_start(), and internal_timer_arm().
|
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.
| 0 | No pin is polled; the periodic timer is not running. |
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().
| 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.
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().
|
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.
| [in] | pin | Packed pin to watch; must be a legal RA8 pin. |
| [in] | sense | Edge selector using the ra8_icu_irqmd_t encoding: 0 falling, 1 rising, 2 both, 3 low level. |
| [in] | handler | Callback invoked on a detected edge; must be non-null and must not block. |
| [in] | arg | Opaque argument handed back to handler. |
| k_ra8_ok | The pin is being sampled. |
| k_ra8_err_null_ptr | handler was null. |
| k_ra8_err_invalid_arg | sense was outside 0..3. |
| k_ra8_err_exists | The pin already has a row. |
| k_ra8_err_no_mem | The table is full. |
| k_ra8_err_rtos_error | The periodic timer would not arm. |
| k_ra8_err_gpio_conflict | The pin is owned by another module. |
handler tolerates being called from timer context. 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().
|
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.
| [in] | prev_level | Level recorded by the previous sample: 0 or 1. |
| [in] | now_level | Level just read: 0 or 1. |
| [in] | sense | Selector using the ra8_icu_irqmd_t encoding: 0 falling, 1 rising, 2 both, 3 low level. |
| true | The handler should run. |
| false | No event, or sense was outside 0..3. |
prev_level and now_level are 0 or 1. sense uses the ICU encoding, not the vendored polarity flags. 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().
|
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.
| [in] | pin | Packed pin previously passed to priv_ra8_esp_hosted_gpio_edge_register. |
| k_ra8_ok | The row was freed. |
| k_ra8_err_not_found | The pin had no row. |
| k_ra8_err_rtos_error | The timer would not stop. |
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().
|
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.
| [in] | period_ms | Sampling period in milliseconds; must be non-zero, because ThreadX rejects a zero-tick timer. |
| k_ra8_ok | The period was accepted. |
| k_ra8_err_invalid_arg | period_ms was zero. |
| k_ra8_err_rtos_error | The timer could not be re-armed. |
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. period_ms. 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().
|
static |
Sampling period in milliseconds, shared by every polled row.
The ThreadX tick on this board is 1 kHz, so the millisecond-to- tick conversion is the identity and this value is also the tick count.
Definition at line 166 of file ra8_esp_hosted_gpio_edge.c.
Referenced by internal_timer_arm(), and priv_ra8_esp_hosted_gpio_set_edge_poll_ms().
|
static |
Every pin currently under software edge detection.
Statically sized (NASA Power of 10 Rule 3); a registration that does not fit is refused rather than allocated.
Definition at line 130 of file ra8_esp_hosted_gpio_edge.c.
Referenced by internal_find(), priv_ra8_esp_hosted_gpio_edge_count(), priv_ra8_esp_hosted_gpio_edge_poll_once(), priv_ra8_esp_hosted_gpio_edge_register(), and priv_ra8_esp_hosted_gpio_edge_unregister().
|
static |
Log tag identifying lines emitted by the software edge detector.
Distinct from the GPIO slice's own tag so a reader can tell a polled-path refusal from a slot-level one.
Definition at line 59 of file ra8_esp_hosted_gpio_edge.c.
|
static |
The one periodic ThreadX timer shared by every polled row.
One timer for the whole table rather than one per pin: the sampling pass is a handful of register reads, so a second timer would cost more than it saves.
Definition at line 143 of file ra8_esp_hosted_gpio_edge.c.
Referenced by internal_timer_arm(), and internal_timer_disarm().
|
static |
True while s_timer has been created and not yet deleted.
ThreadX has no "is this control block live" query, so the fact is tracked here; without it a second registration would try to create an already-created timer.
Definition at line 155 of file ra8_esp_hosted_gpio_edge.c.
Referenced by internal_timer_arm(), internal_timer_disarm(), and priv_ra8_esp_hosted_gpio_set_edge_poll_ms().
|
static |
Writable ThreadX object name for the eh_edge object.
ThreadX takes object names as CHAR* rather than const CHAR*, so a string literal would have to be cast and would drop a qualifier the object really has. A writable array removes the cast instead of hiding it.
Definition at line 179 of file ra8_esp_hosted_gpio_edge.c.
Referenced by internal_timer_arm().