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

The seam between the output bank and the pins. More...

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

Go to the source code of this file.

Functions

void outputs_hw_init (void)
 Forget every binding.
void outputs_hw_apply (const outputs_t *o, const uint16_t *rate_hz)
 Make the bindings match the bank's slot table, each slot at the rate in rate_hz (OUT_MAX_SLOTS entries, from outputs_slot_rates()) rather than its own.
void outputs_hw_apply_only (const outputs_t *o, const uint16_t *rate_hz, uint8_t may_bind)
 As outputs_hw_apply(), with only the slots in may_bind bound; a slot outside it is released and left unbound.
void outputs_hw_service (const outputs_t *o)
 Render the bank onto the pins.
void outputs_hw_ports (const uint8_t *pin, const uint16_t *rate_hz, uint8_t parked, uint8_t dshot, uint8_t channel0)
 The programming ports' pins: pin[n] for port n, LINK_PG_PORTS_MAX entries, a value above OUT_MAX_PIN for a port without one.
uint8_t outputs_hw_ports_bound (void)
 The ports whose function holds their pin, bit n for port n: bound to the generator or to DShot, or parked.
void outputs_hw_ports_drive (uint8_t ports)
 Which bound ports render their channel's pulse while the bank drives, bit n for port n.
void outputs_hw_watch (int ch)
 Watch output channel ch for a move capture's edge; a negative ch stops watching.
bool outputs_hw_edge (uint64_t *us)
 The edge stamped since the last call, once: true with its time in us.
bool outputs_hw_bound (uint8_t slot)
 Whether slot slot is configured and bound to real silicon.
bool outputs_hw_erpm (uint32_t *erpm, uint32_t *age_ms)
 The last electrical rpm a bidirectional DShot ESC (electronic speed controller) reported, and how long ago in milliseconds.
bool outputs_hw_edt (dshot_telem_kind_t kind, uint16_t *value, uint32_t *age_ms)
 The last extended-telemetry reading of kind, and how long ago in milliseconds.

Detailed Description

The seam between the output bank and the pins.

shared/outputs answers what every output should be doing – role, rest, slew, clamp, arming, the silence timeout – and knows nothing about a pin. This turns the answer into edges, by binding a backend to each configured slot and rendering the bank into it every pass.

Nothing here decides anything. If it looks like a policy, it belongs in shared/outputs where the host suite can hold it: the one question this file answers on its own is whether the silicon could do what was asked, and it answers that by refusing a slot rather than by driving something else.

SPDX-License-Identifier: MIT

Function Documentation

◆ outputs_hw_apply()

void outputs_hw_apply ( const outputs_t * o,
const uint16_t * rate_hz )

Make the bindings match the bank's slot table, each slot at the rate in rate_hz (OUT_MAX_SLOTS entries, from outputs_slot_rates()) rather than its own.

Call after anything that changes a slot, a role or a rate. A slot that has not changed is left alone rather than rebuilt, so reconfiguring one output does not interrupt another; a slot the silicon cannot serve is left unbound, and outputs_hw_bound() says so.

Parameters
oThe output bank.
rate_hzOUT_MAX_SLOTS entries, from outputs_slot_rates().

◆ outputs_hw_apply_only()

void outputs_hw_apply_only ( const outputs_t * o,
const uint16_t * rate_hz,
uint8_t may_bind )

As outputs_hw_apply(), with only the slots in may_bind bound; a slot outside it is released and left unbound.

A refused OUTPUTS write puts back exactly the set that was bound before it, so a slot unbound then cannot take the resource a slot bound then needs. When a slot that runs on PIO (DShot, PPM) is bound anew, every DShot programming port is let go first, so the slots take the state machines before the ports; the caller binds the ports again with outputs_hw_ports() after.

Parameters
oThe output bank.
rate_hzOUT_MAX_SLOTS entries, from outputs_slot_rates().
may_bindBit mask of the slots that may be bound. The others are released and left unbound.

◆ outputs_hw_bound()

bool outputs_hw_bound ( uint8_t slot)

Whether slot slot is configured and bound to real silicon.

Parameters
slotSlot index.
Returns
True when the slot is bound.

◆ outputs_hw_edge()

bool outputs_hw_edge ( uint64_t * us)

