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

The programming ports and their link page (0x33). More...

#include <stdbool.h>
#include <stdint.h>
#include "link_pages.h"
#include "outputs.h"

Go to the source code of this file.

Data Structures

struct  prog_port_t
 The state of the programming ports: the PROG page's registers and which ports hold their pin. More...

Macros

#define PROG_PORT_CHANNEL0   9u
 The bank channel of port 0; port n has the next n-th.
#define PROG_PORT_RATE_HZ   50u
 A port's frame rate while the SERVO page names none.
#define PROG_PORT_DEFAULT_PIN   13u
 Port 0's pin on a board that has stored none: GP13, pad 17 of the bring-up module.
#define PROG_PORT_NO_PIN   0xFFu
 What prog_port_pin() returns for a port that holds no pin.
#define PROG_PORT_KEPT   4u
 The registers of one port that are kept in flash: PIN, SLEW, MIN_US, MAX_US. FUNC is kept apart, in one word (prog_port_kept_func()).
#define PROG_PORT_KEPT_COUNT   (LINK_PG_PORTS_MAX * PROG_PORT_KEPT)
#define PROG_PORT_FUNC_UNSTORED   0u
 The kept function word of a board that has stored none: every port at its default function (SERVO PWM for port 0, NONE for the others).

Functions

void prog_port_init (prog_port_t *p, uint8_t count)
 count ports, 0 to LINK_PG_PORTS_MAX, none with a pin, all at PROG_PORT_RATE_HZ.
void prog_port_defaults (uint16_t *kept, uint16_t pin0)
 The kept registers of a board that has stored none: port 0 on pin0 (LINK_PG_PIN_NONE for none), the others without a pin, slew 0, LINK_CC_DEFAULT_MIN to LINK_CC_DEFAULT_MAX.
void prog_port_restore (prog_port_t *p, const uint16_t *kept, outputs_t *o, uint64_t taken)
 Take the kept registers at start, after the slots and the other pin holders are restored.
void prog_port_restore_fn (prog_port_t *p, const uint16_t *kept, uint16_t func_word, outputs_t *o, uint64_t taken)
 As prog_port_restore(), with each port's function from the kept word func_word (prog_port_kept_func()): bits 4n to 4n + 3 hold 1 + port n's FUNC; 0, or a value no write would take, is the port's default.
uint16_t prog_port_kept_func (const prog_port_t *p)
 The functions as they stand, as the kept word: bits 4n to 4n + 3 hold 1 + port n's FUNC, never 0.
void prog_port_kept (const prog_port_t *p, uint16_t *kept)
 The kept registers as they stand, PROG_PORT_KEPT_COUNT of them.
uint8_t prog_port_write (prog_port_t *p, uint8_t off, uint8_t n, const uint16_t *in, outputs_t *o, uint64_t taken, bool locked, uint32_t now_ms)
 A write of the page: 0, or the LINK_NACK_* reason with nothing changed.
void prog_port_read (const prog_port_t *p, uint8_t off, uint8_t n, uint16_t *out)
 Read a window of the PROG page's registers into out.
void prog_port_revert (prog_port_t *p, const prog_port_t *was, outputs_t *o)
 Undo a write the silicon could not follow: the page as was, and each port's channel in o with the slew and endpoints of that page.
void prog_port_bound (prog_port_t *p, uint8_t mask)
 Tell the page which ports' pins are held by their function, bit n for port n: bound to the generator for SERVO PWM, parked for NONE, or held by a wire page.
uint8_t prog_port_count (const prog_port_t *p)
 The number of ports the model holds.
uint8_t prog_port_func (const prog_port_t *p, uint8_t port)
 Port port's function, a link_pg_func_t; NONE for a port the model does not hold.
uint8_t prog_port_pwm_ports (const prog_port_t *p)
 The SERVO PWM ports whose pin the generator has, bit n for port n: the ports a pulse bit and the TARGET may name.
uint8_t prog_port_parked (const prog_port_t *p)
 The NONE ports that hold a pin, bit n for port n: the pins the caller parks as inputs.
