|
rcbench
Servo and ESC test bench: panel, IOmcu and shared C
|
The seam between the output bank and the pins. More...
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. | |
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
| 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.
| o | The output bank. |
| rate_hz | OUT_MAX_SLOTS entries, from outputs_slot_rates(). |
| 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.
| o | The output bank. |
| rate_hz | OUT_MAX_SLOTS entries, from outputs_slot_rates(). |
| may_bind | Bit mask of the slots that may be bound. The others are released and left unbound. |
| bool outputs_hw_bound | ( | uint8_t | slot | ) |
Whether slot slot is configured and bound to real silicon.
| slot | Slot index. |
| bool outputs_hw_edge | ( | uint64_t * | us | ) |
The edge stamped since the last call, once: true with its time in us.
| us | Receives the time of the edge, in microseconds. |
| 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.
| kind | The telemetry frame type. |
| value | Receives the payload byte, as the ESC sent it. |
| age_ms | Receives the time since the reading, in milliseconds. |
kind has been received. False otherwise. | 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.
| erpm | Receives the electrical rpm. |
| age_ms | Receives the time since the reading, in milliseconds. |
| void outputs_hw_init | ( | void | ) |
Forget every binding.
Call once, before the first apply.
| 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.
| pin | Pin of each port, one entry per port. |
| rate_hz | Rate of each port: kbit/s for DShot, frames per second for PWM. |
| parked | Bit n set when port n is parked. |
| dshot | Bit n set when port n runs DShot. |
| channel0 | Bank channel of port 0. |
| 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.
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.
| ports | Bit n set for port n. |
| 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.
| o | The output bank. |
| 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.
| ch | Output channel to watch, or a negative value to stop watching. |