esp-sdr-zephyr
Raw I/Q receive and transmit on the ESP32-S3/C6 Wi-Fi radio, for Zephyr
Loading...
Searching...
No Matches
Continuous receive

The gapless ring through three dump banks, ESP32-S3 (esp_sdr_ring.h). More...

Topics

 Bursts inside a run

Data Structures

struct  esp_sdr_ring_cfg
struct  esp_sdr_ring_stats
struct  esp_sdr_ring_bench_result

Macros

#define ESP_SDR_RING_RATE_HZ   16000000U
#define ESP_SDR_RING_DECIM_MIN   64U
#define ESP_SDR_RING_FULL_SCALE   16384
#define ESP_SDR_RING_DECIM_BOX4   4U
#define ESP_SDR_RING_DECIM_RAW   1U
#define ESP_SDR_RING_UNIT_DEFAULT   12288U
#define ESP_SDR_RING_UNIT_MIN   1024U

Typedefs

typedef void(* esp_sdr_ring_sink_t) (void *user, const int16_t *i, const int16_t *q, size_t n, uint64_t index)

Enumerations

enum  esp_sdr_ring_status {
}

Functions

int esp_sdr_ring_run (const struct esp_sdr_ring_cfg *cfg, struct esp_sdr_ring_stats *stats)
 Stream until esp_sdr_ring_stop() or a ring failure.
bool esp_sdr_ring_wmac_hold (void)
 Hold off the Wi-Fi MAC interrupt on the calling CPU.
void esp_sdr_ring_wmac_release (bool was_enabled)
 Undo esp_sdr_ring_wmac_hold() on the same CPU.
int esp_sdr_ring_bench (const struct esp_sdr_ring_cfg *cfg, unsigned int units, struct esp_sdr_ring_bench_result *res)
 Time the filter on synthetic data in bank 0, the engine idle.
void esp_sdr_ring_stop (void)
 Ask a running esp_sdr_ring_run() to return; safe from any thread or ISR.
bool esp_sdr_ring_active (void)
bool esp_sdr_ring_now (uint64_t *pair)
 The running ring's position, from any CPU.

Detailed Description

The gapless ring through three dump banks, ESP32-S3 (esp_sdr_ring.h).

Macro Definition Documentation

◆ ESP_SDR_RING_DECIM_BOX4

#define ESP_SDR_RING_DECIM_BOX4   4U

Decimation by 4 (4 MS/s) for signals about 2 MHz wide, such as IEEE 802.15.4: the optional -fs/4 mix and a boxcar of 4 instead of the FIR chain, which cannot keep up at this rate. Aliasing is only suppressed by the boxcar's nulls (about 13 dB at +-1 MHz from them); full scale ESP_SDR_RING_BOX4_FULL_SCALE. Needs CONFIG_ESP_SDR_RING_BOX4 (else esp_sdr_ring_run() returns -EINVAL for it).

◆ ESP_SDR_RING_DECIM_MIN

#define ESP_SDR_RING_DECIM_MIN   64U

Decimation limits (powers of two).

◆ ESP_SDR_RING_DECIM_RAW

#define ESP_SDR_RING_DECIM_RAW   1U

No decimation: the sink gets the whole 16 MS/s stream, unpacked to int16 (the raw 10-bit words times 64, full scale ESP_SDR_RING_RAW_FULL_SCALE) in chunks of up to 512 pairs, the optional -fs/4 mix applied; the index is the pair index. The unpack costs about 3 of the 15 cycles per pair (4.6 with the mix): the sink has the rest, so it copies and counts, and leaves the processing to the other CPU. Needs CONFIG_ESP_SDR_RING_RAW.

The ESP_SDR_RING_RAW_HISTORY pairs before i[0] and q[0] are readable too: the stream's previous pairs (stale after a gap or at the start of a run), for a sink that filters in place. i and q are 16-byte aligned, and n and the index are multiples of 8.

◆ ESP_SDR_RING_FULL_SCALE

#define ESP_SDR_RING_FULL_SCALE   16384

Output full scale: the raw 10-bit full scale times 32.

◆ ESP_SDR_RING_RATE_HZ

#define ESP_SDR_RING_RATE_HZ   16000000U

