|
rcbench
Servo and ESC test bench: panel, IOmcu and shared C
|
Receive a D series answer by precharge and sample: the cycle arithmetic, the sampler's PIO program, the decoder and the run. More...
Go to the source code of this file.
Data Structures | |
| struct | hitec_pre_timing_t |
| The cycle counts a system clock gives. More... | |
| struct | hitec_pre_dec_t |
| Decoder state for one receive. More... | |
| struct | hitec_pre_run_t |
| State of one transaction on the sampler. More... | |
Macros | |
| #define | HITEC_PRE_SAMPLES_PER_BIT 8u |
| Samples a bit the period aims at: the period is the system clock cycles nearest to 1/8 of a D series bit. | |
| #define | HITEC_PRE_CHARGE_NS 100u |
| The precharge and the wait from the release to the sample the cycle counts aim at, ns: the middle of the passing window measured on a D485HW, a precharge of 6.7 to 200ns and a sample 40 to 187ns after the release. | |
| #define | HITEC_PRE_SAMPLE_NS 113u |
| #define | HITEC_PRE_CHARGE_MIN_NS 7u |
| The measured passing window, ns. | |
| #define | HITEC_PRE_CHARGE_MAX_NS 200u |
| #define | HITEC_PRE_SAMPLE_MIN_NS 40u |
| #define | HITEC_PRE_SAMPLE_MAX_NS 187u |
| #define | HITEC_PRE_MIN_HZ 48000000u |
| System clocks the arithmetic takes: one instruction's 32 cycles hold the wait, and 1/8 of a bit holds the precharge, the wait and the sample. | |
| #define | HITEC_PRE_MAX_HZ 250000000u |
| #define | HITEC_PRE_WINDOW_MAX_US 30000u |
| Longest window a run takes, us. | |
| #define | HITEC_PRE_WORDS 928u |
| Sample words the sampler's buffer holds: the longest window and HITEC_RX_MAX bytes at every clock the arithmetic takes. | |
| #define | HITEC_PRE_PROGRAM_MAX 12u |
| Instructions of the longest sampler program. | |
| #define | HITEC_PRE_FRAME_BITS 10u |
| Bits of a frame the decoder samples: start, 8 data, stop. | |
Enumerations | |
| enum | hitec_rx_mode_t { HITEC_RX_PULL_UP = 0 , HITEC_RX_PRECHARGE = 1 } |
| How a D series line receives. More... | |
| enum | hitec_pre_dec_phase_t { HITEC_PRE_WAIT_REST = 0 , HITEC_PRE_WAIT_START , HITEC_PRE_IN_BYTE , HITEC_PRE_DEC_DONE } |
| Phase of the decoder. More... | |
| enum | hitec_pre_end_t { HITEC_PRE_END_NONE = 0 , HITEC_PRE_END_FULL , HITEC_PRE_END_WINDOW , HITEC_PRE_END_SHORT } |
| Why the decoder ended. More... | |
| enum | hitec_pre_plan_t { HITEC_PRE_PLAN_LINE = 0 , HITEC_PRE_PLAN_SEND , HITEC_PRE_PLAN_LISTEN , HITEC_PRE_PLAN_REFUSE } |
| What a transaction asks of the sampler, hitec_pre_begin(). More... | |
| enum | hitec_pre_phase_t { HITEC_PRE_IDLE = 0 , HITEC_PRE_TX , HITEC_PRE_SAMPLE , HITEC_PRE_DONE } |
| Phase of a run. More... | |
Functions | |
| bool | hitec_pre_timing (uint32_t sys_hz, hitec_pre_timing_t *out) |
The counts for a system clock of sys_hz. | |
| uint32_t | hitec_pre_cycles_ns (const hitec_pre_timing_t *t, uint64_t cycles) |
cycles system clock cycles of t in ns, rounded to nearest. | |
| unsigned | hitec_pre_program (const hitec_pre_timing_t *t, uint16_t *words, unsigned max) |
| The sampler's program: precharge, release, wait, sample, then the rest of the period, as PIO instruction words: set pindirs, 1 [charge -
1], set pindirs, 0 [wait - 1], in pins, 1, and nop with delays up to the period. | |
| uint32_t | hitec_pre_window_samples (const hitec_pre_timing_t *t, uint32_t window_us) |
Samples a window of window_us waits, rounded to nearest. | |
| uint32_t | hitec_pre_words (const hitec_pre_timing_t *t, uint32_t window_us, uint8_t max_rx) |
Sample words a run with a window of window_us and max_rx bytes takes: the window, every byte from its start to its stop bit's middle, and one word. | |
| static unsigned | hitec_pre_sample (const uint32_t *words, uint32_t k) |
The level of sample k of words: 1 high. | |
| void | hitec_pre_dec_init (hitec_pre_dec_t *d, const hitec_pre_timing_t *t, uint32_t window_us, uint8_t max_rx) |
Prepare d for a window of window_us and up to max_rx bytes (1 to HITEC_RX_MAX). | |
| bool | hitec_pre_dec_feed (hitec_pre_dec_t *d, const hitec_pre_timing_t *t, const uint32_t *words, uint32_t n_words) |
Decode the samples of the first n_words words of words that it has not seen. | |
| void | hitec_pre_dec_close (hitec_pre_dec_t *d) |
| No more samples come: a decoder that has not ended ends with HITEC_PRE_END_SHORT, dropping a byte whose samples are not all in. | |
| hitec_pre_plan_t | hitec_pre_begin (hitec_pre_run_t *r, const hitec_pre_timing_t *t, const hitec_xfer_t *x) |
Plan x on a PRECHARGE line. | |
| void | hitec_pre_tx_xfer (const hitec_xfer_t *x, hitec_xfer_t *out) |
The transaction the line sends for a HITEC_PRE_PLAN_SEND: x with no window and no byte to receive. | |
| void | hitec_pre_tx_done (hitec_pre_run_t *r) |
| The request has ended: HITEC_PRE_TX to HITEC_PRE_SAMPLE. | |
| bool | hitec_pre_step (hitec_pre_run_t *r, const hitec_pre_timing_t *t, const uint32_t *words, uint32_t n_words, bool all_in) |
Feed the first n_words sample words. | |
| void | hitec_pre_abort (hitec_pre_run_t *r, const hitec_pre_timing_t *t, const uint32_t *words, uint32_t n_words) |
Cut the run in any phase but idle: what n_words words hold is decoded, a byte not whole is dropped, and the run is done, aborted. | |
| void | hitec_pre_lost (hitec_pre_run_t *r) |
| Samples went missing (the sampler stalled) or the sampler ran past its time: the capture is marked overflowed. | |
| void | hitec_pre_capture (const hitec_pre_run_t *r, const hitec_pre_timing_t *t, int32_t offset_ns, hitec_capture_t *out) |
| The capture of a done run. | |
Receive a D series answer by precharge and sample: the cycle arithmetic, the sampler's PIO program, the decoder and the run.
Implements the signal-wire programming protocols of Hitec servos. Hitec is a name or trademark of its owner; it is used here only to say which servos this module works with (README.md, "Legal notice and disclaimer").
The D series answer needs a high level on the wire that the servo does not make. With a pull-up on the board (receive mode PULL-UP) the receiver of hitec_pio.h reads the answer as it comes. Without one (receive mode PRECHARGE) the master makes the high level itself, a sample period at a time: a second state machine drives the pad high for a short precharge, releases it, waits, and samples the pad. A servo that pulls the line low pulls it down inside the wait; one that leaves it released leaves it high. The samples go to memory, a 32-bit word every 32 samples, and this module decodes them as inverted 8N1 into the hitec_capture_t the PULL-UP receiver gives.
Measured on one D485HW at a 150MHz system clock, 5 reads per setting: every read passes with the sample 40 to 187ns after the release and a precharge of 6.7 to 200ns; at 213ns a precharge of 1 cycle fails; from 267ns no read passes; with no precharge every sample is low. This module takes the middle: a precharge of HITEC_PRE_CHARGE_NS and the sample HITEC_PRE_SAMPLE_NS after the release, rounded to system clock cycles.
Sample words. Sample k of a run is bit 31 - (k mod 32) of word k / 32: the state machine shifts left and pushes every 32 samples. A sample is 1 for a high pad. Sample k is taken k * period + charge + wait system clock cycles after the state machine starts, through the input synchroniser's HITEC_PIO_SYNC_SYS_CYCLES.
The decoder. Inverted 8N1 at 115 200bit/s: the line rests low, a start bit is high, a data bit low is a 1, the stop bit is low. As the PULL-UP receiver does, it first waits for the rest level, then for a start bit; a start bit is the first high sample after a low one, and a stop bit read low counts as that low sample. The middle of bit j lies floor((j + 1/2) samples-per-bit) samples after that sample; a start bit whose middle reads low is a glitch, and the wait goes on. Every sample spent waiting counts against the window; the samples inside a byte do not. The decoder ends at max_rx bytes, at the end of the window, or at the end of the samples. Integer arithmetic only; a sample word that holds only the level waited for is passed in one step.
The run. A SEND goes out on the line's own state machine with no receiver (hitec_pre_tx_xfer()); the sampler takes the pad when the request has ended (hitec_pre_tx_done()). A LISTEN samples from its start. A transaction with no receive window, or a LEVEL, runs as in PULL-UP. hitec_pre_step() feeds the words the sampler has written, however many there are, so a caller steps it once per pass; an abort keeps the bytes decoded so far.
The module includes nothing outside the C standard headers, this folder's headers and holds no global state.
SPDX-License-Identifier: MIT
| #define HITEC_PRE_CHARGE_MIN_NS 7u |
The measured passing window, ns.
A clock whose rounded cycles fall outside it is refused.
| #define HITEC_PRE_MIN_HZ 48000000u |
System clocks the arithmetic takes: one instruction's 32 cycles hold the wait, and 1/8 of a bit holds the precharge, the wait and the sample.
The bench ran at 150MHz.
| enum hitec_pre_end_t |
| enum hitec_pre_phase_t |
| enum hitec_pre_plan_t |
What a transaction asks of the sampler, hitec_pre_begin().
| enum hitec_rx_mode_t |
| void hitec_pre_abort | ( | hitec_pre_run_t * | r, |
| const hitec_pre_timing_t * | t, | ||
| const uint32_t * | words, | ||
| uint32_t | n_words ) |
Cut the run in any phase but idle: what n_words words hold is decoded, a byte not whole is dropped, and the run is done, aborted.
Nothing on an idle or a done run.
| r | Run state. |
| t | Counts of the clock. |
| words | Sample words, from sample 0. |
| n_words | Words of the buffer that are written. |
| hitec_pre_plan_t hitec_pre_begin | ( | hitec_pre_run_t * | r, |
| const hitec_pre_timing_t * | t, | ||
| const hitec_xfer_t * | x ) |
Plan x on a PRECHARGE line.
For HITEC_PRE_PLAN_SEND the run is in HITEC_PRE_TX, for HITEC_PRE_PLAN_LISTEN in HITEC_PRE_SAMPLE; otherwise it is idle.
| r | Run state to set up. |
| t | Counts of the clock. |
| x | Transaction to plan. |
| void hitec_pre_capture | ( | const hitec_pre_run_t * | r, |
| const hitec_pre_timing_t * | t, | ||
| int32_t | offset_ns, | ||
| hitec_capture_t * | out ) |
The capture of a done run.
offset_ns: the sampler's start from the receiver's time 0 (the release and one bit time after a SEND, the start of a LISTEN), negative when it started before. A start bit's time is the middle between its first high sample and the sample before it.
| r | Done run state. |
| t | Counts of the clock. |
| offset_ns | Offset of the sampler start from the receiver time 0, in ns. |
| out | Receives the capture. |
| uint32_t hitec_pre_cycles_ns | ( | const hitec_pre_timing_t * | t, |
| uint64_t | cycles ) |
cycles system clock cycles of t in ns, rounded to nearest.
| t | Counts of the clock. |
| cycles | Cycle count. |
| void hitec_pre_dec_close | ( | hitec_pre_dec_t * | d | ) |
No more samples come: a decoder that has not ended ends with HITEC_PRE_END_SHORT, dropping a byte whose samples are not all in.
| d | Decoder state. |
| bool hitec_pre_dec_feed | ( | hitec_pre_dec_t * | d, |
| const hitec_pre_timing_t * | t, | ||
| const uint32_t * | words, | ||
| uint32_t | n_words ) |
Decode the samples of the first n_words words of words that it has not seen.
words is the whole buffer from sample 0; a call may pass the same words again with more after them. Returns true once the decoder has ended (max_rx bytes or the window). A start bit whose samples are not all in waits for the next call.
| d | Decoder state. |
| t | Counts of the clock. |
| words | Sample words, from sample 0. |
| n_words | Words of the buffer that are written. |
| void hitec_pre_dec_init | ( | hitec_pre_dec_t * | d, |
| const hitec_pre_timing_t * | t, | ||
| uint32_t | window_us, | ||
| uint8_t | max_rx ) |
Prepare d for a window of window_us and up to max_rx bytes (1 to HITEC_RX_MAX).
| d | Decoder to prepare. |
| t | Counts of the clock. |
| window_us | Window, in us. |
| max_rx | Bytes to receive, 1 to HITEC_RX_MAX. |
| void hitec_pre_lost | ( | hitec_pre_run_t * | r | ) |
Samples went missing (the sampler stalled) or the sampler ran past its time: the capture is marked overflowed.
The run is done. After hitec_pre_abort() it marks the aborted capture overflowed as well.
| r | Run state. |
| unsigned hitec_pre_program | ( | const hitec_pre_timing_t * | t, |
| uint16_t * | words, | ||
| unsigned | max ) |
The sampler's program: precharge, release, wait, sample, then the rest of the period, as PIO instruction words: set pindirs, 1 [charge - 1], set pindirs, 0 [wait - 1], in pins, 1, and nop with delays up to the period.
The pad's SET and IN pin is the line; the output latch is high; autopush at 32 bits, shifting left; no side-set. The program wraps from its last word to its first. Returns the words written, 0 when max is too small.
| t | Counts of the clock. |
| words | Receives the instruction words. |
| max | Capacity of words, in words. |
|
inlinestatic |
The level of sample k of words: 1 high.
Samples are packed 32 to a word, the first sample in the most significant bit.
| words | Sample words, from sample 0. |
| k | Sample index. |
k is high, 0 when it is low. | bool hitec_pre_step | ( | hitec_pre_run_t * | r, |
| const hitec_pre_timing_t * | t, | ||
| const uint32_t * | words, | ||
| uint32_t | n_words, | ||
| bool | all_in ) |
Feed the first n_words sample words.
all_in: the sampler has written every word it takes (r->words) or stopped. Returns true when the run is in HITEC_PRE_DONE: the decoder ended, or every word is in. Nothing outside HITEC_PRE_SAMPLE.
| r | Run state. |
| t | Counts of the clock. |
| words | Sample words, from sample 0. |
| n_words | Words of the buffer that are written. |
| all_in | true when every word the run takes is written. |
| bool hitec_pre_timing | ( | uint32_t | sys_hz, |
| hitec_pre_timing_t * | out ) |
The counts for a system clock of sys_hz.
False, and out left as it was, for a clock outside HITEC_PRE_MIN_HZ to HITEC_PRE_MAX_HZ or one whose rounded precharge or wait falls outside the measured window. At 150MHz: a period of 163 cycles (1086.7ns, 7.99 samples a bit), a precharge of 15 cycles (100.0ns) and the sample 17 cycles (113.3 ns) after the release.
| sys_hz | System clock, in Hz. |
| out | Receives the cycle counts; left unchanged when false is returned. |
| void hitec_pre_tx_done | ( | hitec_pre_run_t * | r | ) |
The request has ended: HITEC_PRE_TX to HITEC_PRE_SAMPLE.
Nothing in another phase.
| r | Run state. |
| void hitec_pre_tx_xfer | ( | const hitec_xfer_t * | x, |
| hitec_xfer_t * | out ) |
The transaction the line sends for a HITEC_PRE_PLAN_SEND: x with no window and no byte to receive.
| x | Transaction the plan was made for. |
| out | Receives x with no window and no byte to receive. |
| uint32_t hitec_pre_window_samples | ( | const hitec_pre_timing_t * | t, |
| uint32_t | window_us ) |
Samples a window of window_us waits, rounded to nearest.
| t | Counts of the clock. |
| window_us | Window, in us. |
| uint32_t hitec_pre_words | ( | const hitec_pre_timing_t * | t, |
| uint32_t | window_us, | ||
| uint8_t | max_rx ) |
Sample words a run with a window of window_us and max_rx bytes takes: the window, every byte from its start to its stop bit's middle, and one word.
0 when the window is above HITEC_PRE_WINDOW_MAX_US or the words would not fit HITEC_PRE_WORDS.
| t | Counts of the clock. |
| window_us | Window, in us. |
| max_rx | Bytes to receive. |