uint8_t prog_port_dshot (const prog_port_t *p)
 The DShot ports that hold a pin (FUNC DSHOT150 to DSHOT600, 4.28), bit n for port n: the pins the caller binds to a DShot state machine.
uint16_t prog_port_kbit (const prog_port_t *p, uint8_t port)
 Port port's DShot bit rate in kbit/s, 0 for another function.
uint8_t prog_port_pin (const prog_port_t *p, uint8_t port)
 The pin port port holds, or PROG_PORT_NO_PIN.
uint8_t prog_port_wire_pin (const prog_port_t *p, uint8_t port, uint8_t bound)
 The pin a wire page (KST, HITEC) may take for a session on port port: the port's pin while the IOmcu holds it (bound, bit n, as outputs_hw_ports_bound() says), PROG_PORT_NO_PIN otherwise and for a DShot port, whose lead goes to an ESC.
uint64_t prog_port_pins (const prog_port_t *p)
 Every pin the ports hold, one bit per pin.
uint8_t prog_port_pwm (const prog_port_t *p)
 Bit n: port n's pulse is switched on.
uint16_t prog_port_pwm_channels (const prog_port_t *p)
 The bank channels of the ports whose pulse is switched on, bit c for channel c: what servo_page_ports() is told.
uint16_t prog_port_sliced_channels (const prog_port_t *p)
 The bank channels of the ports whose pin shares a PWM slice with another port's pin, bit c for channel c: what servo_page_ports() is told as held at PROG_PORT_RATE_HZ.
void prog_port_rate (prog_port_t *p, uint16_t hz)
 The SERVO page's frame rate, 0 while it names none.
uint16_t prog_port_port_hz (const prog_port_t *p, uint8_t port)
 The frame rate port port runs at: the SERVO page's rate for the TARGET port while it names one, PROG_PORT_RATE_HZ otherwise.
uint8_t prog_port_target (const prog_port_t *p)
 0 for the standard servo ports, 1 + n for port n.
uint8_t prog_port_channel (uint8_t port)
 The bank channel of port.
uint8_t prog_port_slots_check (const prog_port_t *p, const uint16_t *slots)
 Whether the OUTPUTS page slots may be taken beside the ports: 0, or LINK_NACK_BAD_VALUE for a slot on a port's pin, a PWM slot on a SERVO PWM port pin's slice, or a bound slot whose channel range reaches a port's bank channel (PROG_PORT_CHANNEL0 to PROG_PORT_CHANNEL0 + LINK_PG_PORTS_MAX - 1).
unsigned prog_port_slots_free (uint16_t *slots)
 Unbinds every slot of slots whose channel range reaches a port's bank channel, for a stored page read at start.

Detailed Description

The programming ports and their link page (0x33).

A programming port is an output of its own kind. It has its own pin, is no slot of the OUTPUTS page and holds no channel of the CHANNELS page. Its pin carries the port's function (FUNC, protocol 4.26) while no wire page holds the port, or that page's wire protocol:

SERVO PWM a servo pulse from the PWM (pulse-width modulation) generator, rendered while the bank is armed and the port's bit in LINK_PG_PWM is set. The pulse is a channel of the bank (prog_port_channel()), so arming, clamping, slew, the 500ms command timeout and the endpoints are the bank's. NONE no driver: the pin is held for the port, parked as an input with its pull-down, and renders nothing. Any free header pin; no PWM-pin or slice rule. DSHOT150, DSHOT300, DSHOT600 (4.28) plain DShot at 150, 300 or 600kbit/s from a PIO state machine of its own, rendered from the port's channel as a motor slot is: the channel's role is THROTTLE, so ARM THROTTLE arms it and the CONTROL page's throttle commands it. Any free header pin; no PWM-pin or slice rule. The page's CMD register is refused on such a port. PROGRAMMING the wire protocol of the KST or HITEC page (kst_port.h, hitec_port.h), which takes the pin from the function and gives it back.

