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

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.

Detailed Description

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.

  • A reply has at most 23 edges. A capture is 200 bytes, against 2150 bytes for the 8ms window after a write sampled at 2MHz.
  • The decoder does not depend on the driver's sampling rate. A PIO (programmable input/output) program that counts cycles between edges and a DMA (direct memory access) sample buffer reduced to edges both fit.
  • The glitch rule is applied here, on the timestamps, so every driver gets the same rule.

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

Macro Definition Documentation

◆ KST_CAP_MAX_EDGES

#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.

◆ KST_FRAME_BITS

#define KST_FRAME_BITS   27u

master to servo

◆ KST_HALF_CELL_NS

#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.

◆ KST_RELEASE_NS

#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.

◆ KST_REPLY_BITS

#define KST_REPLY_BITS   11u

servo to master

◆ KST_RX_FINAL_EDGE_MAX_NS

#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.

◆ KST_RX_HALF_CELL_MIN_NS

#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.

◆ KST_SERVO_CELL_NS

#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.

◆ KST_SYNC_PULSES

#define KST_SYNC_PULSES   64u

The sync burst: 64 high pulses of one half-cell, one half-cell apart.

Other counts are not tested.

Enumeration Type Documentation

◆ kst_expect_t

What the master sent, which decides the accept window and the flags.

Enumerator
KST_EXPECT_READ 

a read frame was sent

KST_EXPECT_WRITE 

a write frame was sent

KST_EXPECT_SYNC 

a sync burst was sent

◆ kst_frame_kind_t

Kind of a master frame.

Enumerator
KST_FRAME_READ 

read request

KST_FRAME_WRITE 

write request

KST_FRAME_SYNC 

sync burst

◆ kst_rx_t

enum kst_rx_t

Result of decoding one reply window.

One code per failed check.

Enumerator
KST_RX_OK 

every check passed

KST_RX_NO_REPLY 

no edge in the window

KST_RX_QUIET 

an edge before the accept window

KST_RX_START_LEVEL 

the line is high when the capture starts

KST_RX_LATE 

first edge after the accept window

KST_RX_CELL 

a cell without opposite halves

KST_RX_LENGTH 

fewer or more than 11 cells

KST_RX_RATE 

mean half-cell outside 24.3 to 26.9us

KST_RX_FLAGS 

flag bits or sync value not as expected

KST_RX_FINAL_EDGE 

line still high 100us after the nominal end

KST_RX_WINDOW 

the capture ends before the quiet time does

KST_RX_OVERFLOW 

the capture lost edges

KST_RX_CAPTURE 

no capture, or edge times not ascending

Function Documentation

◆ kst_frame_duration_ns()

uint32_t kst_frame_duration_ns ( const kst_frame_t * frame)

Time the frame takes on the wire, in ns.

Parameters
frameFrame to measure.
Returns
Time the frame takes on the wire, in ns; 0 for a NULL frame.

◆ kst_frame_level()

bool kst_frame_level ( const kst_frame_t * frame,
unsigned index )

Level of half-cell index; false past the end.

Parameters
frameFrame to read.
indexHalf-cell index, counted from 0.
Returns
The level, 1 high or 0 low; false past the end.

◆ kst_frame_read()

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.

Parameters
regRegister address, up to KST_REG_MAX.
outReceives the frame.
Returns
true when a frame was built; false for an address above KST_REG_MAX.

◆ kst_frame_sync()

void kst_frame_sync ( kst_frame_t * out)

The sync burst that puts a servo into programming mode.

Parameters
outReceives the frame; NULL is ignored.

◆ kst_frame_write()

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.

Parameters
regRegister address.
valueValue to write.
outReceives the frame.
Returns
true when a frame was built.

◆ kst_reply_decode()

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.

Parameters
capCapture to decode.
expectWhat the master sent.
outReceives the decoded reply; NULL uses a scratch buffer.
Returns
KST_RX_OK, or the code of the first failed check.

◆ kst_reply_window_ns()

uint32_t kst_reply_window_ns ( kst_expect_t expect)

Accept window and capture length for expect.

Parameters
expectWhat the master sent.
Returns
Capture length in ns.