The edge stamped since the last call, once: true with its time in us.

Parameters
usReceives the time of the edge, in microseconds.
Returns
True when an edge was stamped since the last call.

◆ outputs_hw_edt()

bool outputs_hw_edt ( dshot_telem_kind_t kind,
uint16_t * value,
uint32_t * age_ms )

The last extended-telemetry reading of kind, and how long ago in milliseconds.

Raw: the payload byte as the ESC sent it, because the units belong to the frame type and not to this file. Returns false for a kind no reply has carried, which is every kind on an ESC that does not do extended telemetry and all of them until one has been asked and has answered.

Each kind carries its own age. They do not arrive together: speed comes back on every frame and the rest are interleaved between them.

Parameters
kindThe telemetry frame type.
valueReceives the payload byte, as the ESC sent it.
age_msReceives the time since the reading, in milliseconds.
Returns
True when a reply of kind has been received. False otherwise.

◆ outputs_hw_erpm()

bool outputs_hw_erpm ( uint32_t * erpm,
uint32_t * age_ms )

The last electrical rpm a bidirectional DShot ESC (electronic speed controller) reported, and how long ago in milliseconds.

Electrical rather than mechanical: an ESC reports periods and has no idea what it is bolted to, and the pole count arrives separately. Returns false when no ESC has ever answered.

Parameters
erpmReceives the electrical rpm.
age_msReceives the time since the reading, in milliseconds.
Returns
True when an ESC has answered. False when none has ever answered.

◆ outputs_hw_init()

void outputs_hw_init ( void )

Forget every binding.

Call once, before the first apply.

◆ outputs_hw_ports()

void outputs_hw_ports ( const uint8_t * pin,
const uint16_t * rate_hz,
uint8_t parked,
uint8_t dshot,
uint8_t channel0 )

The programming ports' pins: pin[n] for port n, LINK_PG_PORTS_MAX entries, a value above OUT_MAX_PIN for a port without one.

A port in parked (bit n, FUNC NONE) holds its pin as an input with its pull-down and renders nothing. A port in dshot (bit n, FUNC DSHOT150 to DSHOT600) is bound to a DShot state machine at rate_hz[n] kbit/s and rendered as a plain DShot slot is: a frame every 1ms while the bank is armed for its channel's role, the throttle, and none while it is not. Any other port's pin is bound to the PWM generator at rate_hz[n] frames a second (SERVO PWM). A port whose pin, rate or function moved is released and held again; one that did not is left running. A port is no slot: it is rendered from bank channel channel0 + n. A pin the chip does not have, or a DShot pin no state machine is left for, is not held.

Parameters
pinPin of each port, one entry per port.
rate_hzRate of each port: kbit/s for DShot, frames per second for PWM.
parkedBit n set when port n is parked.
dshotBit n set when port n runs DShot.
channel0Bank channel of port 0.

◆ outputs_hw_ports_bound()

uint8_t outputs_hw_ports_bound ( void )

The ports whose function holds their pin, bit n for port n: bound to the generator or to DShot, or parked.

Returns
Bit n set for port n.

◆ outputs_hw_ports_drive()

void outputs_hw_ports_drive ( uint8_t ports)

Which bound ports render their channel's pulse while the bank drives, bit n for port n.

A port left out is written a pulse of 0, as a disarmed bank writes it: the pulse in progress completes and the pin rests low. None until told.

Parameters
portsBit n set for port n.

◆ outputs_hw_service()

void outputs_hw_service ( const outputs_t * o)

Render the bank onto the pins.

Call every pass.

Nothing edges unless outputs_driving() is true. DShot has a send rate of its own, because its frame rate is not the bank's business and the OUTPUTS page's rate field is a bit rate for it rather than a frame rate.

Parameters
oThe output bank.

◆ outputs_hw_watch()

void outputs_hw_watch ( int ch)

Watch output channel ch for a move capture's edge; a negative ch stops watching.

The first later pass that renders a pulse other than the one before it on ch's PWM slot or programming port writes it stamped (out_pwm_write_stamped()) and ends the watch: the start of the frame that first carries the new pulse, on time_us_64(). A pulse of 0, the bank stopping, is not an edge. A slot that is not PWM never stamps.

Parameters
chOutput channel to watch, or a negative value to stop watching.