A FUNC write is refused, as a PIN write is, while the bank is armed, a wire page holds a port, the port's pulse is on or the port is the TARGET. The pulse and the TARGET name SERVO PWM ports only, so the servo tester never drives a NONE or DShot port. Port 0 starts as SERVO PWM, the others as NONE.

The servo tester reaches a port three ways: LINK_PG_CMD is the manual command, LINK_PG_TARGET points the SERVO page's sweep and hold at the port (servo_page_target()), and a capture of the SERVO_SENSE page names the port with LINK_SS_ARM_PORT.

Pins. A port's pin and a slot's pin are never the same: a PIN write refuses a slot's pin, and prog_port_slots_check() refuses a slot on a port's pin. A SERVO PWM port's pin shares no PWM slice and no compare register with a PWM slot's pin either, so neither can change the other's frame rate. Two SERVO PWM ports may share a slice; both then run at PROG_PORT_RATE_HZ. A NONE or DShot port's pin is under none of the PWM rules.

Rates. Every port runs at PROG_PORT_RATE_HZ, 50Hz, except the TARGET port while the SERVO page names a rate: that port alone runs at it (protocol 4.19). A slice counts against one wrap register, so a port whose pin shares its slice with another port's pin takes no rate but 50Hz (servo_page_write()), and no pin moves onto the slice of a TARGET port that runs at another rate.

The model holds LINK_PG_PORTS_MAX ports; a build names how many it has.

Pure logic: binding a pin to the generator is the caller's.

SPDX-License-Identifier: MIT

Macro Definition Documentation

◆ PROG_PORT_CHANNEL0

#define PROG_PORT_CHANNEL0   9u

The bank channel of port 0; port n has the next n-th.

Above the 8 channels of the CHANNELS page and the bench throttle's channel 8.

◆ PROG_PORT_DEFAULT_PIN

#define PROG_PORT_DEFAULT_PIN   13u

Port 0's pin on a board that has stored none: GP13, pad 17 of the bring-up module.

Its PWM slice partner GP12 is reserved and the pin with its compare register, GP29, is not on the header.

Function Documentation

◆ prog_port_bound()

void prog_port_bound ( prog_port_t * p,
uint8_t mask )

Tell the page which ports' pins are held by their function, bit n for port n: bound to the generator for SERVO PWM, parked for NONE, or held by a wire page.

A port that loses its pin loses its PWM bit and, if it was the TARGET, the target returns to the standard servo ports.

Parameters
pThe port model.
maskBit n for port n: bound to the generator for SERVO PWM, parked for NONE, or held by a wire page.

◆ prog_port_channel()

uint8_t prog_port_channel ( uint8_t port)

The bank channel of port.

Parameters
portPort index.
Returns
The bank channel of the port, PROG_PORT_CHANNEL0 + port.

◆ prog_port_count()

uint8_t prog_port_count ( const prog_port_t * p)

The number of ports the model holds.

Parameters
pThe port model, or NULL.
Returns
The port count; 0 for a NULL p.

◆ prog_port_defaults()

void prog_port_defaults ( uint16_t * kept,
uint16_t pin0 )

The kept registers of a board that has stored none: port 0 on pin0 (LINK_PG_PIN_NONE for none), the others without a pin, slew 0, LINK_CC_DEFAULT_MIN to LINK_CC_DEFAULT_MAX.

Parameters
keptReceives PROG_PORT_KEPT_COUNT kept registers, written in place.
pin0The pin of port 0, or LINK_PG_PIN_NONE for none.

◆ prog_port_dshot()

uint8_t prog_port_dshot ( const prog_port_t * p)

The DShot ports that hold a pin (FUNC DSHOT150 to DSHOT600, 4.28), bit n for port n: the pins the caller binds to a DShot state machine.

Parameters
pThe port model.
Returns
Bit n set for port n when it is a DShot port that holds a pin; 0 for a NULL p.

◆ prog_port_func()

uint8_t prog_port_func ( const prog_port_t * p,
uint8_t port )

Port port's function, a link_pg_func_t; NONE for a port the model does not hold.