Ring sample rate; outputs come at this rate divided by the decimation.

◆ ESP_SDR_RING_UNIT_DEFAULT

#define ESP_SDR_RING_UNIT_DEFAULT   12288U

Default unit length: 768 us at 16 MS/s.

◆ ESP_SDR_RING_UNIT_MIN

#define ESP_SDR_RING_UNIT_MIN   1024U

Shortest unit: 64 us.

Typedef Documentation

◆ esp_sdr_ring_sink_t

typedef void(* esp_sdr_ring_sink_t) (void *user, const int16_t *i, const int16_t *q, size_t n, uint64_t index)

Output callback, called from the ring loop with interrupts masked on its CPU: copy the samples and return quickly, never block. index is the output sample index of i[0] and q[0] since esp_sdr_ring_run() started; a jump from the previous call's index + n is a gap (lost input).

Enumeration Type Documentation

◆ esp_sdr_ring_status

Why a run ended early.

Enumerator
ESP_SDR_RING_LATE 

A bank switch came later than the ring allows (detail: pairs written).

ESP_SDR_RING_AGE 

A bank was held longer than the ring allows (detail: cycles).

ESP_SDR_RING_START 

A unit did not start where the previous one ended.

ESP_SDR_RING_END 

A unit's end was not inside its sentinel window.

ESP_SDR_RING_LENGTH 

A unit of implausible length (detail: pairs).

Function Documentation

◆ esp_sdr_ring_active()

bool esp_sdr_ring_active ( void )
Returns
Whether esp_sdr_ring_run() is running.

◆ esp_sdr_ring_bench()

int esp_sdr_ring_bench ( const struct esp_sdr_ring_cfg * cfg,
unsigned int units,
struct esp_sdr_ring_bench_result * res )

Time the filter on synthetic data in bank 0, the engine idle.

Runs units ring units (12288 pairs each) through the filter and cfg's sink with interrupts masked on the calling CPU. Not while a run is active.

◆ esp_sdr_ring_now()

bool esp_sdr_ring_now ( uint64_t * pair)

The running ring's position, from any CPU.

Parameters
pairThe index of the pair the engine writes now, counted from the run's first pair (output sample k of a decimating run is pair k times the decimation).
Returns
false outside a run, before its first unit has been located, or if the position kept changing while read.

◆ esp_sdr_ring_run()

int esp_sdr_ring_run ( const struct esp_sdr_ring_cfg * cfg,
struct esp_sdr_ring_stats * stats )

Stream until esp_sdr_ring_stop() or a ring failure.

Runs on the calling thread with interrupts masked on its CPU, except for short windows between polls in which pending interrupts run (the kernel timer may be armed on this CPU, and IPIs; the Wi-Fi MAC interrupt waits until the run ends), and holds the radio for the whole run: call it from a thread pinned to a CPU that nothing else needs meanwhile (cooperative, or a higher-priority thread made ready by such an interrupt preempts the run, which then ends late), and change frequency or gain between runs. A flash write on the other CPU parks this one (the loop answers the stall request) and usually ends the run with ESP_SDR_RING_LATE.

Return values
0after esp_sdr_ring_stop().
-EINVALfor a bad configuration.
-EAGAINif esp_sdr_init() has not run.
-EIOif the ring failed (stats says why).

◆ esp_sdr_ring_stop()

void esp_sdr_ring_stop ( void )

Ask a running esp_sdr_ring_run() to return; safe from any thread or ISR.

A request made while no run is active is discarded when the next run starts. A caller that must not lose one (a settings change racing the start of a run) repeats it, or calls it again from the sink once it sees the change.

◆ esp_sdr_ring_wmac_hold()

bool esp_sdr_ring_wmac_hold ( void )

Hold off the Wi-Fi MAC interrupt on the calling CPU.

The ring does this on its own CPU for a run. Its handler runs for hundreds of microseconds per packet the receiver decodes, and the HAL allocates it on the CPU that started Wi-Fi: a consumer of the ring's output on that other CPU calls this from a thread pinned there, for as long as the run lasts (the MAC needs no serving while the ring owns the radio).

Returns
Whether the line was enabled, for esp_sdr_ring_wmac_release().