|
rcbench
Servo and ESC test bench: panel, IOmcu and shared C
|
Servo pulses from the RP2350's hardware PWM (pulse-width modulation). More...
#include <stdbool.h>#include <stdint.h>Go to the source code of this file.
Macros | |
| #define | OUT_PWM_STAMP_WAIT_US 5u |
| How long the stamped write may wait for the counter to leave the end of its frame, us. | |
Functions | |
| bool | out_pwm_bind (uint8_t pin, uint16_t rate_hz) |
Take pin at rate_hz frames a second. | |
| void | out_pwm_release (uint8_t pin) |
| Give the pin back: the counter stops and the pin is left low. | |
| void | out_pwm_write (uint8_t pin, uint16_t pulse_us) |
Emit pulse_us on every frame. | |
| bool | out_pwm_write_stamped (uint8_t pin, uint16_t pulse_us, uint64_t *frame_us) |
out_pwm_write(), and the time the first frame carrying pulse_us starts, on the 64-bit microsecond timer (time_us_64()), into frame_us. | |
Servo pulses from the RP2350's hardware PWM (pulse-width modulation).
A servo pulse is a level held for a number of microseconds, repeated at a frame rate, and that is what a PWM slice does with no processor involved. There is no reason to spend a PIO (programmable input/output) state machine on it: the part has twelve slices and twenty-four channels, more outputs than this bench has connectors.
What a caller has to know is how GPIO (general-purpose input/output) numbers fold onto them. A slice is two channels sharing one counter, so two pins on the same slice run at the same frame rate whatever the second one asked for, and a second binding with a different rate is refused rather than quietly retimed. Below that, a channel is one compare register: pins 16 apart under GP32 – GP0 and GP16 – and pins 8 apart above it – GP32 and GP40 – are the same channel of the same slice and cannot hold two pulse widths, so the second of such a pair is refused outright. out_pwm_map.h has the fold and the host suite tests it.
SPDX-License-Identifier: MIT
| #define OUT_PWM_STAMP_WAIT_US 5u |
How long the stamped write may wait for the counter to leave the end of its frame, us.
Two counts at most when the slice runs.
| bool out_pwm_bind | ( | uint8_t | pin, |
| uint16_t | rate_hz ) |
Take pin at rate_hz frames a second.
Refuses a pin whose compare register another bound pin already holds, a pin that is already bound to a different rate's slice, a pin the package does not have, and a rate whose period does not fit the counter. Binding an already-bound pin at the same rate succeeds and changes nothing, so a reconfiguration that did not move a slot does not glitch its output.
A refused bind leaves the slot unbound and the OUTPUTS page reading back what was asked for. Nothing on the wire reports whether a slot is bound, so an unbound slot is not distinguishable from a bound one at the panel.
| pin | GPIO number of the pin to bind. |
| rate_hz | Frame rate in Hz. Zero is refused. |
rate_hz. False when the bind is refused. | void out_pwm_release | ( | uint8_t | pin | ) |
Give the pin back: the counter stops and the pin is left low.
| pin | GPIO number of the pin to release. A pin that is not bound is ignored. |
| void out_pwm_write | ( | uint8_t | pin, |
| uint16_t | pulse_us ) |
Emit pulse_us on every frame.
Zero stops the pin edging altogether, which is what the bank means by not driving – a servo held at a pulse it was not commanded is worse than one that is let go.
| pin | GPIO number of a bound pin. A pin that is not bound is ignored. |
| pulse_us | Pulse width in microseconds. A value above the frame's last count is clamped to it. |
| bool out_pwm_write_stamped | ( | uint8_t | pin, |
| uint16_t | pulse_us, | ||
| uint64_t * | frame_us ) |
out_pwm_write(), and the time the first frame carrying pulse_us starts, on the 64-bit microsecond timer (time_us_64()), into frame_us.
The compare register is double-buffered: a level written during a frame takes effect at the wrap that ends it, and the pin rises at counter 0. The counter is read and the level written with interrupts off, never in the frame's last 2 counts – a write there could meet the wrap that latches it, and the frame it lands in would be unknown – so the write lands in the frame the counter was read in, and that frame ends (wrap - counter + 1) counts later. One count is 1us, from clk_sys divided to 1MHz; the timer ticks at 1MHz from the same crystal. The stamp is good to the 1us of each, within +-1us.
False, with the level written and nothing stamped, for a pin not bound or a slice whose counter does not leave the frame's end within OUT_PWM_STAMP_WAIT_US: one that is not counting.
| pin | GPIO number of a bound pin. A pin that is not bound is refused. |
| pulse_us | Pulse width in microseconds. A value above the frame's last count is clamped to it. |
| frame_us | Receives the start time of the frame. Written only when the function returns true. |