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

PPM (pulse-position modulation) out: one pin, several channels, driven by a PIO (programmable input/output) state machine fed by a pair of DMA (direct memory access) channels that restart each other. More...

#include <stdbool.h>
#include <stdint.h>

Go to the source code of this file.

Macros

#define OUT_PPM_MAX_PINS   8u
 Pins that can be bound at one time.

Functions

bool out_ppm_bind (uint8_t pin, uint8_t channels, uint16_t rate_hz)
 Take pin for channels channels at rate_hz frames a second.
void out_ppm_release (uint8_t pin)
 Give the pin, the state machine and both DMA channels back.
bool out_ppm_write (uint8_t pin, const uint16_t *channel_us, uint8_t channels)
 Lay channels pulse widths into the frame and keep sending it.
void out_ppm_stop (uint8_t pin)
 Stop emitting; the pin is left low.

Detailed Description

PPM (pulse-position modulation) out: one pin, several channels, driven by a PIO (programmable input/output) state machine fed by a pair of DMA (direct memory access) channels that restart each other.

The processor is not in the timing path at all. One DMA channel plays the frame into the state machine and chains to a second, whose only transfer writes the buffer address back into the first and retriggers it, so the frame repeats forever whatever the loop is doing. A frame is 22.5ms and the state machine's queue is eight words deep; anything that fed it from the loop would produce a stretched frame every time the loop was busy, and a stretched frame is a servo that twitches.

The frame buffer is written in place while it is being played. A channel updated mid-frame therefore takes effect on the next frame and the rest of that frame carries the previous values, which is one frame of staleness on a signal that is a stream of frames. The alternative, swapping buffers, buys nothing: the receiver acts on whole frames either way.

SPDX-License-Identifier: MIT

Macro Definition Documentation

◆ OUT_PPM_MAX_PINS

#define OUT_PPM_MAX_PINS   8u

Pins that can be bound at one time.

A project that needs another number defines it for the whole build.

Function Documentation

◆ out_ppm_bind()

bool out_ppm_bind ( uint8_t pin,
uint8_t channels,
uint16_t rate_hz )

Take pin for channels channels at rate_hz frames a second.

Refuses a frame rate that cannot carry that many channels at their widest (see ppm_min_frame_us), a pin no PIO block can reach alongside its other programs, and a shortage of state machines or DMA channels. Nothing is emitted until the first out_ppm_write().

A pin that is already bound with the same channel count and frame period stays as it is and the call returns true. With a different count or period it returns false and the old binding keeps running; release the pin first to change it.

Parameters
pinGPIO number.
channelsNumber of channels.
rate_hzFrames per second; refused when rate_hz is 0 or the frame period is below 2us or above 65535us.
Returns
true when the pin is bound with these parameters, false otherwise.

◆ out_ppm_release()

void out_ppm_release ( uint8_t pin)

Give the pin, the state machine and both DMA channels back.

Parameters
pinGPIO number. A pin that is not bound is ignored.

◆ out_ppm_stop()

void out_ppm_stop ( uint8_t pin)

Stop emitting; the pin is left low.

The next write starts it again.

Parameters
pinGPIO number. A pin that is not running is ignored.

◆ out_ppm_write()

bool out_ppm_write ( uint8_t pin,
const uint16_t * channel_us,
uint8_t channels )

Lay channels pulse widths into the frame and keep sending it.

Returns false, and stops the output, for a set of widths that cannot be laid out in the frame this pin was bound with. A refused frame is not half-written: ppm_frame() builds it whole or not at all.

Parameters
pinGPIO number.
channel_usPulse width of each channel, in us.
channelsNumber of channels, which must match the binding.
Returns
true when the frame is sent, false otherwise.