|
rcbench
Servo and ESC test bench: panel, IOmcu and shared C
|
KST servo programming protocol: frames and the reply decoder. More...
#include <stdbool.h>#include <stddef.h>#include <stdint.h>Go to the source code of this file.
Data Structures | |
| struct | kst_frame_t |
| A master frame as line levels, one per half-cell. More... | |
| struct | kst_capture_t |
| The reply window as the driver saw it. More... | |
| struct | kst_reply_t |
| A decoded reply window. More... | |
Macros | |
| #define | KST_REG_COUNT 32u |
| The servo decodes 5 address bits: registers 0x00 to 0x1F. | |
| #define | KST_REG_MAX 0x1Fu |
| #define | KST_HALF_CELL_NS 25400u |
| Transmit half-cell, 25.40us. | |
| #define | KST_HALF_CELL_CYCLES_150MHZ 3810u |
| The same half-cell in cycles of a 150MHz system clock. | |
| #define | KST_SERVO_CELL_NS 51150u |
| The servo's own cell, 51.15us (half-cell 25.575us, 0.7% slower than the master). | |
| #define | KST_SERVO_HALF_CELL_NS 25575u |
| #define | KST_FRAME_BITS 27u |
| #define | KST_REPLY_BITS 11u |
| #define | KST_SYNC_PULSES 64u |
| The sync burst: 64 high pulses of one half-cell, one half-cell apart. | |
| #define | KST_FRAME_MAX_HALF_CELLS 127u |
| Longest level sequence: the sync burst, 64 highs and 63 lows. | |
| #define | KST_FRAME_LEVEL_BYTES 16u |
| #define | KST_RELEASE_NS 50000u |
| After the last half-cell of a frame the driver drives low for 50us, then switches the pad to input. | |
| #define | KST_READ_ACCEPT_MIN_NS 350000u |
| After a read frame and after a sync burst: measured 437 to 439us. | |
| #define | KST_READ_ACCEPT_MAX_NS 600000u |
| #define | KST_READ_WINDOW_NS 1500000u |
| Capture length after a read frame or a sync burst, 1.5ms. | |
| #define | KST_WRITE_ACCEPT_MIN_NS 3300000u |
| After a write frame: measured 3687 to 3714us. | |
| #define | KST_WRITE_ACCEPT_MAX_NS 4200000u |
| #define | KST_WRITE_WINDOW_NS 8000000u |
| Capture length after a write frame, 8ms. | |
| #define | KST_GLITCH_NS 1500u |
| A level that lasts less than 1.5us is not a level change. | |
| #define | KST_RX_SEARCH_NS 8000u |
| A mid-cell edge is searched within 8us of its predicted time. | |
| #define | KST_RX_CONFIRM_NS 12800u |
| The two halves of a cell are compared 12.8us before and after the mid-cell edge. | |
| #define | KST_RX_HALF_CELL_MIN_NS 24300u |
| Mean half-cell of a reply: 25.6us +/- 5%. | |
| #define | KST_RX_HALF_CELL_MAX_NS 26900u |
| #define | KST_RX_FINAL_EDGE_MAX_NS 100000u |
| After a last bit 1 the line is low within 100us of the nominal end. | |
| #define | KST_RX_QUIET_AFTER_NS 200000u |
| The line stays low for 200us after the reply. | |
| #define | KST_CAP_MAX_EDGES 48u |
| Edges a capture holds. | |
Enumerations | |
| enum | kst_frame_kind_t { KST_FRAME_READ = 0 , KST_FRAME_WRITE , KST_FRAME_SYNC } |
| Kind of a master frame. More... | |
| enum | kst_expect_t { KST_EXPECT_READ = 0 , KST_EXPECT_WRITE , KST_EXPECT_SYNC } |
| What the master sent, which decides the accept window and the flags. More... | |
| enum | kst_rx_t { KST_RX_OK = 0 , KST_RX_NO_REPLY , KST_RX_QUIET , KST_RX_START_LEVEL , KST_RX_LATE , KST_RX_CELL , KST_RX_LENGTH , KST_RX_RATE , KST_RX_FLAGS , KST_RX_FINAL_EDGE , KST_RX_WINDOW , KST_RX_OVERFLOW , KST_RX_CAPTURE } |
| Result of decoding one reply window. More... | |
Functions | |
| bool | kst_frame_read (uint8_t reg, kst_frame_t *out) |
Read frame for register reg. | |
| bool | kst_frame_write (uint8_t reg, uint8_t value, kst_frame_t *out) |
| Write frame. | |
| void | kst_frame_sync (kst_frame_t *out) |
| The sync burst that puts a servo into programming mode. | |
| bool | kst_frame_level (const kst_frame_t *frame, unsigned index) |
Level of half-cell index; false past the end. | |
| uint32_t | kst_frame_duration_ns (const kst_frame_t *frame) |
| Time the frame takes on the wire, in ns. | |
| uint32_t | kst_reply_window_ns (kst_expect_t expect) |
Accept window and capture length for expect. | |
| kst_rx_t | kst_reply_decode (const kst_capture_t *cap, kst_expect_t expect, kst_reply_t *out) |
| Decode a reply window. | |
KST servo programming protocol: frames and the reply decoder.
Implements the programming protocol of KST and Chaservo servos. KST and Chaservo are names or trademarks of their respective owners; they are used here only to say which servos this module works with (README.md, "Legal notice and disclaimer").
The protocol runs half duplex on the servo's signal wire. The line idles low. Bits are Manchester coded, most significant bit first: a 1 is a low half-cell followed by a high half-cell, a 0 is high followed by low. Every frame starts with a 1 bit, so its first visible event is a rising edge. The master sends 27 bits, the servo answers with 11. There is no parity, no checksum and no length field; the plausibility checks of the decoder stand in for them.
This file has no hardware access. A frame is handed to a driver as a sequence of half-cell levels to clock out at KST_HALF_CELL_NS each. The driver hands back the reply window as edge timestamps.
Capture representation: edge timestamps, not fixed-rate samples.
Measured on 1 programming card and 1 servo of unidentified model. The accept windows are set around that servo.
The module includes nothing outside the C standard headers and holds no global state.
SPDX-License-Identifier: MIT
| #define KST_CAP_MAX_EDGES 48u |
Edges a capture holds.
A reply has at most 23; the rest is room for glitches, 2 edges each.
| #define KST_FRAME_BITS 27u |
master to servo
| #define KST_HALF_CELL_NS 25400u |
Transmit half-cell, 25.40us.
The only rate the servo is proven to accept. Required accuracy: 50ns, edge jitter below 100ns.
| #define KST_RELEASE_NS 50000u |
After the last half-cell of a frame the driver drives low for 50us, then switches the pad to input.
The earliest reply observed starts 437us after the last edge.
| #define KST_REPLY_BITS 11u |
servo to master
| #define KST_RX_FINAL_EDGE_MAX_NS 100000u |
After a last bit 1 the line is low within 100us of the nominal end.
The servo releases the line there; the last high reads 32us at a 1.4V threshold and 59us at 0.1V.
| #define KST_RX_HALF_CELL_MIN_NS 24300u |
Mean half-cell of a reply: 25.6us +/- 5%.
The servo's clock tolerance over temperature and supply is not measured.
| #define KST_SERVO_CELL_NS 51150u |
The servo's own cell, 51.15us (half-cell 25.575us, 0.7% slower than the master).
The decoder predicts each mid-cell edge with it.
| #define KST_SYNC_PULSES 64u |
The sync burst: 64 high pulses of one half-cell, one half-cell apart.
Other counts are not tested.
| enum kst_expect_t |
| enum kst_frame_kind_t |
| enum kst_rx_t |
Result of decoding one reply window.
One code per failed check.
| uint32_t kst_frame_duration_ns | ( | const kst_frame_t * | frame | ) |
Time the frame takes on the wire, in ns.
| frame | Frame to measure. |
| bool kst_frame_level | ( | const kst_frame_t * | frame, |
| unsigned | index ) |
Level of half-cell index; false past the end.
| frame | Frame to read. |
| index | Half-cell index, counted from 0. |
| bool kst_frame_read | ( | uint8_t | reg, |
| kst_frame_t * | out ) |
Read frame for register reg.
False, and no frame, for an address above KST_REG_MAX.
| reg | Register address, up to KST_REG_MAX. |
| out | Receives the frame. |
| void kst_frame_sync | ( | kst_frame_t * | out | ) |
The sync burst that puts a servo into programming mode.
| out | Receives the frame; NULL is ignored. |
| bool kst_frame_write | ( | uint8_t | reg, |
| uint8_t | value, | ||
| kst_frame_t * | out ) |
Write frame.
False, and no frame, for register 0x00 and for an address above KST_REG_MAX: neither is ever written.
| reg | Register address. |
| value | Value to write. |
| out | Receives the frame. |
| kst_rx_t kst_reply_decode | ( | const kst_capture_t * | cap, |
| kst_expect_t | expect, | ||
| kst_reply_t * | out ) |
Decode a reply window.
The decoder tracks the mid-cell edge of each of the 10 cells after the start cell and re-centres on every edge it finds. It does not classify run lengths: the last high of a reply is stretched by the release of the line. The value after a write is not a dependable echo; the caller reads the register back.
out is filled in every case; out->delay_ns and out->half_cell_ns are 0 where the check that failed comes before they are known.
| cap | Capture to decode. |
| expect | What the master sent. |
| out | Receives the decoded reply; NULL uses a scratch buffer. |
| uint32_t kst_reply_window_ns | ( | kst_expect_t | expect | ) |
Accept window and capture length for expect.
| expect | What the master sent. |