rcbench
Servo and ESC test bench: panel, IOmcu and shared C
Loading...
Searching...
No Matches
edge_ring.h File Reference

The words the tap's PIO (programmable input/output) program pushes, and the ring a DMA (direct memory access) channel collects them in. More...

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "tone.h"

Go to the source code of this file.

Data Structures

struct  edge_ring_t
 Read position of an edge ring. More...

Macros

#define EDGE_COUNT_BITS   31u
 The counter's bits a word carries.
#define EDGE_COUNT_MASK   0x7FFFFFFFu

Functions

uint32_t edge_word (uint32_t count, bool level)
 The word the program pushes for an edge at counter value count.
uint32_t edge_word_count (uint32_t word)
 A word's 31-bit count and level.
bool edge_word_level (uint32_t word)
 The word's level after the edge.
uint64_t edge_tick (uint32_t count, uint64_t est)
 The tick of the counter value count nearest est, with a counter that started at 0 and counts down.
void edge_ring_init (edge_ring_t *r)
 Start reading a ring from slot 0, as after the DMA channel restarts.
size_t edge_ring_take (edge_ring_t *r, const uint32_t *ring, uint32_t size, uint32_t wr, uint64_t est, tone_edge_t *out, size_t max, bool *overrun)
 Take the words in ring ( size words, a power of two) written since the last call, wr being the slot the DMA writes next, as edges stamped against est (the present tick, edge_tick()).

Detailed Description

The words the tap's PIO (programmable input/output) program pushes, and the ring a DMA (direct memory access) channel collects them in.

Word format. Bits 31 to 1 are the low 31 bits of the state machine's down counter X when the edge was seen; bit 0 is the level after the edge, 1 for a rise. X starts at 0 when the capture starts and counts down once per tick (4 system clocks, 26.7ns at 150MHz), so the ticks elapsed since the start are (0 - count) mod 2^31. The counter wraps every 2^31 ticks, 57.3s.

Extension. A word carries 31 bits of a 64-bit tick count. The rest comes from an estimate of the present tick the caller has from another clock: the word's tick is the one congruent to its count modulo 2^31 nearest the estimate. The estimate has to be within 2^30 ticks (28.6s) of the truth; microseconds are what it is held to. Chaining the differences between words instead would lose a multiple of 57.3s across any silence longer than that.

The ring. The DMA channel writes the words into a ring of a power of two in size, endlessly; the caller reads the channel's write position as a word index. The capture clears the ring before it starts. edge_ring_take() takes the words written since the last call. An overrun, the DMA having lapped the reader, shows as the slot of the last word taken holding another word: counts do not repeat within 57.3s, so a lap always shows. Before the first word is taken that slot is the ring's last one and the word expected is 0, the cleared state; a real word of 0, a fall at tick 0, cannot occur. The reader then discards what is in the ring and starts again after the newest word.

Pure C, no SDK (software development kit). Host-tested in test_edge_ring.

SPDX-License-Identifier: MIT

Function Documentation

◆ edge_ring_init()

void edge_ring_init ( edge_ring_t * r)

Start reading a ring from slot 0, as after the DMA channel restarts.

The ring holds only zero words at that moment, so a lap before the first read shows as a word in its last slot.

Parameters
rReader state to initialise.

◆ edge_ring_take()

size_t edge_ring_take ( edge_ring_t * r,
const uint32_t * ring,
uint32_t size,
uint32_t wr,
uint64_t est,
tone_edge_t * out,
size_t max,
bool * overrun )

Take the words in ring ( size words, a power of two) written since the last call, wr being the slot the DMA writes next, as edges stamped against est (the present tick, edge_tick()).

At most max edges go to out; words past that stay in the ring for the next call.

Returns the edges written. *overrun is set when the DMA lapped the reader: nothing is returned, the reader is moved after the newest word, and the caller ends the beep under way (tone_flush()).

Parameters
rReader state.
ringRing of edge words.
sizeRing size in words, a power of two.
wrSlot the DMA writes next.
estEstimate of the present tick.
outReceives the edges.
maxMost edges taken in this call.
overrunSet to true when the DMA lapped the reader; may be NULL.
Returns
Number of edges written to out.

◆ edge_tick()

uint64_t edge_tick ( uint32_t count,
uint64_t est )

The tick of the counter value count nearest est, with a counter that started at 0 and counts down.

Ticks before the start do not exist: the result is at least 0.

Parameters
countCounter value of the edge, 31 bits.
estEstimate of the present tick.
Returns
The 64-bit tick of the edge.

◆ edge_word()

uint32_t edge_word ( uint32_t count,
bool level )

The word the program pushes for an edge at counter value count.

Parameters
countCounter value at the edge; the low 31 bits are used.
levelLevel after the edge: true for a rise.
Returns
The edge word.

◆ edge_word_count()

uint32_t edge_word_count ( uint32_t word)

A word's 31-bit count and level.

Parameters
wordEdge word.
Returns
The count, 0 to 2^31 - 1.

◆ edge_word_level()

bool edge_word_level ( uint32_t word)

The word's level after the edge.

Parameters
wordEdge word.
Returns
true for a rise.