|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
Pmod1 side-band sampling, wire test, pull-up contest, chip-select hunt. More...
#include <stdint.h>#include "c6_probe.h"#include "ra8_board_ek_ra8d2.h"#include "ra8_err.h"#include "ra8_port_utils.h"#include "ra8_time.h"Go to the source code of this file.
Functions | |
| ra8_err_t | c6_probe_sideband_init (void) |
| Claim the four Pmod1 side-band pins as no-pull digital inputs. | |
| void | c6_probe_sample_sideband (c6_sideband_sample_t *out) |
| Read every Pmod1 side-band pin into one sample. | |
| const char * | c6_probe_sideband_name (uint8_t idx) |
| Name a side-band pin for the console. | |
| void | c6_probe_print_sideband (const char *label, const c6_sideband_sample_t *s) |
| Print a labelled side-band sample as label P006=1 P402=0 .... | |
| void | c6_probe_vote (const c6_sideband_sample_t *pre, const c6_sideband_sample_t *mid, const c6_sideband_sample_t *post, c6_probe_stats_t *st) |
| Fold one transaction's three samples into the classification votes. | |
| uint8_t | c6_probe_best (const uint32_t *votes, uint8_t ignore, uint32_t min_votes) |
| Pick the side-band pin that won the vote outright, or report none. | |
| static ra8_err_t | internal_pull_read (ra8_port_pin_t pin, uint8_t *out_low) |
| Hold one pin against the internal pull-up and count the low reads. | |
| ra8_err_t | c6_probe_pull_contest (c6_probe_stats_t *st) |
| Find which side-band pins an external driver is holding low. | |
| uint8_t | c6_probe_sunk_pin (const c6_probe_stats_t *st, uint8_t ignore) |
| Name the one pin that lost every read of the pull-up contest. | |
| void | c6_probe_resolve_map (const c6_probe_stats_t *st, uint8_t *hs_idx, uint8_t *dr_idx) |
| Resolve the HANDSHAKE and DATA_READY side-band map from the accumulated evidence. | |
| static ra8_err_t | internal_kick_net (ra8_port_pin_t pin, ra8_level_t level, uint8_t *out_level) |
| Drive one net to a level, release it, and sample what it settles to. | |
| c6_wire_kind_t | c6_probe_wire_kind (uint8_t after_high, uint8_t after_low) |
| Classify one Pmod1 net from its two drive-and-release samples. | |
| void | c6_probe_wire_test (void) |
| Run the drive-and-release test over every Pmod1 muxed net. | |
| static bool | internal_cs_try (uint8_t idx, c6_probe_stats_t *st) |
| Assert one candidate chip-select and report any side-band response. | |
| uint8_t | c6_probe_cs_hunt (c6_probe_stats_t *st) |
| Find which MCU pin the board's Pmod1 mux has wired to the C6's chip-select, and identify HANDSHAKE at the same time. | |
Variables | |
| static const ra8_port_pin_t | k_c6_sideband_pin [k_c6_sb_count] |
| The four Pmod1 side-band pins, in c6_sideband_idx_t order. | |
| static const char *const | k_c6_sideband_label [k_c6_sb_count+1U] |
| Console labels for k_c6_sideband_pin, same order. | |
| static const ra8_port_pin_t | k_c6_wire_pin [k_c6_wire_count] |
| The five Pmod1 muxed-net candidates, in c6_wire_idx_t order. | |
| static const char *const | k_c6_wire_label [k_c6_wire_count+1U] |
| Console labels for k_c6_wire_pin, same order. | |
Pmod1 side-band sampling, wire test, pull-up contest, chip-select hunt.
Everything the probe knows about the physical side of the Pmod1 link lives here. Three facts about the C6 image in coprocessor/esp32c6/ make these diagnostics possible without any working data path:
Definition in file c6_sideband.c.
| uint8_t c6_probe_best | ( | const uint32_t * | votes, |
| uint8_t | ignore, | ||
| uint32_t | min_votes ) |
Pick the side-band pin that won the vote outright, or report none.
A winner must clear two bars, and both exist because the bench produced the failure they prevent. It must reach min_votes, so one transition on a floating pin cannot name a mapping; and it must be a strict winner, so a tie is reported as unresolved rather than silently broken by table order. Reporting "unresolved" is a useful answer here – claiming the wrong pin is not.
| [in] | votes | Per-pin vote counters. |
| [in] | ignore | Index to skip, or k_c6_sb_count to skip nothing. |
| [in] | min_votes | Smallest vote count that may claim a mapping; must be at least one. |
| k_c6_sb_count | No pin reached min_votes, the top score was tied, votes was NULL, or min_votes was zero. |
Definition at line 180 of file c6_sideband.c.
References k_c6_sb_count.
Referenced by c6_probe_resolve_map(), c6_probe_run(), and c6_probe_sweep_mode().
| uint8_t c6_probe_cs_hunt | ( | c6_probe_stats_t * | st | ) |
Find which MCU pin the board's Pmod1 mux has wired to the C6's chip-select, and identify HANDSHAKE at the same time.
The C6 image sets CONFIG_ESP_SPI_DEASSERT_HS_ON_CS=y, so its chip-select edge interrupt drops HANDSHAKE the moment chip-select is asserted and re-raises it once the next transaction is queued (gpio_disable_hs_isr_handler / spi_post_setup_cb in the C6's peripheral-side SPI driver). Asserting each muxed-net candidate in turn and watching for a side-band pin to drop therefore needs no clock, no payload and no working data path: the pin that provokes the drop is the real chip-select, and the pin that drops is HANDSHAKE.
| [in,out] | st | Statistics block; handshake votes are accumulated here. |
| k_c6_wire_count | No candidate provoked a side-band response. |
Definition at line 485 of file c6_sideband.c.
References c6_probe_puts(), internal_cs_try(), k_c6_wire_count, and k_c6_wire_label.
Referenced by main().
| void c6_probe_print_sideband | ( | const char * | label, |
| const c6_sideband_sample_t * | s ) |
Print a labelled side-band sample as label P006=1 P402=0 ....
| [in] | label | Short prefix, already indented by the caller. |
| [in] | s | Sample to print; ignored when NULL. |
Definition at line 141 of file c6_sideband.c.
References c6_probe_put_u32(), c6_probe_puts(), c6_probe_sideband_name(), k_c6_sb_count, and c6_sideband_sample_t::level.
Referenced by internal_cs_try(), internal_one_xfer(), and main().
|
nodiscard |
Find which side-band pins an external driver is holding low.
Re-claims each side-band pin as an input with the RA8D2's internal pull-up engaged, reads it k_c6_probe_pull_samples times, and restores it to a no-pull input. A pin with nothing on it is pulled high and reads high every time; a pin that keeps reading low is losing a current fight to something off-chip, which nothing floating can imitate. That is the strongest "this pin is connected" evidence the probe can gather, and it needs no cooperation from the C6 whatsoever.
It is what identifies DATA_READY. An esp-hosted peripheral with an empty transmit queue holds DATA_READY low by design, so across a whole probe run that pin moves once at most, and usually where nothing is sampling. The pin that matters most is therefore the one a transition-counting rule cannot see – and the one this rule reads without ambiguity.
One line per pin is printed, so the raw count is in the log even when the verdict is unresolved.
| [in,out] | st | Statistics block; pull_low and pull_samples are written. |
| k_ra8_ok | Every pin was tested and restored to a no-pull input. |
| k_ra8_err_null_ptr | st was NULL. |
| k_ra8_err_gpio_conflict | A side-band pin is owned elsewhere. |
Definition at line 269 of file c6_sideband.c.
References c6_probe_put_u32(), c6_probe_puts(), c6_probe_sideband_name(), internal_pull_read(), k_c6_probe_pull_samples, k_c6_sb_count, k_c6_sideband_pin, k_ra8_err_null_ptr, k_ra8_ok, c6_probe_stats_t::pull_low, and c6_probe_stats_t::pull_samples.
Referenced by c6_probe_run().
| void c6_probe_resolve_map | ( | const c6_probe_stats_t * | st, |
| uint8_t * | hs_idx, | ||
| uint8_t * | dr_idx ) |
Resolve the HANDSHAKE and DATA_READY side-band map from the accumulated evidence.
The whole identification policy lives here, in one place, ranked by how hard the evidence is to fake:
Any step that cannot decide yields k_c6_sb_count, and the caller prints unresolved. That is deliberate: the previous policy took the highest vote unconditionally, and a single noise transition on an unconnected pin was enough to publish a wrong pin map that read exactly like a measured one.
| [in] | st | Accumulated evidence. |
| [out] | hs_idx | Resolved HANDSHAKE index, or k_c6_sb_count. |
| [out] | dr_idx | Resolved DATA_READY index, or k_c6_sb_count. |
Definition at line 313 of file c6_sideband.c.
References c6_probe_best(), c6_probe_sunk_pin(), c6_probe_stats_t::dr_vote, c6_probe_stats_t::hs_vote, k_c6_probe_min_votes, and k_c6_sb_count.
Referenced by c6_probe_run().
| void c6_probe_sample_sideband | ( | c6_sideband_sample_t * | out | ) |
Read every Pmod1 side-band pin into one sample.
| [out] | out | Destination sample; ignored when NULL. |
Definition at line 121 of file c6_sideband.c.
References k_c6_sb_count, k_c6_sideband_pin, k_ra8_level_high, k_ra8_level_low, k_ra8_ok, c6_sideband_sample_t::level, and ra8_gpio_read().
Referenced by internal_cs_try(), internal_transfer(), internal_wait_ready(), and main().
|
nodiscard |
Claim the four Pmod1 side-band pins as no-pull digital inputs.
No internal pull is applied for sampling: the C6 drives HANDSHAKE and DATA_READY push-pull, and holding a pull-up during the run would make an unconnected pin indistinguishable from an asserted one – precisely the distinction this app exists to make. c6_probe_pull_contest engages the pull-up briefly and on purpose, then restores the pins to this state.
| k_ra8_ok | All four side-band pins are inputs. |
| k_ra8_err_gpio_conflict | A pin is already owned elsewhere. |
| k_ra8_err_gpio_invalid_port | Board pin table disagrees with the HAL. |
Definition at line 110 of file c6_sideband.c.
References k_c6_sb_count, k_c6_sideband_pin, k_ra8_ok, k_ra8_pull_none, and ra8_gpio_input_init().
Referenced by c6_probe_setup_or_halt().
| const char * c6_probe_sideband_name | ( | uint8_t | idx | ) |
Name a side-band pin for the console.
| [in] | idx | Side-band index, or k_c6_sb_count for "unresolved". |
| unresolved | idx was out of range. |
Definition at line 135 of file c6_sideband.c.
References k_c6_sb_count, and k_c6_sideband_label.
Referenced by c6_probe_print_map(), c6_probe_print_sideband(), and c6_probe_pull_contest().
| uint8_t c6_probe_sunk_pin | ( | const c6_probe_stats_t * | st, |
| uint8_t | ignore ) |
Name the one pin that lost every read of the pull-up contest.
Reads the verdict out of the evidence c6_probe_pull_contest gathered: a pin qualifies only when pull_low equals pull_samples, i.e. it read low on every single sample taken against the pull-up.
Two conditions are deliberately reported as "no answer" rather than as a winner. Unanimity is required because a pin that reads low only sometimes is being driven by something that is not an idle DATA_READY – a coupled edge, a shared ground bounce – and naming it would be a guess. Uniqueness is required because two sunk pins mean the caller's exclusion (typically the resolved HANDSHAKE) has not narrowed the field to one, and picking either by table order is the exact failure this whole mechanism exists to prevent.
| [in] | st | Statistics block filled by c6_probe_pull_contest. |
| [in] | ignore | Index to skip, or k_c6_sb_count to skip nothing. |
| k_c6_sb_count | No pin was sunk, more than one was, the contest was never run, or st was NULL. |
Definition at line 294 of file c6_sideband.c.
References k_c6_sb_count, c6_probe_stats_t::pull_low, and c6_probe_stats_t::pull_samples.
Referenced by c6_probe_resolve_map().
| void c6_probe_vote | ( | const c6_sideband_sample_t * | pre, |
| const c6_sideband_sample_t * | mid, | ||
| const c6_sideband_sample_t * | post, | ||
| c6_probe_stats_t * | st ) |
Fold one transaction's three samples into the classification votes.
HANDSHAKE is the pin that is high before the transfer and low while the chip-select is asserted, because the C6 is built with CONFIG_ESP_SPI_DEASSERT_HS_ON_CS=y and clears it from its chip-select edge interrupt (gpio_disable_hs_isr_handler in the C6's peripheral-side SPI driver). That is a genuine identification: the pin moves, twice per transaction, in step with a line the probe itself drives.
The DATA_READY vote is far weaker and must not be read as its equal. It counts a pin that was high before the transfer and still low well after it, which is what the C6 does when it drains a queued frame (get_next_tx_buffer). That is a once-per-boot event: the C6 raises DATA_READY for its queued INIT event and lowers it when the first transaction takes it, after which the pin stays low and every later pre sample is already low, so the vote cannot fire again. Worse, that single transition usually lands between transactions – during the chip-select hunt, say – where nothing is sampling, so in practice the counter often stays at zero for the correctly-wired pin. The vote proves DATA_READY when it fires and says nothing at all when it does not, which is why c6_probe_resolve_map prefers the pull-up contest and keeps this counter only as a fallback.
| [in] | pre | Sample taken with the chip-select released. |
| [in] | mid | Sample taken with the chip-select asserted. |
| [in] | post | Sample taken after the chip-select was released again. |
| [in,out] | st | Statistics block to accumulate into. |
Definition at line 156 of file c6_sideband.c.
References c6_probe_stats_t::dr_vote, c6_probe_stats_t::ever_high, c6_probe_stats_t::ever_low, c6_probe_stats_t::hs_vote, k_c6_sb_count, and c6_sideband_sample_t::level.
Referenced by internal_one_xfer().
| c6_wire_kind_t c6_probe_wire_kind | ( | uint8_t | after_high, |
| uint8_t | after_low ) |
Classify one Pmod1 net from its two drive-and-release samples.
| [in] | after_high | Level read after driving the net high and releasing. |
| [in] | after_low | Level read after driving the net low and releasing. |
| k_c6_wire_floating | Held both driven levels: nothing attached. |
| k_c6_wire_low_side | Snapped low both times: pull-down or driver. |
| k_c6_wire_high_side | Snapped high both times: pull-up or driver. |
| k_c6_wire_odd | Inverted pair; not physically expected. |
Definition at line 384 of file c6_sideband.c.
References k_c6_wire_floating, k_c6_wire_high_side, k_c6_wire_low_side, and k_c6_wire_odd.
Referenced by c6_probe_wire_test().
| void c6_probe_wire_test | ( | void | ) |
Run the drive-and-release test over every Pmod1 muxed net.
Prints one line per candidate so the log states, without inference, what terminates each MCU pin that the board's Pmod1 mux might connect to J26.
Definition at line 398 of file c6_sideband.c.
References c6_probe_put_u32(), c6_probe_puts(), c6_probe_wire_kind(), internal_kick_net(), k_c6_wire_count, k_c6_wire_label, k_c6_wire_pin, k_ra8_level_high, k_ra8_level_low, and k_ra8_ok.
Referenced by main().
|
static |
Assert one candidate chip-select and report any side-band response.
Drives the candidate high, samples, drives it low for a settle period, samples again, restores it high and releases it. A live C6 on the other end answers the falling edge by dropping HANDSHAKE, so a pin that went from high to low between the two samples both proves the candidate is the chip-select and names HANDSHAKE.
| [in] | idx | One-based index into k_c6_wire_pin. |
| [in,out] | st | Statistics block; handshake votes accumulate here. |
| true | The C6 answered this candidate's chip-select edge. |
| false | Nothing on the far end reacted, or the drive failed. |
Definition at line 453 of file c6_sideband.c.
References c6_probe_print_sideband(), c6_probe_puts(), c6_probe_sample_sideband(), c6_probe_stats_t::hs_vote, k_c6_probe_cs_hold_ms, k_c6_probe_settle_ms, k_c6_sb_count, k_c6_wire_label, k_c6_wire_pin, k_ra8_level_high, k_ra8_level_low, k_ra8_ok, c6_sideband_sample_t::level, pin, ra8_delay_ms(), ra8_gpio_output_init(), ra8_gpio_release(), and ra8_gpio_write().
Referenced by c6_probe_cs_hunt().
|
static |
Drive one net to a level, release it, and sample what it settles to.
Claims the pin as a push-pull output at level, holds it long enough for the net to charge, then releases the claim and re-claims it as a no-pull input before sampling. A net with no termination keeps the driven level on its own capacitance for far longer than the settle delay; a terminated net snaps back within microseconds.
| [in] | pin | Board pin to exercise. |
| [in] | level | Level to drive before releasing. |
| [out] | out_level | Level read back after release; ignored when NULL. |
| k_ra8_ok | The net was driven, released and sampled. |
| k_ra8_err_null_ptr | out_level was NULL. |
| k_ra8_err_gpio_conflict | The pin is owned by another driver. |
Definition at line 355 of file c6_sideband.c.
References k_c6_probe_cs_hold_ms, k_ra8_err_null_ptr, k_ra8_level_high, k_ra8_level_low, k_ra8_ok, k_ra8_pull_none, pin, ra8_delay_ms(), ra8_gpio_input_init(), ra8_gpio_output_init(), ra8_gpio_read(), and ra8_gpio_release().
Referenced by c6_probe_wire_test().
|
static |
Hold one pin against the internal pull-up and count the low reads.
Releases the probe's no-pull claim, re-claims the pin as an input with the pull-up engaged, samples it, and restores the no-pull claim on every exit path so a failure part-way through cannot leave the run sampling through a pull-up.
| [in] | pin | Side-band pin to test. |
| [out] | out_low | Number of reads that came back low. |
| k_ra8_ok | Every sample was taken and the pin restored to no-pull. |
| k_ra8_err_null_ptr | out_low was NULL. |
| k_ra8_err_gpio_conflict | The pin is owned by another driver. |
Definition at line 231 of file c6_sideband.c.
References k_c6_probe_pull_samples, k_c6_probe_pull_settle_ms, k_ra8_err_null_ptr, k_ra8_level_high, k_ra8_level_low, k_ra8_ok, k_ra8_pull_none, k_ra8_pull_up, pin, ra8_delay_ms(), ra8_gpio_input_init(), ra8_gpio_read(), and ra8_gpio_release().
Referenced by c6_probe_pull_contest().
|
static |
Console labels for k_c6_sideband_pin, same order.
A fifth entry backs the "no pin resolved" case so callers never index past the table.
Definition at line 67 of file c6_sideband.c.
Referenced by c6_probe_sideband_name().
|
static |
The four Pmod1 side-band pins, in c6_sideband_idx_t order.
Sourced from the board layer so no EK-RA8D2 pin fact is re-encoded here.
Definition at line 51 of file c6_sideband.c.
Referenced by c6_probe_pull_contest(), c6_probe_sample_sideband(), and c6_probe_sideband_init().
|
static |
Console labels for k_c6_wire_pin, same order.
A sixth entry backs the "no candidate reached the C6" case.
Definition at line 101 of file c6_sideband.c.
Referenced by c6_probe_cs_hunt(), c6_probe_wire_test(), and internal_cs_try().
|
static |
The five Pmod1 muxed-net candidates, in c6_wire_idx_t order.
Board pins only; nothing here re-encodes an EK-RA8D2 pin fact.
Definition at line 84 of file c6_sideband.c.
Referenced by c6_probe_wire_test(), and internal_cs_try().