Parameters
pThe port model, or NULL.
portPort index, 0 to LINK_PG_PORTS_MAX - 1.
Returns
The function, a link_pg_func_t value; LINK_PG_FN_NONE for a NULL p or a port of LINK_PG_PORTS_MAX or more.

◆ prog_port_init()

void prog_port_init ( prog_port_t * p,
uint8_t count )

count ports, 0 to LINK_PG_PORTS_MAX, none with a pin, all at PROG_PORT_RATE_HZ.

Parameters
pThe port model to set up.
countPorts the build has, 0 to LINK_PG_PORTS_MAX; a larger value is clamped.

◆ prog_port_kbit()

uint16_t prog_port_kbit ( const prog_port_t * p,
uint8_t port )

Port port's DShot bit rate in kbit/s, 0 for another function.

Parameters
pThe port model, or NULL.
portPort index, 0 to LINK_PG_PORTS_MAX - 1.
Returns
The bit rate in kbit/s; 0 for a NULL p, a port of LINK_PG_PORTS_MAX or more, or a function that is not DShot.

◆ prog_port_kept()

void prog_port_kept ( const prog_port_t * p,
uint16_t * kept )

The kept registers as they stand, PROG_PORT_KEPT_COUNT of them.

Parameters
pThe port model.
keptReceives PROG_PORT_KEPT_COUNT registers, written in place.

◆ prog_port_kept_func()

uint16_t prog_port_kept_func ( const prog_port_t * p)

The functions as they stand, as the kept word: bits 4n to 4n + 3 hold 1 + port n's FUNC, never 0.

Parameters
pThe port model.
Returns
The kept function word; PROG_PORT_FUNC_UNSTORED for a NULL p.

◆ prog_port_parked()

uint8_t prog_port_parked ( const prog_port_t * p)

The NONE ports that hold a pin, bit n for port n: the pins the caller parks as inputs.

Parameters
pThe port model.
Returns
Bit n set for port n when it is a NONE port that holds a pin; 0 for a NULL p.

◆ prog_port_pin()

uint8_t prog_port_pin ( const prog_port_t * p,
uint8_t port )

The pin port port holds, or PROG_PORT_NO_PIN.

Parameters
pThe port model, or NULL.
portPort index.
Returns
The pin the port holds, or PROG_PORT_NO_PIN for a NULL p or a port that holds no pin.

◆ prog_port_pins()

uint64_t prog_port_pins ( const prog_port_t * p)

Every pin the ports hold, one bit per pin.

Parameters
pThe port model, or NULL.
Returns
One bit per pin the ports hold; 0 for a NULL p.

◆ prog_port_port_hz()

uint16_t prog_port_port_hz ( const prog_port_t * p,
uint8_t port )

The frame rate port port runs at: the SERVO page's rate for the TARGET port while it names one, PROG_PORT_RATE_HZ otherwise.

Parameters
pThe port model, or NULL.
portPort index.
Returns
The frame rate of the port in Hz; PROG_PORT_RATE_HZ for a NULL p.

◆ prog_port_pwm()

uint8_t prog_port_pwm ( const prog_port_t * p)

Bit n: port n's pulse is switched on.

Parameters
pThe port model, or NULL.
Returns
The pulse bits, bit n for port n; 0 for a NULL p.

◆ prog_port_pwm_channels()

uint16_t prog_port_pwm_channels ( const prog_port_t * p)

The bank channels of the ports whose pulse is switched on, bit c for channel c: what servo_page_ports() is told.

Parameters
pThe port model, or NULL.
Returns
Bit c set for each bank channel c of a port whose pulse is on; 0 for a NULL p.

◆ prog_port_pwm_ports()

uint8_t prog_port_pwm_ports ( const prog_port_t * p)

The SERVO PWM ports whose pin the generator has, bit n for port n: the ports a pulse bit and the TARGET may name.

Parameters
pThe port model.
Returns
Bit n set for port n when it is a SERVO PWM port whose pin is bound; 0 for a NULL p.

◆ prog_port_rate()

void prog_port_rate ( prog_port_t * p,
uint16_t hz )

