|
rcbench
Servo and ESC test bench: panel, IOmcu and shared C
|
The Hitec wire on one RP2350 pin: a hitec_driver_t made of one PIO (programmable input/output) state machine (hitec_line.pio) and two DMA (direct memory access) channels, one for the words of a transaction and one for the received bytes. More...
#include <stdbool.h>#include <stdint.h>#include "hitec_pio.h"#include "hitec_pre.h"#include "hitec_wire.h"Go to the source code of this file.
Data Structures | |
| struct | hitec_line_t |
| One line. More... | |
Macros | |
| #define | HITEC_LINE_GRACE_US 1000u |
| The driver ends a transaction whose state machine still runs this long after the time the transaction can take. | |
Enumerations | |
| enum | hitec_line_err_t { HITEC_LINE_OK = 0 , HITEC_LINE_ERR_ARG , HITEC_LINE_ERR_CLOCK , HITEC_LINE_ERR_PIO , HITEC_LINE_ERR_DMA } |
Functions | |
| void | hitec_line_init (hitec_line_t *line) |
Mark line closed. | |
| hitec_line_err_t | hitec_line_open (hitec_line_t *line, unsigned pin, uint8_t family, uint8_t drive) |
Claim the resources and take pin for family (hitec_family_t) with drive (hitec_drive_t): from the return on the pad is a released input with the family's pull. | |
| hitec_line_err_t | hitec_line_open_rx (hitec_line_t *line, unsigned pin, uint8_t family, uint8_t drive, uint8_t rx) |
hitec_line_open() with the receive mode rx (hitec_rx_mode_t). | |
| uint8_t | hitec_line_rx_mode (const hitec_line_t *line) |
| The receive mode of the open line; HITEC_RX_PULL_UP while closed. | |
| void | hitec_line_close (hitec_line_t *line) |
| Stop the state machine, give back what the open claimed and leave the pad an input with the family's pull and no input override. | |
| bool | hitec_line_is_open (const hitec_line_t *line) |
| Check whether a line is open. | |
| bool | hitec_line_busy (const hitec_line_t *line) |
| A transaction runs: between a start() that returned true and the poll() that returns true. | |
| uint32_t | hitec_line_bit_ns (const hitec_line_t *line) |
| The bit time the system clock gives, in ns; 0 on a closed line. | |
| void | hitec_line_abort (hitec_line_t *line) |
| Cut the running transaction: the pad is released at once, and the next poll() returns the bytes so far with the capture marked aborted. | |
| bool | hitec_line_start (void *ctx, const hitec_xfer_t *xfer) |
The three functions of hitec_driver_t; ctx is the hitec_line_t. | |
| bool | hitec_line_poll (void *ctx, hitec_capture_t *out) |
| Poll a transaction; the second of the three driver functions. | |
| uint32_t | hitec_line_now_us (void *ctx) |
| Read the microsecond clock; the third of the three driver functions. | |
| hitec_driver_t | hitec_line_driver (hitec_line_t *line) |
The driver for line. | |
The Hitec wire on one RP2350 pin: a hitec_driver_t made of one PIO (programmable input/output) state machine (hitec_line.pio) and two DMA (direct memory access) channels, one for the words of a transaction and one for the received bytes.
A D series line opened to receive by PRECHARGE (hitec_pre.h) adds a second state machine, the sampler, and a third DMA channel for its samples.
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").
Resources. hitec_line_open() claims 1 state machine, 30 words of program space in a PIO block that reaches the pin, and 2 DMA channels; hitec_line_close() gives all of them back. Every open line loads its own copy of the program, so a block of 32 words holds 1 line and the RP2350's 3 blocks hold up to 3. No interrupt and no PIO interrupt flag is used. PRECHARGE claims 1 more state machine with the sampler's program, 7 words at 150MHz (hitec_pre_program()), in a block with room for it, and 1 more DMA channel, at the open; the close gives them back.
Clock. The divider is computed from clock_get_hz(clk_sys) at the open, 16 state machine cycles a bit. The open is refused when the divider would be below 4 or the bit time more than 0.05% off. The system clock must not change while the line is open.
Pad. Open and outside a transaction the pad is an input: classic with its pull-down on, the D series with its pull-up on and the input inverted. The internal pulls are 50 to 80kOhm; the D series needs a pull-up on the board. In a transaction the pad drives as the stream says and is released at the end of the transmit, at the end of the answer, at the end of the window, at an abort and at a restart. The close leaves the pad an input with the family's pull and the input override off.
PRECHARGE. A SEND with a receive window goes out with no receiver (hitec_pre_tx_xfer()). The first poll() that finds the request ended hands the pad to the sampler: the pin's control and pad registers are kept, the pin goes to the sampler's PIO block with no input override, 2mA drive and slow slew, and a DMA channel writes the samples to the line object. Each poll() decodes the words written since the last one (hitec_pre_step()). At the decoder's end, at the last word, at an abort and at the close the sampler stops with the pad released, and the pin's two registers are written back as they were. A LISTEN samples from its start; one that answers is refused, and so is a window above HITEC_PRE_WINDOW_MAX_US. A transaction with no window and a LEVEL run as in PULL-UP. The bytes' times carry the sampler's start, read off the microsecond timer: within 1us.
Every function is called from one context. hitec_line_poll() ends a transaction whose state machine still runs HITEC_LINE_GRACE_US after the time the transaction can take: the state machine is stopped, the receive channel takes the words still in the FIFO, the bytes are counted, and then the machine is restarted with the pad released. The capture holds every byte pushed before the stop and is marked as overflowed.
Not measured: no byte of this driver has been on a pin.
SPDX-License-Identifier: MIT
| enum hitec_line_err_t |
| Enumerator | |
|---|---|
| HITEC_LINE_ERR_ARG | No line object, a pin the chip does not have, an unknown family or drive, or push-pull for classic. |
| HITEC_LINE_ERR_CLOCK | The system clock gives no divider (hitec_pio.h), or PRECHARGE no cycle counts (hitec_pre_timing()). |
| HITEC_LINE_ERR_PIO | No state machine or no program space; for PRECHARGE, none for the sampler. |
| HITEC_LINE_ERR_DMA | Fewer than 2 free DMA channels, 3 for PRECHARGE. |
| void hitec_line_abort | ( | hitec_line_t * | line | ) |
Cut the running transaction: the pad is released at once, and the next poll() returns the bytes so far with the capture marked aborted.
Does nothing when no transaction runs.
| line | Line object. |
| uint32_t hitec_line_bit_ns | ( | const hitec_line_t * | line | ) |
The bit time the system clock gives, in ns; 0 on a closed line.
| line | Line object. |
| bool hitec_line_busy | ( | const hitec_line_t * | line | ) |
A transaction runs: between a start() that returned true and the poll() that returns true.
| line | Line object. |
| void hitec_line_close | ( | hitec_line_t * | line | ) |
Stop the state machine, give back what the open claimed and leave the pad an input with the family's pull and no input override.
A transaction on the wire is cut. Safe on a closed line.
| line | Line object. |
| hitec_driver_t hitec_line_driver | ( | hitec_line_t * | line | ) |
| void hitec_line_init | ( | hitec_line_t * | line | ) |
Mark line closed.
Call once, before the first open.
| line | Line object to mark closed. |
| bool hitec_line_is_open | ( | const hitec_line_t * | line | ) |
Check whether a line is open.
| line | Line object. |
| uint32_t hitec_line_now_us | ( | void * | ctx | ) |
Read the microsecond clock; the third of the three driver functions.
| ctx | The hitec_line_t. |
| hitec_line_err_t hitec_line_open | ( | hitec_line_t * | line, |
| unsigned | pin, | ||
| uint8_t | family, | ||
| uint8_t | drive ) |
Claim the resources and take pin for family (hitec_family_t) with drive (hitec_drive_t): from the return on the pad is a released input with the family's pull.
The caller has stopped every other use of the pin. On an error nothing stays claimed and the pin is not touched. An open line is closed first.
| line | Line object. |
| pin | GPIO number. |
| family | hitec_family_t value. |
| drive | hitec_drive_t value. |
| hitec_line_err_t hitec_line_open_rx | ( | hitec_line_t * | line, |
| unsigned | pin, | ||
| uint8_t | family, | ||
| uint8_t | drive, | ||
| uint8_t | rx ) |
hitec_line_open() with the receive mode rx (hitec_rx_mode_t).
HITEC_RX_PULL_UP is hitec_line_open(). HITEC_RX_PRECHARGE takes the D series only (HITEC_LINE_ERR_ARG for classic) and claims the sampler as well; on an error nothing stays claimed and the pin is not touched.
| line | Line object. |
| pin | GPIO number. |
| family | hitec_family_t value. |
| drive | hitec_drive_t value. |
| rx | hitec_rx_mode_t value. |
| bool hitec_line_poll | ( | void * | ctx, |
| hitec_capture_t * | out ) |
Poll a transaction; the second of the three driver functions.
| ctx | The hitec_line_t. |
| out | Receives the capture when the transaction has ended. |
| uint8_t hitec_line_rx_mode | ( | const hitec_line_t * | line | ) |
The receive mode of the open line; HITEC_RX_PULL_UP while closed.
| line | Line object. |
| bool hitec_line_start | ( | void * | ctx, |
| const hitec_xfer_t * | xfer ) |
The three functions of hitec_driver_t; ctx is the hitec_line_t.
| ctx | The hitec_line_t. |
| xfer | Transaction to run. |