The SERVO page's frame rate, 0 while it names none.

It reaches the TARGET port only; a write is judged against it.

Parameters
pThe port model, or NULL; a NULL p is ignored.
hzThe SERVO page's frame rate in Hz, 0 for none.

◆ prog_port_read()

void prog_port_read ( const prog_port_t * p,
uint8_t off,
uint8_t n,
uint16_t * out )

Read a window of the PROG page's registers into out.

Parameters
pThe port model.
offFirst register of the window.
nNumber of registers to read.
outReceives n register values; left unchanged for a NULL p or out, or a window beyond LINK_PG_REGS.

◆ prog_port_restore()

void prog_port_restore ( prog_port_t * p,
const uint16_t * kept,
outputs_t * o,
uint64_t taken )

Take the kept registers at start, after the slots and the other pin holders are restored.

A value no write would take becomes its default, except a slew above LINK_CC_SLEW_MAX, which becomes LINK_CC_SLEW_MAX. A pin that is taken (a slot's, one in taken, reserved in o, or beside a PWM slot in the silicon) stays on the page and is not held: LINK_PG_FLAGS says refused until another pin is written. Sets the role, slew and endpoints of each port's channel in o.

Parameters
pThe port model to restore into.
keptPROG_PORT_KEPT_COUNT kept registers, as prog_port_kept() wrote them.
oThe outputs model whose port channels are set.
takenBit n: pin n is held by another holder beyond the slots and the bank's reservation.

◆ prog_port_restore_fn()

void prog_port_restore_fn ( prog_port_t * p,
const uint16_t * kept,
uint16_t func_word,
outputs_t * o,
uint64_t taken )

As prog_port_restore(), with each port's function from the kept word func_word (prog_port_kept_func()): bits 4n to 4n + 3 hold 1 + port n's FUNC; 0, or a value no write would take, is the port's default.

A kept pin is judged under its port's function: a SERVO PWM port's pin must be a pin of the generator.

Parameters
pThe port model to restore into.
keptPROG_PORT_KEPT_COUNT kept registers, as prog_port_kept() wrote them.
func_wordThe kept function word, as prog_port_kept_func() wrote it.
oThe outputs model whose port channels are set.
takenBit n: pin n is held by another holder beyond the slots and the bank's reservation.

◆ prog_port_revert()

void prog_port_revert ( prog_port_t * p,
const prog_port_t * was,
outputs_t * o )

Undo a write the silicon could not follow: the page as was, and each port's channel in o with the slew and endpoints of that page.

A command the write carried stays commanded.

Parameters
pThe port model, overwritten with was.
wasThe port model as it stood before the write that failed.
oThe outputs model whose port channels are set.

◆ prog_port_sliced_channels()

uint16_t prog_port_sliced_channels ( const prog_port_t * p)

The bank channels of the ports whose pin shares a PWM slice with another port's pin, bit c for channel c: what servo_page_ports() is told as held at PROG_PORT_RATE_HZ.

Parameters
pThe port model, or NULL.
Returns
Bit c set for each bank channel c of a port whose pin shares a PWM slice with another port's pin; 0 for a NULL p.

◆ prog_port_slots_check()

uint8_t prog_port_slots_check ( const prog_port_t * p,
const uint16_t * slots )

Whether the OUTPUTS page slots may be taken beside the ports: 0, or LINK_NACK_BAD_VALUE for a slot on a port's pin, a PWM slot on a SERVO PWM port pin's slice, or a bound slot whose channel range reaches a port's bank channel (PROG_PORT_CHANNEL0 to PROG_PORT_CHANNEL0 + LINK_PG_PORTS_MAX - 1).

Parameters
pThe port model, or NULL.
slotsThe OUTPUTS slot registers, LINK_OUT_SLOTS slots of LINK_OS_STRIDE registers each.
Returns
0 when the slots may be taken; LINK_NACK_BAD_VALUE for a NULL slots or a refused slot (see above). 0 for a NULL p.

◆ prog_port_slots_free()

unsigned prog_port_slots_free ( uint16_t * slots)

Unbinds every slot of slots whose channel range reaches a port's bank channel, for a stored page read at start.

Returns how many.

Parameters
slotsThe OUTPUTS slot registers, LINK_OUT_SLOTS slots of LINK_OS_STRIDE registers each; a slot on a port's channel has its driver cleared in place.
Returns
The number of slots unbound; 0 for NULL slots.

◆ prog_port_target()

uint8_t prog_port_target ( const prog_port_t * p)

0 for the standard servo ports, 1 + n for port n.

Parameters
pThe port model, or NULL.
Returns
1 + n for the TARGET port n, 0 for the standard servo ports; 0 for a NULL p.

◆ prog_port_wire_pin()

uint8_t prog_port_wire_pin ( const prog_port_t * p,
uint8_t port,
uint8_t bound )

The pin a wire page (KST, HITEC) may take for a session on port port: the port's pin while the IOmcu holds it (bound, bit n, as outputs_hw_ports_bound() says), PROG_PORT_NO_PIN otherwise and for a DShot port, whose lead goes to an ESC.

Parameters
pThe port model, or NULL.
portPort index, 0 to LINK_PG_PORTS_MAX - 1.
boundBit n for port n: the port's pin is held by the IOmcu (outputs_hw_ports_bound()).
Returns
The pin for the wire page, or PROG_PORT_NO_PIN (see above).

◆ prog_port_write()

uint8_t prog_port_write ( prog_port_t * p,
uint8_t off,
uint8_t n,
const uint16_t * in,
outputs_t * o,
uint64_t taken,
bool locked,
uint32_t now_ms )

A write of the page: 0, or the LINK_NACK_* reason with nothing changed.

taken: the pins other holders have beyond the slots and the bank's reservation. locked: no PIN or FUNC may change now (the bank is armed or asked to arm, or a wire page holds a port). A PIN or FUNC change is also refused for a port whose PWM bit is set or that is the TARGET, before or after the frame. A FUNC above LINK_PG_FN_NONE, and any register of a port the build does not have, is BAD_VALUE. A PIN is judged under the FUNC the frame leaves its port with.

PWM and TARGET name only SERVO PWM ports whose pin the generator has (prog_port_bound()), and not a port whose PIN or FUNC the same frame changes.

No port whose PWM bit the write leaves set may have an endpoint longer than its frame carries: MIN_US and MAX_US at most out_pwm_pulse_max() of the rate the write leaves the port at (prog_port_port_hz()), 1784us at 560Hz (BAD_VALUE, protocol 4.16). This covers a range written to a pulsing port and a pulse switched on under a range that does not fit.

A TARGET change returns the SERVO rate to 0 (servo_page_target()), so every port is judged at PROG_PORT_RATE_HZ after one, and the write sets the rate prog_port_rate() last named to 0 as well: prog_port_port_hz() then names the rate each port runs at once the write is in force, before the SERVO page has followed the TARGET. Refused as well (BAD_VALUE, protocol 4.19): a TARGET change away from the standard servo ports while they run at a SERVO rate, when a PWM slot back at its own rate would carry a pulse longer than its frame (outputs_pulse_check()); and a PIN that puts a port on the PWM slice of the TARGET port while that port runs at a rate other than PROG_PORT_RATE_HZ.

Parameters
pThe port model, updated when the write is applied.
offFirst register of the window; below LINK_PG_PWM is read-only.
nNumber of registers in the window; 0 applies nothing.
inThe n register values to write.
oThe outputs model whose port channels are set.
takenBit n: pin n is held by another holder beyond the slots and the bank's reservation.
lockedTrue refuses every PIN and FUNC change.
now_msCurrent time in milliseconds, passed on for a CMD write.
Returns
0 when the write is applied; otherwise the LINK_NACK_* reason: LINK_NACK_BAD_RANGE for a NULL argument or a window beyond LINK_PG_REGS, LINK_NACK_READ_ONLY for a window below LINK_PG_PWM, LINK_NACK_BAD_VALUE for a value refused as described above.