Merge branch 'refs/heads/main' into resample_methods

# Conflicts:
#	examples/xdisplay_mirror.py
This commit is contained in:
foamyguy 2025-03-13 16:22:30 -05:00
commit fe7c44be88
22 changed files with 2354 additions and 2293 deletions

View file

@ -12,6 +12,9 @@
# #
# See https://github.com/pre-commit/pre-commit # See https://github.com/pre-commit/pre-commit
# Don't re-format vendored files
exclude: "^src/piolib/.*$"
ci: ci:
autoupdate_commit_msg: "chore: update pre-commit hooks" autoupdate_commit_msg: "chore: update pre-commit hooks"
autofix_commit_msg: "style: pre-commit fixes" autofix_commit_msg: "style: pre-commit fixes"

View file

@ -20,14 +20,12 @@ Here's an example for running an emulator using a rom stored in "/tmp/snesrom.sm
$ python virtualdisplay.py --pinout AdafruitMatrixHatBGR --scale 2 --backend xvfb --width 128 --height 128 --serpentine --num-address-lines 5 --num-planes 4 -- mednafen -snes.xscalefs 1 -snes.yscalefs 1 -snes.xres 128 -video.fs 1 -video.driver softfb /tmp/snesrom.smc $ python virtualdisplay.py --pinout AdafruitMatrixHatBGR --scale 2 --backend xvfb --width 128 --height 128 --serpentine --num-address-lines 5 --num-planes 4 -- mednafen -snes.xscalefs 1 -snes.yscalefs 1 -snes.xres 128 -video.fs 1 -video.driver softfb /tmp/snesrom.smc
""" """
# To run a nice emulator:
import shlex import shlex
from subprocess import Popen from subprocess import Popen
import click import click
import numpy as np import numpy as np
from PIL import ImageEnhance
from pyvirtualdisplay.smartdisplay import SmartDisplay from pyvirtualdisplay.smartdisplay import SmartDisplay
import adafruit_blinka_raspberry_pi5_piomatter as piomatter import adafruit_blinka_raspberry_pi5_piomatter as piomatter
@ -40,10 +38,12 @@ from adafruit_blinka_raspberry_pi5_piomatter.pixelmappers import simple_multilan
@click.option("--backend", help="The pyvirtualdisplay backend to use", default="xvfb") @click.option("--backend", help="The pyvirtualdisplay backend to use", default="xvfb")
@click.option("--extra-args", help="Extra arguments to pass to the backend server", default="") @click.option("--extra-args", help="Extra arguments to pass to the backend server", default="")
@click.option("--rfbport", help="The port number for the --backend xvnc", default=None, type=int) @click.option("--rfbport", help="The port number for the --backend xvnc", default=None, type=int)
@click.option("--brightness", help="The brightness factor of the image output to the matrix",
default=1.0, type=click.FloatRange(min=0.1, max=1.0))
@click.option("--use-xauth/--no-use-xauth", help="If a Xauthority file should be created", default=False) @click.option("--use-xauth/--no-use-xauth", help="If a Xauthority file should be created", default=False)
@piomatter_click.standard_options @piomatter_click.standard_options
@click.argument("command", nargs=-1) @click.argument("command", nargs=-1)
def main(scale, backend, use_xauth, extra_args, rfbport, width, height, serpentine, rotation, pinout, def main(scale, backend, use_xauth, extra_args, rfbport, brightness, width, height, serpentine, rotation, pinout,
n_planes, n_temporal_planes, n_addr_lines, n_lanes, command): n_planes, n_temporal_planes, n_addr_lines, n_lanes, command):
kwargs = {} kwargs = {}
if backend == "xvnc": if backend == "xvnc":
@ -64,8 +64,12 @@ def main(scale, backend, use_xauth, extra_args, rfbport, width, height, serpenti
with SmartDisplay(backend=backend, use_xauth=use_xauth, size=(round(width*scale),round(height*scale)), manage_global_env=False, **kwargs) as disp, Popen(command, env=disp.env()) as proc: with SmartDisplay(backend=backend, use_xauth=use_xauth, size=(round(width*scale),round(height*scale)), manage_global_env=False, **kwargs) as disp, Popen(command, env=disp.env()) as proc:
while proc.poll() is None: while proc.poll() is None:
img = disp.grab(autocrop=False) img = disp.grab(autocrop=False)
if img is None: if img is None:
continue continue
if brightness != 1.0:
darkener = ImageEnhance.Brightness(img)
img = darkener.enhance(brightness)
img = img.resize((width, height)) img = img.resize((width, height))
framebuffer[:, :] = np.array(img) framebuffer[:, :] = np.array(img)
matrix.show() matrix.show()

View file

@ -20,7 +20,7 @@ This example command will mirror a 128x128 pixel square from the top left of the
import click import click
import numpy as np import numpy as np
from PIL import Image, ImageGrab from PIL import Image, ImageEnhance, ImageGrab
import adafruit_blinka_raspberry_pi5_piomatter as piomatter import adafruit_blinka_raspberry_pi5_piomatter as piomatter
import adafruit_blinka_raspberry_pi5_piomatter.click as piomatter_click import adafruit_blinka_raspberry_pi5_piomatter.click as piomatter_click
@ -38,11 +38,13 @@ RESAMPLE_MAP = {
@click.option("--mirror-region", help="Region of X display to mirror. Comma seperated x,y,w,h. " @click.option("--mirror-region", help="Region of X display to mirror. Comma seperated x,y,w,h. "
"Default will mirror entire display.", default="") "Default will mirror entire display.", default="")
@click.option("--x-display", help="The X display to mirror. Default is :0", default=":0") @click.option("--x-display", help="The X display to mirror. Default is :0", default=":0")
@click.option("--brightness", help="The brightness factor of the image output to the matrix",
default=1.0, type=click.FloatRange(min=0.1, max=1.0))
@click.option("--resample-method", type=click.Choice(RESAMPLE_MAP), default="nearest", @click.option("--resample-method", type=click.Choice(RESAMPLE_MAP), default="nearest",
help="The resample method for PIL to use when resizing the screen image. Default is nearest") help="The resample method for PIL to use when resizing the screen image. Default is nearest")
@piomatter_click.standard_options(n_lanes=2, n_temporal_planes=0) @piomatter_click.standard_options(n_lanes=2, n_temporal_planes=0)
def main(width, height, serpentine, rotation, pinout, n_planes, def main(width, height, serpentine, rotation, pinout, n_planes,
n_temporal_planes, n_addr_lines, n_lanes, mirror_region, x_display, resample_method): n_temporal_planes, n_addr_lines, n_lanes, mirror_region, x_display, resample_method, brightness):
if n_lanes != 2: if n_lanes != 2:
pixelmap = simple_multilane_mapper(width, height, n_addr_lines, n_lanes) pixelmap = simple_multilane_mapper(width, height, n_addr_lines, n_lanes)
@ -66,14 +68,16 @@ def main(width, height, serpentine, rotation, pinout, n_planes,
while True: while True:
img = ImageGrab.grab(xdisplay=x_display) img = ImageGrab.grab(xdisplay=x_display)
if mirror_region is not None: if mirror_region is not None:
img = img.crop((mirror_region[0], mirror_region[1], # left,top img = img.crop((mirror_region[0], mirror_region[1], # left,top
mirror_region[0] + mirror_region[2], # right mirror_region[0] + mirror_region[2], # right
mirror_region[1] + mirror_region[3])) # bottom mirror_region[1] + mirror_region[3])) # bottom
if brightness != 1.0:
darkener = ImageEnhance.Brightness(img)
img = darkener.enhance(brightness)
img = img.resize((width, height), RESAMPLE_MAP[resample_method]) img = img.resize((width, height), RESAMPLE_MAP[resample_method])
framebuffer[:, :] = np.array(img) framebuffer[:, :] = np.array(img)
matrix.show() matrix.show()
if __name__ == '__main__': if __name__ == '__main__':
main() main()

20
src/CMakeLists.txt Normal file
View file

@ -0,0 +1,20 @@
cmake_minimum_required(VERSION 3.12)
project(protodemo C CXX)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 20)
add_compile_options(-Wall -g3 -Og)
add_executable(protodemo
protodemo.cpp
piolib/piolib.c
piolib/pio_rp1.c
)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/protomatter.pio.h
COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/assemble.py ${CMAKE_CURRENT_SOURCE_DIR}/protomatter.pio ${CMAKE_CURRENT_BINARY_DIR}/protomatter.pio.h
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/assemble.py ${CMAKE_CURRENT_SOURCE_DIR}/protomatter.pio
)
target_include_directories(protodemo PRIVATE include piolib/include)

View file

@ -1,7 +0,0 @@
protodemo: protodemo.c piolib/*.c include/piomatter/*.h include/piomatter/protomatter.pio.h Makefile
g++ -std=c++20 -O3 -ggdb -x c++ -Iinclude -Ipiolib/include -o $@ $(filter %.c, $^) -Wno-narrowing
matrixmap.h:
include/piomatter/protomatter.pio.h: protomatter.pio assemble.py
python assemble.py $< $@

View file

@ -27,8 +27,8 @@ class _PybindEnumChoice(click.Choice):
return r return r
def _validate_temporal_planes(ctx, param, value): def _validate_temporal_planes(ctx, param, value):
if value not in (0, 2, 4): if value not in (0, 1, 2, 3, 4, 5):
raise click.BadParameter("must be 0, 2, or 4") raise click.BadParameter("must be from 0 to 5 (0 and 1 both disable temporal planes)")
return value return value
def standard_options( def standard_options(

View file

@ -134,47 +134,27 @@ schedule_sequence make_temporal_dither_schedule(int n_planes,
if (n_temporal_planes >= n_planes) { if (n_temporal_planes >= n_planes) {
throw std::range_error("n_temporal_planes can't exceed n_planes"); throw std::range_error("n_temporal_planes can't exceed n_planes");
} }
if (n_temporal_planes != 2 && n_temporal_planes != 4) {
// the code can generate a schedule for 8 temporal planes, but it
// flickers intolerably
throw std::range_error("n_temporal_planes must be 0, 1, 2, or 4");
}
int n_real_planes = n_planes - n_temporal_planes; int n_real_planes = n_planes - n_temporal_planes;
schedule base_sched;
for (int j = 0; j < n_real_planes; j++) {
base_sched.emplace_back(
9 - j, (1 << (n_temporal_planes + n_real_planes - j - 1)) /
n_temporal_planes);
}
schedule_sequence result; schedule_sequence result;
auto add_sched = [&result, &base_sched](int plane, int count) { auto add_sched = [&result, n_real_planes,
auto sched = base_sched; n_temporal_planes](int i, int plane, int count) {
schedule sched;
for (int j = 0; j < n_real_planes; j++) {
int k = 1 << (n_temporal_planes + n_real_planes - j - 1);
sched.emplace_back(9 - j, (k + i) / n_temporal_planes);
}
sched.emplace_back(9 - plane, count); sched.emplace_back(9 - plane, count);
result.emplace_back(sched); result.emplace_back(sched);
}; };
for (int i = 0; i < n_temporal_planes; i++) { for (int i = 0; i < n_temporal_planes; i++) {
add_sched(n_real_planes + i, 1 << (n_temporal_planes - i - 1)); add_sched(i, n_real_planes + i, 1 << (n_temporal_planes - i - 1));
} }
#if 0
std::vector<uint32_t> counts(10, 0);
for (auto s : result) {
for(auto t: s) {
counts[t.shift] += t.active_time;
}
}
for (auto s : counts) {
printf("%d ", s);
}
printf("\n");
#endif
return rescale_schedule(result, pixels_across); return rescale_schedule(result, pixels_across);
;
} }
struct matrix_geometry { struct matrix_geometry {

View file

@ -19,7 +19,7 @@ struct adafruit_matrix_bonnet_pinout {
static constexpr uint32_t post_oe_delay = 0; static constexpr uint32_t post_oe_delay = 0;
static constexpr uint32_t post_latch_delay = 0; static constexpr uint32_t post_latch_delay = 0;
static constexpr uint32_t post_addr_delay = 500; static constexpr uint32_t post_addr_delay = 5;
}; };
struct adafruit_matrix_bonnet_pinout_bgr { struct adafruit_matrix_bonnet_pinout_bgr {
@ -37,7 +37,7 @@ struct adafruit_matrix_bonnet_pinout_bgr {
static constexpr uint32_t post_oe_delay = 0; static constexpr uint32_t post_oe_delay = 0;
static constexpr uint32_t post_latch_delay = 0; static constexpr uint32_t post_latch_delay = 0;
static constexpr uint32_t post_addr_delay = 500; static constexpr uint32_t post_addr_delay = 5;
}; };
struct active3_pinout { struct active3_pinout {
@ -56,7 +56,7 @@ struct active3_pinout {
static constexpr uint32_t post_oe_delay = 0; static constexpr uint32_t post_oe_delay = 0;
static constexpr uint32_t post_latch_delay = 0; static constexpr uint32_t post_latch_delay = 0;
static constexpr uint32_t post_addr_delay = 500; static constexpr uint32_t post_addr_delay = 5;
}; };
struct active3_pinout_bgr { struct active3_pinout_bgr {
@ -75,7 +75,7 @@ struct active3_pinout_bgr {
static constexpr uint32_t post_oe_delay = 0; static constexpr uint32_t post_oe_delay = 0;
static constexpr uint32_t post_latch_delay = 0; static constexpr uint32_t post_latch_delay = 0;
static constexpr uint32_t post_addr_delay = 500; static constexpr uint32_t post_addr_delay = 5;
}; };
} // namespace piomatter } // namespace piomatter

View file

@ -20,20 +20,6 @@ static uint64_t monotonicns64() {
constexpr size_t MAX_XFER = 65532; constexpr size_t MAX_XFER = 65532;
void pio_sm_xfer_data_large(PIO pio, int sm, int direction, size_t size,
uint32_t *databuf) {
while (size) {
size_t xfersize = std::min(size_t{MAX_XFER}, size);
int r = pio_sm_xfer_data(pio, sm, direction, xfersize, databuf);
if (r) {
throw std::runtime_error(
"pio_sm_xfer_data (reboot may be required)");
}
size -= xfersize;
databuf += xfersize / sizeof(*databuf);
}
}
struct piomatter_base { struct piomatter_base {
piomatter_base() {} piomatter_base() {}
piomatter_base(const piomatter_base &) = delete; piomatter_base(const piomatter_base &) = delete;
@ -106,7 +92,7 @@ struct piomatter : piomatter_base {
if (sm < 0) { if (sm < 0) {
throw std::runtime_error("pio_claim_unused_sm"); throw std::runtime_error("pio_claim_unused_sm");
} }
int r = pio_sm_config_xfer(pio, sm, PIO_DIR_TO_SM, MAX_XFER, 2); int r = pio_sm_config_xfer(pio, sm, PIO_DIR_TO_SM, MAX_XFER, 3);
if (r) { if (r) {
throw std::runtime_error("pio_sm_config_xfer"); throw std::runtime_error("pio_sm_config_xfer");
} }
@ -188,8 +174,7 @@ struct piomatter : piomatter_base {
const auto &data = cur_buf[seq_idx]; const auto &data = cur_buf[seq_idx];
auto datasize = sizeof(uint32_t) * data.size(); auto datasize = sizeof(uint32_t) * data.size();
auto dataptr = const_cast<uint32_t *>(&data[0]); auto dataptr = const_cast<uint32_t *>(&data[0]);
pio_sm_xfer_data_large(pio, sm, PIO_DIR_TO_SM, datasize, pio_sm_xfer_data(pio, sm, PIO_DIR_TO_SM, datasize, dataptr);
dataptr);
t1 = monotonicns64(); t1 = monotonicns64();
if (t0 != t1) { if (t0 != t1) {
fps = 1e9 / (t1 - t0); fps = 1e9 / (t1 - t0);

View file

@ -8,16 +8,16 @@
#define _HARDWARE_CLOCKS_H #define _HARDWARE_CLOCKS_H
enum clock_index { enum clock_index {
clk_gpout0 = 0, ///< GPIO Muxing 0 clk_gpout0 = 0, ///< GPIO Muxing 0
clk_gpout1, ///< GPIO Muxing 1 clk_gpout1, ///< GPIO Muxing 1
clk_gpout2, ///< GPIO Muxing 2 clk_gpout2, ///< GPIO Muxing 2
clk_gpout3, ///< GPIO Muxing 3 clk_gpout3, ///< GPIO Muxing 3
clk_ref, ///< Watchdog and timers reference clock clk_ref, ///< Watchdog and timers reference clock
clk_sys, ///< Processors, bus fabric, memory, memory mapped registers clk_sys, ///< Processors, bus fabric, memory, memory mapped registers
clk_peri, ///< Peripheral clock for UART and SPI clk_peri, ///< Peripheral clock for UART and SPI
clk_usb, ///< USB clock clk_usb, ///< USB clock
clk_adc, ///< ADC clock clk_adc, ///< ADC clock
clk_rtc, ///< Real time clock clk_rtc, ///< Real time clock
CLK_COUNT CLK_COUNT
}; };

View file

@ -39,16 +39,14 @@ enum gpio_irq_level {
}; };
enum gpio_override { enum gpio_override {
GPIO_OVERRIDE_NORMAL = GPIO_OVERRIDE_NORMAL = 0, ///< peripheral signal selected via \ref gpio_set_function
0, ///< peripheral signal selected via \ref gpio_set_function GPIO_OVERRIDE_INVERT = 1, ///< invert peripheral signal selected via \ref gpio_set_function
GPIO_OVERRIDE_INVERT = GPIO_OVERRIDE_LOW = 2, ///< drive low/disable output
1, ///< invert peripheral signal selected via \ref gpio_set_function GPIO_OVERRIDE_HIGH = 3, ///< drive high/enable output
GPIO_OVERRIDE_LOW = 2, ///< drive low/disable output
GPIO_OVERRIDE_HIGH = 3, ///< drive high/enable output
}; };
enum gpio_slew_rate { enum gpio_slew_rate {
GPIO_SLEW_RATE_SLOW = 0, ///< Slew rate limiting enabled GPIO_SLEW_RATE_SLOW = 0, ///< Slew rate limiting enabled
GPIO_SLEW_RATE_FAST = 1 ///< Slew rate limiting disabled GPIO_SLEW_RATE_FAST = 1 ///< Slew rate limiting disabled
}; };
enum gpio_drive_strength { enum gpio_drive_strength {

View file

@ -13,17 +13,14 @@
* \defgroup pio_instructions pio_instructions * \defgroup pio_instructions pio_instructions
* \ingroup hardware_pio * \ingroup hardware_pio
* *
* Functions for generating PIO instruction encodings programmatically. In debug * Functions for generating PIO instruction encodings programmatically. In debug builds
*builds `PARAM_ASSERTIONS_ENABLED_PIO_INSTRUCTIONS` can be set to 1 to enable *`PARAM_ASSERTIONS_ENABLED_PIO_INSTRUCTIONS` can be set to 1 to enable validation of encoding function
*validation of encoding function parameters. * parameters.
* *
* For fuller descriptions of the instructions in question see the "RP2040 * For fuller descriptions of the instructions in question see the "RP2040 Datasheet"
*Datasheet"
*/ */
// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_PIO_INSTRUCTIONS, Enable/disable // PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_PIO_INSTRUCTIONS, Enable/disable assertions in the PIO instructions, type=bool, default=0, group=pio_instructions
// assertions in the PIO instructions, type=bool, default=0,
// group=pio_instructions
#ifndef PARAM_ASSERTIONS_ENABLED_PIO_INSTRUCTIONS #ifndef PARAM_ASSERTIONS_ENABLED_PIO_INSTRUCTIONS
#define PARAM_ASSERTIONS_ENABLED_PIO_INSTRUCTIONS 0 #define PARAM_ASSERTIONS_ENABLED_PIO_INSTRUCTIONS 0
#endif #endif
@ -45,48 +42,44 @@ enum pio_instr_bits {
}; };
#ifndef NDEBUG #ifndef NDEBUG
#define _PIO_INVALID_IN_SRC 0x08u #define _PIO_INVALID_IN_SRC 0x08u
#define _PIO_INVALID_OUT_DEST 0x10u #define _PIO_INVALID_OUT_DEST 0x10u
#define _PIO_INVALID_SET_DEST 0x20u #define _PIO_INVALID_SET_DEST 0x20u
#define _PIO_INVALID_MOV_SRC 0x40u #define _PIO_INVALID_MOV_SRC 0x40u
#define _PIO_INVALID_MOV_DEST 0x80u #define _PIO_INVALID_MOV_DEST 0x80u
#else #else
#define _PIO_INVALID_IN_SRC 0u #define _PIO_INVALID_IN_SRC 0u
#define _PIO_INVALID_OUT_DEST 0u #define _PIO_INVALID_OUT_DEST 0u
#define _PIO_INVALID_SET_DEST 0u #define _PIO_INVALID_SET_DEST 0u
#define _PIO_INVALID_MOV_SRC 0u #define _PIO_INVALID_MOV_SRC 0u
#define _PIO_INVALID_MOV_DEST 0u #define _PIO_INVALID_MOV_DEST 0u
#endif #endif
/*! \brief Enumeration of values to pass for source/destination args for /*! \brief Enumeration of values to pass for source/destination args for instruction encoding functions
* instruction encoding functions \ingroup pio_instructions * \ingroup pio_instructions
* *
* \note Not all values are suitable for all functions. Validity is only checked * \note Not all values are suitable for all functions. Validity is only checked in debug mode when
* in debug mode when `PARAM_ASSERTIONS_ENABLED_PIO_INSTRUCTIONS` is 1 * `PARAM_ASSERTIONS_ENABLED_PIO_INSTRUCTIONS` is 1
*/ */
enum pio_src_dest { enum pio_src_dest {
pio_pins = 0u, pio_pins = 0u,
pio_x = 1u, pio_x = 1u,
pio_y = 2u, pio_y = 2u,
pio_null = 3u | _PIO_INVALID_SET_DEST | _PIO_INVALID_MOV_DEST, pio_null = 3u | _PIO_INVALID_SET_DEST | _PIO_INVALID_MOV_DEST,
pio_pindirs = pio_pindirs = 4u | _PIO_INVALID_IN_SRC | _PIO_INVALID_MOV_SRC | _PIO_INVALID_MOV_DEST,
4u | _PIO_INVALID_IN_SRC | _PIO_INVALID_MOV_SRC | _PIO_INVALID_MOV_DEST, pio_exec_mov = 4u | _PIO_INVALID_IN_SRC | _PIO_INVALID_OUT_DEST | _PIO_INVALID_SET_DEST | _PIO_INVALID_MOV_SRC,
pio_exec_mov = 4u | _PIO_INVALID_IN_SRC | _PIO_INVALID_OUT_DEST | pio_status = 5u | _PIO_INVALID_IN_SRC | _PIO_INVALID_OUT_DEST | _PIO_INVALID_SET_DEST | _PIO_INVALID_MOV_DEST,
_PIO_INVALID_SET_DEST | _PIO_INVALID_MOV_SRC, pio_pc = 5u | _PIO_INVALID_IN_SRC | _PIO_INVALID_SET_DEST | _PIO_INVALID_MOV_SRC,
pio_status = 5u | _PIO_INVALID_IN_SRC | _PIO_INVALID_OUT_DEST |
_PIO_INVALID_SET_DEST | _PIO_INVALID_MOV_DEST,
pio_pc =
5u | _PIO_INVALID_IN_SRC | _PIO_INVALID_SET_DEST | _PIO_INVALID_MOV_SRC,
pio_isr = 6u | _PIO_INVALID_SET_DEST, pio_isr = 6u | _PIO_INVALID_SET_DEST,
pio_osr = 7u | _PIO_INVALID_OUT_DEST | _PIO_INVALID_SET_DEST, pio_osr = 7u | _PIO_INVALID_OUT_DEST | _PIO_INVALID_SET_DEST,
pio_exec_out = 7u | _PIO_INVALID_IN_SRC | _PIO_INVALID_SET_DEST | pio_exec_out = 7u | _PIO_INVALID_IN_SRC | _PIO_INVALID_SET_DEST | _PIO_INVALID_MOV_SRC | _PIO_INVALID_MOV_DEST,
_PIO_INVALID_MOV_SRC | _PIO_INVALID_MOV_DEST,
}; };
static inline uint _pio_major_instr_bits(uint instr) { return instr & 0xe000u; } static inline uint _pio_major_instr_bits(uint instr) {
return instr & 0xe000u;
}
static inline uint _pio_encode_instr_and_args(enum pio_instr_bits instr_bits, static inline uint _pio_encode_instr_and_args(enum pio_instr_bits instr_bits, uint arg1, uint arg2) {
uint arg1, uint arg2) {
valid_params_if(PIO_INSTRUCTIONS, arg1 <= 0x7); valid_params_if(PIO_INSTRUCTIONS, arg1 <= 0x7);
#if PARAM_ASSERTIONS_ENABLED(PIO_INSTRUCTIONS) #if PARAM_ASSERTIONS_ENABLED(PIO_INSTRUCTIONS)
uint32_t major = _pio_major_instr_bits(instr_bits); uint32_t major = _pio_major_instr_bits(instr_bits);
@ -99,21 +92,17 @@ static inline uint _pio_encode_instr_and_args(enum pio_instr_bits instr_bits,
return instr_bits | (arg1 << 5u) | (arg2 & 0x1fu); return instr_bits | (arg1 << 5u) | (arg2 & 0x1fu);
} }
static inline uint static inline uint _pio_encode_instr_and_src_dest(enum pio_instr_bits instr_bits, enum pio_src_dest dest, uint value) {
_pio_encode_instr_and_src_dest(enum pio_instr_bits instr_bits,
enum pio_src_dest dest, uint value) {
return _pio_encode_instr_and_args(instr_bits, dest & 7u, value); return _pio_encode_instr_and_args(instr_bits, dest & 7u, value);
} }
/*! \brief Encode just the delay slot bits of an instruction /*! \brief Encode just the delay slot bits of an instruction
* \ingroup pio_instructions * \ingroup pio_instructions
* *
* \note This function does not return a valid instruction encoding; instead it * \note This function does not return a valid instruction encoding; instead it returns an encoding of the delay
* returns an encoding of the delay slot suitable for `OR`ing with the result of * slot suitable for `OR`ing with the result of an encoding function for an actual instruction. Care should be taken when
* an encoding function for an actual instruction. Care should be taken when * combining the results of this function with the results of \ref pio_encode_sideset and \ref pio_encode_sideset_opt
* combining the results of this function with the results of \ref * as they share the same bits within the instruction encoding.
* pio_encode_sideset and \ref pio_encode_sideset_opt as they share the same
* bits within the instruction encoding.
* *
* \param cycles the number of cycles 0-31 (or less if side set is being used) * \param cycles the number of cycles 0-31 (or less if side set is being used)
* \return the delay slot bits to be ORed with an instruction encoding * \return the delay slot bits to be ORed with an instruction encoding
@ -124,42 +113,38 @@ static inline uint pio_encode_delay(uint cycles) {
return cycles << 8u; return cycles << 8u;
} }
/*! \brief Encode just the side set bits of an instruction (in non optional side /*! \brief Encode just the side set bits of an instruction (in non optional side set mode)
* set mode) \ingroup pio_instructions * \ingroup pio_instructions
* *
* \note This function does not return a valid instruction encoding; instead it * \note This function does not return a valid instruction encoding; instead it returns an encoding of the side set bits
* returns an encoding of the side set bits suitable for `OR`ing with the result * suitable for `OR`ing with the result of an encoding function for an actual instruction. Care should be taken when
* of an encoding function for an actual instruction. Care should be taken when * combining the results of this function with the results of \ref pio_encode_delay as they share the same bits
* combining the results of this function with the results of \ref * within the instruction encoding.
* pio_encode_delay as they share the same bits within the instruction encoding.
* *
* \param sideset_bit_count number of side set bits as would be specified via * \param sideset_bit_count number of side set bits as would be specified via `.sideset` in pioasm
* `.sideset` in pioasm \param value the value to sideset on the pins \return * \param value the value to sideset on the pins
* the side set bits to be ORed with an instruction encoding * \return the side set bits to be ORed with an instruction encoding
*/ */
static inline uint pio_encode_sideset(uint sideset_bit_count, uint value) { static inline uint pio_encode_sideset(uint sideset_bit_count, uint value) {
valid_params_if(PIO_INSTRUCTIONS, valid_params_if(PIO_INSTRUCTIONS, sideset_bit_count >= 1 && sideset_bit_count <= 5);
sideset_bit_count >= 1 && sideset_bit_count <= 5);
valid_params_if(PIO_INSTRUCTIONS, value <= ((1u << sideset_bit_count) - 1)); valid_params_if(PIO_INSTRUCTIONS, value <= ((1u << sideset_bit_count) - 1));
return value << (13u - sideset_bit_count); return value << (13u - sideset_bit_count);
} }
/*! \brief Encode just the side set bits of an instruction (in optional -`opt` /*! \brief Encode just the side set bits of an instruction (in optional -`opt` side set mode)
* side set mode) \ingroup pio_instructions * \ingroup pio_instructions
* *
* \note This function does not return a valid instruction encoding; instead it * \note This function does not return a valid instruction encoding; instead it returns an encoding of the side set bits
* returns an encoding of the side set bits suitable for `OR`ing with the result * suitable for `OR`ing with the result of an encoding function for an actual instruction. Care should be taken when
* of an encoding function for an actual instruction. Care should be taken when * combining the results of this function with the results of \ref pio_encode_delay as they share the same bits
* combining the results of this function with the results of \ref * within the instruction encoding.
* pio_encode_delay as they share the same bits within the instruction encoding.
* *
* \param sideset_bit_count number of side set bits as would be specified via * \param sideset_bit_count number of side set bits as would be specified via `.sideset <n> opt` in pioasm
* `.sideset <n> opt` in pioasm \param value the value to sideset on the pins * \param value the value to sideset on the pins
* \return the side set bits to be ORed with an instruction encoding * \return the side set bits to be ORed with an instruction encoding
*/ */
static inline uint pio_encode_sideset_opt(uint sideset_bit_count, uint value) { static inline uint pio_encode_sideset_opt(uint sideset_bit_count, uint value) {
valid_params_if(PIO_INSTRUCTIONS, valid_params_if(PIO_INSTRUCTIONS, sideset_bit_count >= 1 && sideset_bit_count <= 4);
sideset_bit_count >= 1 && sideset_bit_count <= 4);
valid_params_if(PIO_INSTRUCTIONS, value <= ((1u << sideset_bit_count) - 1)); valid_params_if(PIO_INSTRUCTIONS, value <= ((1u << sideset_bit_count) - 1));
return 0x1000u | value << (12u - sideset_bit_count); return 0x1000u | value << (12u - sideset_bit_count);
} }
@ -169,9 +154,9 @@ static inline uint pio_encode_sideset_opt(uint sideset_bit_count, uint value) {
* *
* This is the equivalent of `JMP <addr>` * This is the equivalent of `JMP <addr>`
* *
* \param addr The target address 0-31 (an absolute address within the PIO * \param addr The target address 0-31 (an absolute address within the PIO instruction memory)
* instruction memory) \return The instruction encoding with 0 delay and no side * \return The instruction encoding with 0 delay and no side set value
* set value \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
*/ */
static inline uint pio_encode_jmp(uint addr) { static inline uint pio_encode_jmp(uint addr) {
return _pio_encode_instr_and_args(pio_instr_bits_jmp, 0, addr); return _pio_encode_instr_and_args(pio_instr_bits_jmp, 0, addr);
@ -182,22 +167,22 @@ static inline uint pio_encode_jmp(uint addr) {
* *
* This is the equivalent of `JMP !X <addr>` * This is the equivalent of `JMP !X <addr>`
* *
* \param addr The target address 0-31 (an absolute address within the PIO * \param addr The target address 0-31 (an absolute address within the PIO instruction memory)
* instruction memory) \return The instruction encoding with 0 delay and no side * \return The instruction encoding with 0 delay and no side set value
* set value \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
*/ */
static inline uint pio_encode_jmp_not_x(uint addr) { static inline uint pio_encode_jmp_not_x(uint addr) {
return _pio_encode_instr_and_args(pio_instr_bits_jmp, 1, addr); return _pio_encode_instr_and_args(pio_instr_bits_jmp, 1, addr);
} }
/*! \brief Encode a conditional JMP if scratch X non-zero (and post-decrement X) /*! \brief Encode a conditional JMP if scratch X non-zero (and post-decrement X) instruction
* instruction \ingroup pio_instructions * \ingroup pio_instructions
* *
* This is the equivalent of `JMP X-- <addr>` * This is the equivalent of `JMP X-- <addr>`
* *
* \param addr The target address 0-31 (an absolute address within the PIO * \param addr The target address 0-31 (an absolute address within the PIO instruction memory)
* instruction memory) \return The instruction encoding with 0 delay and no side * \return The instruction encoding with 0 delay and no side set value
* set value \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
*/ */
static inline uint pio_encode_jmp_x_dec(uint addr) { static inline uint pio_encode_jmp_x_dec(uint addr) {
return _pio_encode_instr_and_args(pio_instr_bits_jmp, 2, addr); return _pio_encode_instr_and_args(pio_instr_bits_jmp, 2, addr);
@ -208,22 +193,22 @@ static inline uint pio_encode_jmp_x_dec(uint addr) {
* *
* This is the equivalent of `JMP !Y <addr>` * This is the equivalent of `JMP !Y <addr>`
* *
* \param addr The target address 0-31 (an absolute address within the PIO * \param addr The target address 0-31 (an absolute address within the PIO instruction memory)
* instruction memory) \return The instruction encoding with 0 delay and no side * \return The instruction encoding with 0 delay and no side set value
* set value \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
*/ */
static inline uint pio_encode_jmp_not_y(uint addr) { static inline uint pio_encode_jmp_not_y(uint addr) {
return _pio_encode_instr_and_args(pio_instr_bits_jmp, 3, addr); return _pio_encode_instr_and_args(pio_instr_bits_jmp, 3, addr);
} }
/*! \brief Encode a conditional JMP if scratch Y non-zero (and post-decrement Y) /*! \brief Encode a conditional JMP if scratch Y non-zero (and post-decrement Y) instruction
* instruction \ingroup pio_instructions * \ingroup pio_instructions
* *
* This is the equivalent of `JMP Y-- <addr>` * This is the equivalent of `JMP Y-- <addr>`
* *
* \param addr The target address 0-31 (an absolute address within the PIO * \param addr The target address 0-31 (an absolute address within the PIO instruction memory)
* instruction memory) \return The instruction encoding with 0 delay and no side * \return The instruction encoding with 0 delay and no side set value
* set value \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
*/ */
static inline uint pio_encode_jmp_y_dec(uint addr) { static inline uint pio_encode_jmp_y_dec(uint addr) {
return _pio_encode_instr_and_args(pio_instr_bits_jmp, 4, addr); return _pio_encode_instr_and_args(pio_instr_bits_jmp, 4, addr);
@ -234,9 +219,9 @@ static inline uint pio_encode_jmp_y_dec(uint addr) {
* *
* This is the equivalent of `JMP X!=Y <addr>` * This is the equivalent of `JMP X!=Y <addr>`
* *
* \param addr The target address 0-31 (an absolute address within the PIO * \param addr The target address 0-31 (an absolute address within the PIO instruction memory)
* instruction memory) \return The instruction encoding with 0 delay and no side * \return The instruction encoding with 0 delay and no side set value
* set value \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
*/ */
static inline uint pio_encode_jmp_x_ne_y(uint addr) { static inline uint pio_encode_jmp_x_ne_y(uint addr) {
return _pio_encode_instr_and_args(pio_instr_bits_jmp, 5, addr); return _pio_encode_instr_and_args(pio_instr_bits_jmp, 5, addr);
@ -247,22 +232,22 @@ static inline uint pio_encode_jmp_x_ne_y(uint addr) {
* *
* This is the equivalent of `JMP PIN <addr>` * This is the equivalent of `JMP PIN <addr>`
* *
* \param addr The target address 0-31 (an absolute address within the PIO * \param addr The target address 0-31 (an absolute address within the PIO instruction memory)
* instruction memory) \return The instruction encoding with 0 delay and no side * \return The instruction encoding with 0 delay and no side set value
* set value \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
*/ */
static inline uint pio_encode_jmp_pin(uint addr) { static inline uint pio_encode_jmp_pin(uint addr) {
return _pio_encode_instr_and_args(pio_instr_bits_jmp, 6, addr); return _pio_encode_instr_and_args(pio_instr_bits_jmp, 6, addr);
} }
/*! \brief Encode a conditional JMP if output shift register not empty /*! \brief Encode a conditional JMP if output shift register not empty instruction
* instruction \ingroup pio_instructions * \ingroup pio_instructions
* *
* This is the equivalent of `JMP !OSRE <addr>` * This is the equivalent of `JMP !OSRE <addr>`
* *
* \param addr The target address 0-31 (an absolute address within the PIO * \param addr The target address 0-31 (an absolute address within the PIO instruction memory)
* instruction memory) \return The instruction encoding with 0 delay and no side * \return The instruction encoding with 0 delay and no side set value
* set value \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
*/ */
static inline uint pio_encode_jmp_not_osre(uint addr) { static inline uint pio_encode_jmp_not_osre(uint addr) {
return _pio_encode_instr_and_args(pio_instr_bits_jmp, 7, addr); return _pio_encode_instr_and_args(pio_instr_bits_jmp, 7, addr);
@ -284,8 +269,7 @@ static inline uint _pio_encode_irq(bool relative, uint irq) {
* \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
*/ */
static inline uint pio_encode_wait_gpio(bool polarity, uint gpio) { static inline uint pio_encode_wait_gpio(bool polarity, uint gpio) {
return _pio_encode_instr_and_args(pio_instr_bits_wait, return _pio_encode_instr_and_args(pio_instr_bits_wait, 0u | (polarity ? 4u : 0u), gpio);
0u | (polarity ? 4u : 0u), gpio);
} }
/*! \brief Encode a WAIT for pin instruction /*! \brief Encode a WAIT for pin instruction
@ -294,13 +278,12 @@ static inline uint pio_encode_wait_gpio(bool polarity, uint gpio) {
* This is the equivalent of `WAIT <polarity> PIN <pin>` * This is the equivalent of `WAIT <polarity> PIN <pin>`
* *
* \param polarity true for `WAIT 1`, false for `WAIT 0` * \param polarity true for `WAIT 1`, false for `WAIT 0`
* \param pin The pin number 0-31 relative to the executing SM's input pin * \param pin The pin number 0-31 relative to the executing SM's input pin mapping
* mapping \return The instruction encoding with 0 delay and no side set value * \return The instruction encoding with 0 delay and no side set value
* \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
*/ */
static inline uint pio_encode_wait_pin(bool polarity, uint pin) { static inline uint pio_encode_wait_pin(bool polarity, uint pin) {
return _pio_encode_instr_and_args(pio_instr_bits_wait, return _pio_encode_instr_and_args(pio_instr_bits_wait, 1u | (polarity ? 4u : 0u), pin);
1u | (polarity ? 4u : 0u), pin);
} }
/*! \brief Encode a WAIT for IRQ instruction /*! \brief Encode a WAIT for IRQ instruction
@ -309,16 +292,14 @@ static inline uint pio_encode_wait_pin(bool polarity, uint pin) {
* This is the equivalent of `WAIT <polarity> IRQ <irq> <relative>` * This is the equivalent of `WAIT <polarity> IRQ <irq> <relative>`
* *
* \param polarity true for `WAIT 1`, false for `WAIT 0` * \param polarity true for `WAIT 1`, false for `WAIT 0`
* \param relative true for a `WAIT IRQ <irq> REL`, false for regular `WAIT IRQ * \param relative true for a `WAIT IRQ <irq> REL`, false for regular `WAIT IRQ <irq>`
* <irq>` \param irq the irq number 0-7 \return The instruction encoding with 0 * \param irq the irq number 0-7
* delay and no side set value \see pio_encode_delay, pio_encode_sideset, * \return The instruction encoding with 0 delay and no side set value
* pio_encode_sideset_opt * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
*/ */
static inline uint pio_encode_wait_irq(bool polarity, bool relative, uint irq) { static inline uint pio_encode_wait_irq(bool polarity, bool relative, uint irq) {
valid_params_if(PIO_INSTRUCTIONS, irq <= 7); valid_params_if(PIO_INSTRUCTIONS, irq <= 7);
return _pio_encode_instr_and_args(pio_instr_bits_wait, return _pio_encode_instr_and_args(pio_instr_bits_wait, 2u | (polarity ? 4u : 0u), _pio_encode_irq(relative, irq));
2u | (polarity ? 4u : 0u),
_pio_encode_irq(relative, irq));
} }
/*! \brief Encode an IN instruction /*! \brief Encode an IN instruction
@ -362,8 +343,7 @@ static inline uint pio_encode_out(enum pio_src_dest dest, uint count) {
* \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
*/ */
static inline uint pio_encode_push(bool if_full, bool block) { static inline uint pio_encode_push(bool if_full, bool block) {
return _pio_encode_instr_and_args( return _pio_encode_instr_and_args(pio_instr_bits_push, (if_full ? 2u : 0u) | (block ? 1u : 0u), 0);
pio_instr_bits_push, (if_full ? 2u : 0u) | (block ? 1u : 0u), 0);
} }
/*! \brief Encode a PULL instruction /*! \brief Encode a PULL instruction
@ -377,8 +357,7 @@ static inline uint pio_encode_push(bool if_full, bool block) {
* \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
*/ */
static inline uint pio_encode_pull(bool if_empty, bool block) { static inline uint pio_encode_pull(bool if_empty, bool block) {
return _pio_encode_instr_and_args( return _pio_encode_instr_and_args(pio_instr_bits_pull, (if_empty ? 2u : 0u) | (block ? 1u : 0u), 0);
pio_instr_bits_pull, (if_empty ? 2u : 0u) | (block ? 1u : 0u), 0);
} }
/*! \brief Encode a MOV instruction /*! \brief Encode a MOV instruction
@ -391,8 +370,7 @@ static inline uint pio_encode_pull(bool if_empty, bool block) {
* \return The instruction encoding with 0 delay and no side set value * \return The instruction encoding with 0 delay and no side set value
* \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
*/ */
static inline uint pio_encode_mov(enum pio_src_dest dest, static inline uint pio_encode_mov(enum pio_src_dest dest, enum pio_src_dest src) {
enum pio_src_dest src) {
valid_params_if(PIO_INSTRUCTIONS, !(dest & _PIO_INVALID_MOV_DEST)); valid_params_if(PIO_INSTRUCTIONS, !(dest & _PIO_INVALID_MOV_DEST));
valid_params_if(PIO_INSTRUCTIONS, !(src & _PIO_INVALID_MOV_SRC)); valid_params_if(PIO_INSTRUCTIONS, !(src & _PIO_INVALID_MOV_SRC));
return _pio_encode_instr_and_src_dest(pio_instr_bits_mov, dest, src & 7u); return _pio_encode_instr_and_src_dest(pio_instr_bits_mov, dest, src & 7u);
@ -408,12 +386,10 @@ static inline uint pio_encode_mov(enum pio_src_dest dest,
* \return The instruction encoding with 0 delay and no side set value * \return The instruction encoding with 0 delay and no side set value
* \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
*/ */
static inline uint pio_encode_mov_not(enum pio_src_dest dest, static inline uint pio_encode_mov_not(enum pio_src_dest dest, enum pio_src_dest src) {
enum pio_src_dest src) {
valid_params_if(PIO_INSTRUCTIONS, !(dest & _PIO_INVALID_MOV_DEST)); valid_params_if(PIO_INSTRUCTIONS, !(dest & _PIO_INVALID_MOV_DEST));
valid_params_if(PIO_INSTRUCTIONS, !(src & _PIO_INVALID_MOV_SRC)); valid_params_if(PIO_INSTRUCTIONS, !(src & _PIO_INVALID_MOV_SRC));
return _pio_encode_instr_and_src_dest(pio_instr_bits_mov, dest, return _pio_encode_instr_and_src_dest(pio_instr_bits_mov, dest, (1u << 3u) | (src & 7u));
(1u << 3u) | (src & 7u));
} }
/*! \brief Encode a MOV instruction with bit reverse /*! \brief Encode a MOV instruction with bit reverse
@ -426,12 +402,10 @@ static inline uint pio_encode_mov_not(enum pio_src_dest dest,
* \return The instruction encoding with 0 delay and no side set value * \return The instruction encoding with 0 delay and no side set value
* \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
*/ */
static inline uint pio_encode_mov_reverse(enum pio_src_dest dest, static inline uint pio_encode_mov_reverse(enum pio_src_dest dest, enum pio_src_dest src) {
enum pio_src_dest src) {
valid_params_if(PIO_INSTRUCTIONS, !(dest & _PIO_INVALID_MOV_DEST)); valid_params_if(PIO_INSTRUCTIONS, !(dest & _PIO_INVALID_MOV_DEST));
valid_params_if(PIO_INSTRUCTIONS, !(src & _PIO_INVALID_MOV_SRC)); valid_params_if(PIO_INSTRUCTIONS, !(src & _PIO_INVALID_MOV_SRC));
return _pio_encode_instr_and_src_dest(pio_instr_bits_mov, dest, return _pio_encode_instr_and_src_dest(pio_instr_bits_mov, dest, (2u << 3u) | (src & 7u));
(2u << 3u) | (src & 7u));
} }
/*! \brief Encode a IRQ SET instruction /*! \brief Encode a IRQ SET instruction
@ -439,14 +413,13 @@ static inline uint pio_encode_mov_reverse(enum pio_src_dest dest,
* *
* This is the equivalent of `IRQ SET <irq> <relative>` * This is the equivalent of `IRQ SET <irq> <relative>`
* *
* \param relative true for a `IRQ SET <irq> REL`, false for regular `IRQ SET * \param relative true for a `IRQ SET <irq> REL`, false for regular `IRQ SET <irq>`
* <irq>` \param irq the irq number 0-7 \return The instruction encoding with 0 * \param irq the irq number 0-7
* delay and no side set value \see pio_encode_delay, pio_encode_sideset, * \return The instruction encoding with 0 delay and no side set value
* pio_encode_sideset_opt * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
*/ */
static inline uint pio_encode_irq_set(bool relative, uint irq) { static inline uint pio_encode_irq_set(bool relative, uint irq) {
return _pio_encode_instr_and_args(pio_instr_bits_irq, 0, return _pio_encode_instr_and_args(pio_instr_bits_irq, 0, _pio_encode_irq(relative, irq));
_pio_encode_irq(relative, irq));
} }
/*! \brief Encode a IRQ WAIT instruction /*! \brief Encode a IRQ WAIT instruction
@ -454,14 +427,13 @@ static inline uint pio_encode_irq_set(bool relative, uint irq) {
* *
* This is the equivalent of `IRQ WAIT <irq> <relative>` * This is the equivalent of `IRQ WAIT <irq> <relative>`
* *
* \param relative true for a `IRQ WAIT <irq> REL`, false for regular `IRQ WAIT * \param relative true for a `IRQ WAIT <irq> REL`, false for regular `IRQ WAIT <irq>`
* <irq>` \param irq the irq number 0-7 \return The instruction encoding with 0 * \param irq the irq number 0-7
* delay and no side set value \see pio_encode_delay, pio_encode_sideset, * \return The instruction encoding with 0 delay and no side set value
* pio_encode_sideset_opt * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
*/ */
static inline uint pio_encode_irq_wait(bool relative, uint irq) { static inline uint pio_encode_irq_wait(bool relative, uint irq) {
return _pio_encode_instr_and_args(pio_instr_bits_irq, 1, return _pio_encode_instr_and_args(pio_instr_bits_irq, 1, _pio_encode_irq(relative, irq));
_pio_encode_irq(relative, irq));
} }
/*! \brief Encode a IRQ CLEAR instruction /*! \brief Encode a IRQ CLEAR instruction
@ -469,14 +441,13 @@ static inline uint pio_encode_irq_wait(bool relative, uint irq) {
* *
* This is the equivalent of `IRQ CLEAR <irq> <relative>` * This is the equivalent of `IRQ CLEAR <irq> <relative>`
* *
* \param relative true for a `IRQ CLEAR <irq> REL`, false for regular `IRQ * \param relative true for a `IRQ CLEAR <irq> REL`, false for regular `IRQ CLEAR <irq>`
* CLEAR <irq>` \param irq the irq number 0-7 \return The instruction encoding * \param irq the irq number 0-7
* with 0 delay and no side set value \see pio_encode_delay, pio_encode_sideset, * \return The instruction encoding with 0 delay and no side set value
* pio_encode_sideset_opt * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
*/ */
static inline uint pio_encode_irq_clear(bool relative, uint irq) { static inline uint pio_encode_irq_clear(bool relative, uint irq) {
return _pio_encode_instr_and_args(pio_instr_bits_irq, 2, return _pio_encode_instr_and_args(pio_instr_bits_irq, 2, _pio_encode_irq(relative, irq));
_pio_encode_irq(relative, irq));
} }
/*! \brief Encode a SET instruction /*! \brief Encode a SET instruction
@ -502,7 +473,9 @@ static inline uint pio_encode_set(enum pio_src_dest dest, uint value) {
* \return The instruction encoding with 0 delay and no side set value * \return The instruction encoding with 0 delay and no side set value
* \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
*/ */
static inline uint pio_encode_nop(void) { return pio_encode_mov(pio_y, pio_y); } static inline uint pio_encode_nop(void) {
return pio_encode_mov(pio_y, pio_y);
}
#ifdef __cplusplus #ifdef __cplusplus
} }

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,11 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2024 Raspberry Pi Ltd.
* All rights reserved.
*/
#ifndef _HARDWARE_TIMER_H
#define _HARDWARE_TIMER_H
#include "piolib.h"
#endif

View file

@ -25,27 +25,17 @@
#define PARAM_ASSERTIONS_DISABLE_ALL 0 #define PARAM_ASSERTIONS_DISABLE_ALL 0
#endif #endif
#define PARAM_ASSERTIONS_ENABLED(x) \ #define PARAM_ASSERTIONS_ENABLED(x) ((PARAM_ASSERTIONS_ENABLED_ ## x || PARAM_ASSERTIONS_ENABLE_ALL) && !PARAM_ASSERTIONS_DISABLE_ALL)
((PARAM_ASSERTIONS_ENABLED_##x || PARAM_ASSERTIONS_ENABLE_ALL) && \ #define invalid_params_if(x, test) ({if (PARAM_ASSERTIONS_ENABLED(x)) assert(!(test));})
!PARAM_ASSERTIONS_DISABLE_ALL) #define valid_params_if(x, test) ({if (PARAM_ASSERTIONS_ENABLED(x)) assert(test);})
#define invalid_params_if(x, test) \
({ \
if (PARAM_ASSERTIONS_ENABLED(x)) \
assert(!(test)); \
})
#define valid_params_if(x, test) \
({ \
if (PARAM_ASSERTIONS_ENABLED(x)) \
assert(test); \
})
#define STATIC_ASSERT(cond) static_assert(cond, #cond) #define STATIC_ASSERT(cond) static_assert(cond, #cond)
#define _u(x) ((uint)(x)) #define _u(x) ((uint)(x))
#define bool_to_bit(x) ((uint) !!(x)) #define bool_to_bit(x) ((uint)!!(x))
#ifndef count_of #ifndef count_of
#define count_of(a) (sizeof(a) / sizeof((a)[0])) #define count_of(a) (sizeof(a)/sizeof((a)[0]))
#endif #endif
typedef unsigned int uint; typedef unsigned int uint;

View file

@ -11,32 +11,39 @@
extern "C" { extern "C" {
#endif #endif
#include "pio_platform.h"
#include "hardware/clocks.h" #include "hardware/clocks.h"
#include "hardware/gpio.h" #include "hardware/gpio.h"
#include "pio_platform.h"
#ifndef PARAM_ASSERTIONS_ENABLED_PIO #ifndef PARAM_ASSERTIONS_ENABLED_PIO
#define PARAM_ASSERTIONS_ENABLED_PIO 0 #define PARAM_ASSERTIONS_ENABLED_PIO 0
#endif #endif
#define PIO_ERR(x) ((PIO)(uintptr_t)(x)) #define PIO_ERR(x)((PIO)(uintptr_t)(x))
#define PIO_IS_ERR(x) (((uintptr_t)(x) >= (uintptr_t)-200)) #define PIO_IS_ERR(x)(((uintptr_t)(x) >= (uintptr_t)-200))
#define PIO_ERR_VAL(x) ((int)(uintptr_t)(x)) #define PIO_ERR_VAL(x)((int)(uintptr_t)(x))
#define PIO_ORIGIN_ANY ((uint)(~0)) #define PIO_ORIGIN_ANY ((uint)(~0))
#define PIO_ORIGIN_INVALID PIO_ORIGIN_ANY #define PIO_ORIGIN_INVALID PIO_ORIGIN_ANY
#define pio0 pio_open_helper(0) #define pio0 pio_open_helper(0)
enum pio_fifo_join { enum pio_fifo_join {
PIO_FIFO_JOIN_NONE = 0, PIO_FIFO_JOIN_NONE = 0,
PIO_FIFO_JOIN_TX = 1, PIO_FIFO_JOIN_TX = 1,
PIO_FIFO_JOIN_RX = 2, PIO_FIFO_JOIN_RX = 2,
}; };
enum pio_mov_status_type { STATUS_TX_LESSTHAN = 0, STATUS_RX_LESSTHAN = 1 }; enum pio_mov_status_type {
STATUS_TX_LESSTHAN = 0,
STATUS_RX_LESSTHAN = 1
};
enum pio_xfer_dir { PIO_DIR_TO_SM, PIO_DIR_FROM_SM, PIO_DIR_COUNT }; enum pio_xfer_dir {
PIO_DIR_TO_SM,
PIO_DIR_FROM_SM,
PIO_DIR_COUNT
};
#ifndef PIOLIB_INTERNALS #ifndef PIOLIB_INTERNALS
@ -53,16 +60,16 @@ enum pio_instr_bits {
}; };
#ifndef NDEBUG #ifndef NDEBUG
#define _PIO_INVALID_IN_SRC 0x08u #define _PIO_INVALID_IN_SRC 0x08u
#define _PIO_INVALID_OUT_DEST 0x10u #define _PIO_INVALID_OUT_DEST 0x10u
#define _PIO_INVALID_SET_DEST 0x20u #define _PIO_INVALID_SET_DEST 0x20u
#define _PIO_INVALID_MOV_SRC 0x40u #define _PIO_INVALID_MOV_SRC 0x40u
#define _PIO_INVALID_MOV_DEST 0x80u #define _PIO_INVALID_MOV_DEST 0x80u
#else #else
#define _PIO_INVALID_IN_SRC 0u #define _PIO_INVALID_IN_SRC 0u
#define _PIO_INVALID_OUT_DEST 0u #define _PIO_INVALID_OUT_DEST 0u
#define _PIO_INVALID_SET_DEST 0u #define _PIO_INVALID_SET_DEST 0u
#define _PIO_INVALID_MOV_SRC 0u #define _PIO_INVALID_MOV_SRC 0u
#define _PIO_INVALID_MOV_DEST 0u #define _PIO_INVALID_MOV_DEST 0u
#endif #endif
@ -71,18 +78,13 @@ enum pio_src_dest {
pio_x = 1u, pio_x = 1u,
pio_y = 2u, pio_y = 2u,
pio_null = 3u | _PIO_INVALID_SET_DEST | _PIO_INVALID_MOV_DEST, pio_null = 3u | _PIO_INVALID_SET_DEST | _PIO_INVALID_MOV_DEST,
pio_pindirs = pio_pindirs = 4u | _PIO_INVALID_IN_SRC | _PIO_INVALID_MOV_SRC | _PIO_INVALID_MOV_DEST,
4u | _PIO_INVALID_IN_SRC | _PIO_INVALID_MOV_SRC | _PIO_INVALID_MOV_DEST, pio_exec_mov = 4u | _PIO_INVALID_IN_SRC | _PIO_INVALID_OUT_DEST | _PIO_INVALID_SET_DEST | _PIO_INVALID_MOV_SRC,
pio_exec_mov = 4u | _PIO_INVALID_IN_SRC | _PIO_INVALID_OUT_DEST | pio_status = 5u | _PIO_INVALID_IN_SRC | _PIO_INVALID_OUT_DEST | _PIO_INVALID_SET_DEST | _PIO_INVALID_MOV_DEST,
_PIO_INVALID_SET_DEST | _PIO_INVALID_MOV_SRC, pio_pc = 5u | _PIO_INVALID_IN_SRC | _PIO_INVALID_SET_DEST | _PIO_INVALID_MOV_SRC,
pio_status = 5u | _PIO_INVALID_IN_SRC | _PIO_INVALID_OUT_DEST |
_PIO_INVALID_SET_DEST | _PIO_INVALID_MOV_DEST,
pio_pc =
5u | _PIO_INVALID_IN_SRC | _PIO_INVALID_SET_DEST | _PIO_INVALID_MOV_SRC,
pio_isr = 6u | _PIO_INVALID_SET_DEST, pio_isr = 6u | _PIO_INVALID_SET_DEST,
pio_osr = 7u | _PIO_INVALID_OUT_DEST | _PIO_INVALID_SET_DEST, pio_osr = 7u | _PIO_INVALID_OUT_DEST | _PIO_INVALID_SET_DEST,
pio_exec_out = 7u | _PIO_INVALID_IN_SRC | _PIO_INVALID_SET_DEST | pio_exec_out = 7u | _PIO_INVALID_IN_SRC | _PIO_INVALID_SET_DEST | _PIO_INVALID_MOV_SRC | _PIO_INVALID_MOV_DEST,
_PIO_INVALID_MOV_SRC | _PIO_INVALID_MOV_DEST,
}; };
#endif #endif
@ -113,17 +115,12 @@ struct pio_chip {
int (*open_instance)(PIO pio); int (*open_instance)(PIO pio);
void (*close_instance)(PIO pio); void (*close_instance)(PIO pio);
int (*pio_sm_config_xfer)(PIO pio, uint sm, uint dir, uint buf_size, int (*pio_sm_config_xfer)(PIO pio, uint sm, uint dir, uint buf_size, uint buf_count);
uint buf_count); int (*pio_sm_xfer_data)(PIO pio, uint sm, uint dir, uint data_bytes, void *data);
int (*pio_sm_xfer_data)(PIO pio, uint sm, uint dir, uint data_bytes,
void *data);
bool (*pio_can_add_program_at_offset)(PIO pio, const pio_program_t *program, bool (*pio_can_add_program_at_offset)(PIO pio, const pio_program_t *program, uint offset);
uint offset); uint (*pio_add_program_at_offset)(PIO pio, const pio_program_t *program, uint offset);
uint (*pio_add_program_at_offset)(PIO pio, const pio_program_t *program, bool (*pio_remove_program)(PIO pio, const pio_program_t *program, uint loaded_offset);
uint offset);
bool (*pio_remove_program)(PIO pio, const pio_program_t *program,
uint loaded_offset);
bool (*pio_clear_instruction_memory)(PIO pio); bool (*pio_clear_instruction_memory)(PIO pio);
uint (*pio_encode_delay)(PIO pio, uint cycles); uint (*pio_encode_delay)(PIO pio, uint cycles);
uint (*pio_encode_sideset)(PIO pio, uint sideset_bit_count, uint value); uint (*pio_encode_sideset)(PIO pio, uint sideset_bit_count, uint value);
@ -138,18 +135,14 @@ struct pio_chip {
uint (*pio_encode_jmp_not_osre)(PIO pio, uint addr); uint (*pio_encode_jmp_not_osre)(PIO pio, uint addr);
uint (*pio_encode_wait_gpio)(PIO pio, bool polarity, uint gpio); uint (*pio_encode_wait_gpio)(PIO pio, bool polarity, uint gpio);
uint (*pio_encode_wait_pin)(PIO pio, bool polarity, uint pin); uint (*pio_encode_wait_pin)(PIO pio, bool polarity, uint pin);
uint (*pio_encode_wait_irq)(PIO pio, bool polarity, bool relative, uint (*pio_encode_wait_irq)(PIO pio, bool polarity, bool relative, uint irq);
uint irq);
uint (*pio_encode_in)(PIO pio, enum pio_src_dest src, uint count); uint (*pio_encode_in)(PIO pio, enum pio_src_dest src, uint count);
uint (*pio_encode_out)(PIO pio, enum pio_src_dest dest, uint count); uint (*pio_encode_out)(PIO pio, enum pio_src_dest dest, uint count);
uint (*pio_encode_push)(PIO pio, bool if_full, bool block); uint (*pio_encode_push)(PIO pio, bool if_full, bool block);
uint (*pio_encode_pull)(PIO pio, bool if_empty, bool block); uint (*pio_encode_pull)(PIO pio, bool if_empty, bool block);
uint (*pio_encode_mov)(PIO pio, enum pio_src_dest dest, uint (*pio_encode_mov)(PIO pio, enum pio_src_dest dest, enum pio_src_dest src);
enum pio_src_dest src); uint (*pio_encode_mov_not)(PIO pio, enum pio_src_dest dest, enum pio_src_dest src);
uint (*pio_encode_mov_not)(PIO pio, enum pio_src_dest dest, uint (*pio_encode_mov_reverse)(PIO pio, enum pio_src_dest dest, enum pio_src_dest src);
enum pio_src_dest src);
uint (*pio_encode_mov_reverse)(PIO pio, enum pio_src_dest dest,
enum pio_src_dest src);
uint (*pio_encode_irq_set)(PIO pio, bool relative, uint irq); uint (*pio_encode_irq_set)(PIO pio, bool relative, uint irq);
uint (*pio_encode_irq_wait)(PIO pio, bool relative, uint irq); uint (*pio_encode_irq_wait)(PIO pio, bool relative, uint irq);
uint (*pio_encode_irq_clear)(PIO pio, bool relative, uint irq); uint (*pio_encode_irq_clear)(PIO pio, bool relative, uint irq);
@ -162,21 +155,16 @@ struct pio_chip {
bool (*pio_sm_unclaim)(PIO pio, uint sm); bool (*pio_sm_unclaim)(PIO pio, uint sm);
bool (*pio_sm_is_claimed)(PIO pio, uint sm); bool (*pio_sm_is_claimed)(PIO pio, uint sm);
void (*pio_sm_init)(PIO pio, uint sm, uint initial_pc, void (*pio_sm_init)(PIO pio, uint sm, uint initial_pc, const pio_sm_config *config);
const pio_sm_config *config);
void (*pio_sm_set_config)(PIO pio, uint sm, const pio_sm_config *config); void (*pio_sm_set_config)(PIO pio, uint sm, const pio_sm_config *config);
void (*pio_sm_exec)(PIO pio, uint sm, uint instr, bool blocking); void (*pio_sm_exec)(PIO pio, uint sm, uint instr, bool blocking);
void (*pio_sm_clear_fifos)(PIO pio, uint sm); void (*pio_sm_clear_fifos)(PIO pio, uint sm);
void (*pio_sm_set_clkdiv_int_frac)(PIO pio, uint sm, uint16_t div_int, void (*pio_sm_set_clkdiv_int_frac)(PIO pio, uint sm, uint16_t div_int, uint8_t div_frac);
uint8_t div_frac);
void (*pio_sm_set_clkdiv)(PIO pio, uint sm, float div); void (*pio_sm_set_clkdiv)(PIO pio, uint sm, float div);
void (*pio_sm_set_pins)(PIO pio, uint sm, uint32_t pin_values); void (*pio_sm_set_pins)(PIO pio, uint sm, uint32_t pin_values);
void (*pio_sm_set_pins_with_mask)(PIO pio, uint sm, uint32_t pin_values, void (*pio_sm_set_pins_with_mask)(PIO pio, uint sm, uint32_t pin_values, uint32_t pin_mask);
uint32_t pin_mask); void (*pio_sm_set_pindirs_with_mask)(PIO pio, uint sm, uint32_t pin_dirs, uint32_t pin_mask);
void (*pio_sm_set_pindirs_with_mask)(PIO pio, uint sm, uint32_t pin_dirs, void (*pio_sm_set_consecutive_pindirs)(PIO pio, uint sm, uint pin_base, uint pin_count, bool is_out);
uint32_t pin_mask);
void (*pio_sm_set_consecutive_pindirs)(PIO pio, uint sm, uint pin_base,
uint pin_count, bool is_out);
void (*pio_sm_set_enabled)(PIO pio, uint sm, bool enabled); void (*pio_sm_set_enabled)(PIO pio, uint sm, bool enabled);
void (*pio_sm_set_enabled_mask)(PIO pio, uint32_t mask, bool enabled); void (*pio_sm_set_enabled_mask)(PIO pio, uint32_t mask, bool enabled);
void (*pio_sm_restart)(PIO pio, uint sm); void (*pio_sm_restart)(PIO pio, uint sm);
@ -196,34 +184,23 @@ struct pio_chip {
void (*pio_sm_drain_tx_fifo)(PIO pio, uint sm); void (*pio_sm_drain_tx_fifo)(PIO pio, uint sm);
pio_sm_config (*pio_get_default_sm_config)(PIO pio); pio_sm_config (*pio_get_default_sm_config)(PIO pio);
void (*smc_set_out_pins)(PIO pio, pio_sm_config *c, uint out_base, void (*smc_set_out_pins)(PIO pio, pio_sm_config *c, uint out_base, uint out_count);
uint out_count); void (*smc_set_set_pins)(PIO pio, pio_sm_config *c, uint set_base, uint set_count);
void (*smc_set_set_pins)(PIO pio, pio_sm_config *c, uint set_base,
uint set_count);
void (*smc_set_in_pins)(PIO pio, pio_sm_config *c, uint in_base); void (*smc_set_in_pins)(PIO pio, pio_sm_config *c, uint in_base);
void (*smc_set_sideset_pins)(PIO pio, pio_sm_config *c, uint sideset_base); void (*smc_set_sideset_pins)(PIO pio, pio_sm_config *c, uint sideset_base);
void (*smc_set_sideset)(PIO pio, pio_sm_config *c, uint bit_count, void (*smc_set_sideset)(PIO pio, pio_sm_config *c, uint bit_count, bool optional, bool pindirs);
bool optional, bool pindirs); void (*smc_set_clkdiv_int_frac)(PIO pio, pio_sm_config *c, uint16_t div_int, uint8_t div_frac);
void (*smc_set_clkdiv_int_frac)(PIO pio, pio_sm_config *c, uint16_t div_int,
uint8_t div_frac);
void (*smc_set_clkdiv)(PIO pio, pio_sm_config *c, float div); void (*smc_set_clkdiv)(PIO pio, pio_sm_config *c, float div);
void (*smc_set_wrap)(PIO pio, pio_sm_config *c, uint wrap_target, void (*smc_set_wrap)(PIO pio, pio_sm_config *c, uint wrap_target, uint wrap);
uint wrap);
void (*smc_set_jmp_pin)(PIO pio, pio_sm_config *c, uint pin); void (*smc_set_jmp_pin)(PIO pio, pio_sm_config *c, uint pin);
void (*smc_set_in_shift)(PIO pio, pio_sm_config *c, bool shift_right, void (*smc_set_in_shift)(PIO pio, pio_sm_config *c, bool shift_right, bool autopush, uint push_threshold);
bool autopush, uint push_threshold); void (*smc_set_out_shift)(PIO pio, pio_sm_config *c, bool shift_right, bool autopull, uint pull_threshold);
void (*smc_set_out_shift)(PIO pio, pio_sm_config *c, bool shift_right, void (*smc_set_fifo_join)(PIO pio, pio_sm_config *c, enum pio_fifo_join join);
bool autopull, uint pull_threshold); void (*smc_set_out_special)(PIO pio, pio_sm_config *c, bool sticky, bool has_enable_pin, uint enable_pin_index);
void (*smc_set_fifo_join)(PIO pio, pio_sm_config *c, void (*smc_set_mov_status)(PIO pio, pio_sm_config *c, enum pio_mov_status_type status_sel, uint status_n);
enum pio_fifo_join join);
void (*smc_set_out_special)(PIO pio, pio_sm_config *c, bool sticky,
bool has_enable_pin, uint enable_pin_index);
void (*smc_set_mov_status)(PIO pio, pio_sm_config *c,
enum pio_mov_status_type status_sel,
uint status_n);
uint32_t (*clock_get_hz)(PIO pio, enum clock_index clk_index); uint32_t (*clock_get_hz)(PIO pio, enum clock_index clk_index);
void (*pio_gpio_init)(PIO pio, uint pin); void (*pio_gpio_init)(PIO, uint pin);
void (*gpio_init)(PIO pio, uint gpio); void (*gpio_init)(PIO pio, uint gpio);
void (*gpio_set_function)(PIO pio, uint gpio, enum gpio_function fn); void (*gpio_set_function)(PIO pio, uint gpio, enum gpio_function fn);
void (*gpio_set_pulls)(PIO pio, uint gpio, bool up, bool down); void (*gpio_set_pulls)(PIO pio, uint gpio, bool up, bool down);
@ -231,8 +208,7 @@ struct pio_chip {
void (*gpio_set_inover)(PIO pio, uint gpio, uint value); void (*gpio_set_inover)(PIO pio, uint gpio, uint value);
void (*gpio_set_oeover)(PIO pio, uint gpio, uint value); void (*gpio_set_oeover)(PIO pio, uint gpio, uint value);
void (*gpio_set_input_enabled)(PIO pio, uint gpio, bool enabled); void (*gpio_set_input_enabled)(PIO pio, uint gpio, bool enabled);
void (*gpio_set_drive_strength)(PIO pio, uint gpio, void (*gpio_set_drive_strength)(PIO pio, uint gpio, enum gpio_drive_strength drive);
enum gpio_drive_strength drive);
}; };
struct pio_instance { struct pio_instance {
@ -252,58 +228,74 @@ int pio_get_index(PIO pio);
void pio_select(PIO pio); void pio_select(PIO pio);
PIO pio_get_current(void); PIO pio_get_current(void);
static inline void pio_error(PIO pio, const char *msg) { static inline void pio_error(PIO pio, const char *msg)
{
pio->error = true; pio->error = true;
if (pio->errors_are_fatal) if (pio->errors_are_fatal)
pio_panic(msg); pio_panic(msg);
} }
static inline bool pio_get_error(PIO pio) { return pio->error; } static inline bool pio_get_error(PIO pio)
{
return pio->error;
}
static inline void pio_clear_error(PIO pio) { pio->error = false; } static inline void pio_clear_error(PIO pio)
{
pio->error = false;
}
static inline void pio_enable_fatal_errors(PIO pio, bool enable) { static inline void pio_enable_fatal_errors(PIO pio, bool enable)
{
pio->errors_are_fatal = enable; pio->errors_are_fatal = enable;
} }
static inline uint pio_get_sm_count(PIO pio) { return pio->chip->sm_count; } static inline uint pio_get_sm_count(PIO pio)
{
return pio->chip->sm_count;
}
static inline uint pio_get_instruction_count(PIO pio) { static inline uint pio_get_instruction_count(PIO pio)
{
return pio->chip->instr_count; return pio->chip->instr_count;
} }
static inline uint pio_get_fifo_depth(PIO pio) { return pio->chip->fifo_depth; } static inline uint pio_get_fifo_depth(PIO pio)
{
return pio->chip->fifo_depth;
}
static inline void check_pio_param(__unused PIO pio) { static inline void check_pio_param(__unused PIO pio)
{
valid_params_if(PIO, pio_get_index(pio) >= 0); valid_params_if(PIO, pio_get_index(pio) >= 0);
} }
static inline int pio_sm_config_xfer(PIO pio, uint sm, uint dir, uint buf_size, static inline int pio_sm_config_xfer(PIO pio, uint sm, uint dir, uint buf_size, uint buf_count)
uint buf_count) { {
check_pio_param(pio); check_pio_param(pio);
return pio->chip->pio_sm_config_xfer(pio, sm, dir, buf_size, buf_count); return pio->chip->pio_sm_config_xfer(pio, sm, dir, buf_size, buf_count);
} }
static inline int pio_sm_xfer_data(PIO pio, uint sm, uint dir, uint data_bytes, static inline int pio_sm_xfer_data(PIO pio, uint sm, uint dir, uint data_bytes, void *data)
void *data) { {
check_pio_param(pio); check_pio_param(pio);
return pio->chip->pio_sm_xfer_data(pio, sm, dir, data_bytes, data); return pio->chip->pio_sm_xfer_data(pio, sm, dir, data_bytes, data);
} }
static inline bool pio_can_add_program(PIO pio, const pio_program_t *program) { static inline bool pio_can_add_program(PIO pio, const pio_program_t *program)
{
check_pio_param(pio); check_pio_param(pio);
return pio->chip->pio_can_add_program_at_offset(pio, program, return pio->chip->pio_can_add_program_at_offset(pio, program, PIO_ORIGIN_ANY);
PIO_ORIGIN_ANY);
} }
static inline bool pio_can_add_program_at_offset(PIO pio, static inline bool pio_can_add_program_at_offset(PIO pio, const pio_program_t *program, uint offset)
const pio_program_t *program, {
uint offset) {
check_pio_param(pio); check_pio_param(pio);
return pio->chip->pio_can_add_program_at_offset(pio, program, offset); return pio->chip->pio_can_add_program_at_offset(pio, program, offset);
} }
static inline uint pio_add_program(PIO pio, const pio_program_t *program) { static inline uint pio_add_program(PIO pio, const pio_program_t *program)
{
uint offset; uint offset;
check_pio_param(pio); check_pio_param(pio);
offset = pio->chip->pio_add_program_at_offset(pio, program, PIO_ORIGIN_ANY); offset = pio->chip->pio_add_program_at_offset(pio, program, PIO_ORIGIN_ANY);
@ -312,492 +304,548 @@ static inline uint pio_add_program(PIO pio, const pio_program_t *program) {
return offset; return offset;
} }
static inline void static inline void pio_add_program_at_offset(PIO pio, const pio_program_t *program, uint offset)
pio_add_program_at_offset(PIO pio, const pio_program_t *program, uint offset) { {
check_pio_param(pio); check_pio_param(pio);
if (pio->chip->pio_add_program_at_offset(pio, program, offset) == if (pio->chip->pio_add_program_at_offset(pio, program, offset) == PIO_ORIGIN_INVALID)
PIO_ORIGIN_INVALID)
pio_error(pio, "No program space"); pio_error(pio, "No program space");
} }
static inline void pio_remove_program(PIO pio, const pio_program_t *program, static inline void pio_remove_program(PIO pio, const pio_program_t *program, uint loaded_offset)
uint loaded_offset) { {
check_pio_param(pio); check_pio_param(pio);
if (!pio->chip->pio_remove_program(pio, program, loaded_offset)) if (!pio->chip->pio_remove_program(pio, program, loaded_offset))
pio_error(pio, "Failed to remove program"); pio_error(pio, "Failed to remove program");
} }
static inline void pio_clear_instruction_memory(PIO pio) { static inline void pio_clear_instruction_memory(PIO pio)
{
check_pio_param(pio); check_pio_param(pio);
if (!pio->chip->pio_clear_instruction_memory(pio)) if (!pio->chip->pio_clear_instruction_memory(pio))
pio_error(pio, "Failed to clear instruction memory"); pio_error(pio, "Failed to clear instruction memory");
} }
static inline uint pio_encode_delay(uint cycles) { static inline uint pio_encode_delay(uint cycles)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
return pio->chip->pio_encode_delay(pio, cycles); return pio->chip->pio_encode_delay(pio, cycles);
} }
static inline uint pio_encode_sideset(uint sideset_bit_count, uint value) { static inline uint pio_encode_sideset(uint sideset_bit_count, uint value)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
return pio->chip->pio_encode_sideset(pio, sideset_bit_count, value); return pio->chip->pio_encode_sideset(pio, sideset_bit_count, value);
} }
static inline uint pio_encode_sideset_opt(uint sideset_bit_count, uint value) { static inline uint pio_encode_sideset_opt(uint sideset_bit_count, uint value)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
return pio->chip->pio_encode_sideset_opt(pio, sideset_bit_count, value); return pio->chip->pio_encode_sideset_opt(pio, sideset_bit_count, value);
} }
static inline uint pio_encode_jmp(uint addr) { static inline uint pio_encode_jmp(uint addr)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
return pio->chip->pio_encode_jmp(pio, addr); return pio->chip->pio_encode_jmp(pio, addr);
} }
static inline uint pio_encode_jmp_not_x(uint addr) { static inline uint pio_encode_jmp_not_x(uint addr)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
return pio->chip->pio_encode_jmp_not_x(pio, addr); return pio->chip->pio_encode_jmp_not_x(pio, addr);
} }
static inline uint pio_encode_jmp_x_dec(uint addr) { static inline uint pio_encode_jmp_x_dec(uint addr)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
return pio->chip->pio_encode_jmp_x_dec(pio, addr); return pio->chip->pio_encode_jmp_x_dec(pio, addr);
} }
static inline uint pio_encode_jmp_not_y(uint addr) { static inline uint pio_encode_jmp_not_y(uint addr)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
return pio->chip->pio_encode_jmp_not_y(pio, addr); return pio->chip->pio_encode_jmp_not_y(pio, addr);
} }
static inline uint pio_encode_jmp_y_dec(uint addr) { static inline uint pio_encode_jmp_y_dec(uint addr)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
return pio->chip->pio_encode_jmp_y_dec(pio, addr); return pio->chip->pio_encode_jmp_y_dec(pio, addr);
} }
static inline uint pio_encode_jmp_x_ne_y(uint addr) { static inline uint pio_encode_jmp_x_ne_y(uint addr)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
return pio->chip->pio_encode_jmp_x_ne_y(pio, addr); return pio->chip->pio_encode_jmp_x_ne_y(pio, addr);
} }
static inline uint pio_encode_jmp_pin(uint addr) { static inline uint pio_encode_jmp_pin(uint addr)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
return pio->chip->pio_encode_jmp_pin(pio, addr); return pio->chip->pio_encode_jmp_pin(pio, addr);
} }
static inline uint pio_encode_jmp_not_osre(uint addr) { static inline uint pio_encode_jmp_not_osre(uint addr)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
return pio->chip->pio_encode_jmp_not_osre(pio, addr); return pio->chip->pio_encode_jmp_not_osre(pio, addr);
} }
static inline uint pio_encode_wait_gpio(bool polarity, uint gpio) { static inline uint pio_encode_wait_gpio(bool polarity, uint gpio)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
return pio->chip->pio_encode_wait_gpio(pio, polarity, gpio); return pio->chip->pio_encode_wait_gpio(pio, polarity, gpio);
} }
static inline uint pio_encode_wait_pin(bool polarity, uint pin) { static inline uint pio_encode_wait_pin(bool polarity, uint pin)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
return pio->chip->pio_encode_wait_pin(pio, polarity, pin); return pio->chip->pio_encode_wait_pin(pio, polarity, pin);
} }
static inline uint pio_encode_wait_irq(bool polarity, bool relative, uint irq) { static inline uint pio_encode_wait_irq(bool polarity, bool relative, uint irq)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
return pio->chip->pio_encode_wait_irq(pio, polarity, relative, irq); return pio->chip->pio_encode_wait_irq(pio, polarity, relative, irq);
} }
static inline uint pio_encode_in(enum pio_src_dest src, uint count) { static inline uint pio_encode_in(enum pio_src_dest src, uint count)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
return pio->chip->pio_encode_in(pio, src, count); return pio->chip->pio_encode_in(pio, src, count);
} }
static inline uint pio_encode_out(enum pio_src_dest dest, uint count) { static inline uint pio_encode_out(enum pio_src_dest dest, uint count)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
return pio->chip->pio_encode_out(pio, dest, count); return pio->chip->pio_encode_out(pio, dest, count);
} }
static inline uint pio_encode_push(bool if_full, bool block) { static inline uint pio_encode_push(bool if_full, bool block)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
return pio->chip->pio_encode_push(pio, if_full, block); return pio->chip->pio_encode_push(pio, if_full, block);
} }
static inline uint pio_encode_pull(bool if_empty, bool block) { static inline uint pio_encode_pull(bool if_empty, bool block)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
return pio->chip->pio_encode_pull(pio, if_empty, block); return pio->chip->pio_encode_pull(pio, if_empty, block);
} }
static inline uint pio_encode_mov(enum pio_src_dest dest, static inline uint pio_encode_mov(enum pio_src_dest dest, enum pio_src_dest src)
enum pio_src_dest src) { {
PIO pio = pio_get_current(); PIO pio = pio_get_current();
return pio->chip->pio_encode_mov(pio, dest, src); return pio->chip->pio_encode_mov(pio, dest, src);
} }
static inline uint pio_encode_mov_not(enum pio_src_dest dest, static inline uint pio_encode_mov_not(enum pio_src_dest dest, enum pio_src_dest src)
enum pio_src_dest src) { {
PIO pio = pio_get_current(); PIO pio = pio_get_current();
return pio->chip->pio_encode_mov_not(pio, dest, src); return pio->chip->pio_encode_mov_not(pio, dest, src);
} }
static inline uint pio_encode_mov_reverse(enum pio_src_dest dest, static inline uint pio_encode_mov_reverse(enum pio_src_dest dest, enum pio_src_dest src)
enum pio_src_dest src) { {
PIO pio = pio_get_current(); PIO pio = pio_get_current();
return pio->chip->pio_encode_mov_reverse(pio, dest, src); return pio->chip->pio_encode_mov_reverse(pio, dest, src);
} }
static inline uint pio_encode_irq_set(bool relative, uint irq) { static inline uint pio_encode_irq_set(bool relative, uint irq)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
return pio->chip->pio_encode_irq_set(pio, relative, irq); return pio->chip->pio_encode_irq_set(pio, relative, irq);
} }
static inline uint pio_encode_irq_wait(bool relative, uint irq) { static inline uint pio_encode_irq_wait(bool relative, uint irq)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
return pio->chip->pio_encode_irq_wait(pio, relative, irq); return pio->chip->pio_encode_irq_wait(pio, relative, irq);
} }
static inline uint pio_encode_irq_clear(bool relative, uint irq) { static inline uint pio_encode_irq_clear(bool relative, uint irq)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
return pio->chip->pio_encode_irq_clear(pio, relative, irq); return pio->chip->pio_encode_irq_clear(pio, relative, irq);
} }
static inline uint pio_encode_set(enum pio_src_dest dest, uint value) { static inline uint pio_encode_set(enum pio_src_dest dest, uint value)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
return pio->chip->pio_encode_set(pio, dest, value); return pio->chip->pio_encode_set(pio, dest, value);
} }
static inline uint pio_encode_nop(void) { static inline uint pio_encode_nop(void)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
return pio->chip->pio_encode_nop(pio); return pio->chip->pio_encode_nop(pio);
} }
static inline void pio_sm_claim(PIO pio, uint sm) { static inline void pio_sm_claim(PIO pio, uint sm)
{
check_pio_param(pio); check_pio_param(pio);
if (!pio->chip->pio_sm_claim(pio, sm)) if (!pio->chip->pio_sm_claim(pio, sm))
pio_error(pio, "Failed to claim SM"); pio_error(pio, "Failed to claim SM");
} }
static inline void pio_claim_sm_mask(PIO pio, uint mask) { static inline void pio_claim_sm_mask(PIO pio, uint mask)
{
check_pio_param(pio); check_pio_param(pio);
if (!pio->chip->pio_sm_claim_mask(pio, mask)) if (!pio->chip->pio_sm_claim_mask(pio, mask))
pio_error(pio, "Failed to claim masked SMs"); pio_error(pio, "Failed to claim masked SMs");
} }
static inline void pio_sm_unclaim(PIO pio, uint sm) { static inline void pio_sm_unclaim(PIO pio, uint sm)
{
check_pio_param(pio); check_pio_param(pio);
pio->chip->pio_sm_unclaim(pio, sm); pio->chip->pio_sm_unclaim(pio, sm);
} }
static inline int pio_claim_unused_sm(PIO pio, bool required) { static inline int pio_claim_unused_sm(PIO pio, bool required)
{
check_pio_param(pio); check_pio_param(pio);
return pio->chip->pio_sm_claim_unused(pio, required); return pio->chip->pio_sm_claim_unused(pio, required);
} }
static inline bool pio_sm_is_claimed(PIO pio, uint sm) { static inline bool pio_sm_is_claimed(PIO pio, uint sm)
{
check_pio_param(pio); check_pio_param(pio);
return pio->chip->pio_sm_is_claimed(pio, sm); return pio->chip->pio_sm_is_claimed(pio, sm);
} }
static inline void pio_sm_init(PIO pio, uint sm, uint initial_pc, static inline void pio_sm_init(PIO pio, uint sm, uint initial_pc, const pio_sm_config *config)
const pio_sm_config *config) { {
check_pio_param(pio); check_pio_param(pio);
pio->chip->pio_sm_init(pio, sm, initial_pc, config); pio->chip->pio_sm_init(pio, sm, initial_pc, config);
} }
static inline void pio_sm_set_config(PIO pio, uint sm, static inline void pio_sm_set_config(PIO pio, uint sm, const pio_sm_config *config)
const pio_sm_config *config) { {
check_pio_param(pio); check_pio_param(pio);
pio->chip->pio_sm_set_config(pio, sm, config); pio->chip->pio_sm_set_config(pio, sm, config);
} }
static inline void pio_sm_exec(PIO pio, uint sm, uint instr) { static inline void pio_sm_exec(PIO pio, uint sm, uint instr)
{
check_pio_param(pio); check_pio_param(pio);
pio->chip->pio_sm_exec(pio, sm, instr, false); pio->chip->pio_sm_exec(pio, sm, instr, false);
} }
static inline void pio_sm_exec_wait_blocking(PIO pio, uint sm, uint instr) { static inline void pio_sm_exec_wait_blocking(PIO pio, uint sm, uint instr)
{
check_pio_param(pio); check_pio_param(pio);
pio->chip->pio_sm_exec(pio, sm, instr, true); pio->chip->pio_sm_exec(pio, sm, instr, true);
} }
static inline void pio_sm_clear_fifos(PIO pio, uint sm) { static inline void pio_sm_clear_fifos(PIO pio, uint sm)
{
check_pio_param(pio); check_pio_param(pio);
pio->chip->pio_sm_clear_fifos(pio, sm); pio->chip->pio_sm_clear_fifos(pio, sm);
} }
static inline void pio_sm_set_clkdiv_int_frac(PIO pio, uint sm, static inline void pio_sm_set_clkdiv_int_frac(PIO pio, uint sm, uint16_t div_int, uint8_t div_frac)
uint16_t div_int, {
uint8_t div_frac) {
check_pio_param(pio); check_pio_param(pio);
pio->chip->pio_sm_set_clkdiv_int_frac(pio, sm, div_int, div_frac); pio->chip->pio_sm_set_clkdiv_int_frac(pio, sm, div_int, div_frac);
} }
static inline void pio_sm_set_clkdiv(PIO pio, uint sm, float div) { static inline void pio_sm_set_clkdiv(PIO pio, uint sm, float div)
{
check_pio_param(pio); check_pio_param(pio);
pio->chip->pio_sm_set_clkdiv(pio, sm, div); pio->chip->pio_sm_set_clkdiv(pio, sm, div);
} }
static inline void pio_sm_set_pins(PIO pio, uint sm, uint32_t pin_values) { static inline void pio_sm_set_pins(PIO pio, uint sm, uint32_t pin_values)
{
check_pio_param(pio); check_pio_param(pio);
pio->chip->pio_sm_set_pins(pio, sm, pin_values); pio->chip->pio_sm_set_pins(pio, sm, pin_values);
} }
static inline void pio_sm_set_pins_with_mask(PIO pio, uint sm, static inline void pio_sm_set_pins_with_mask(PIO pio, uint sm, uint32_t pin_values, uint32_t pin_mask)
uint32_t pin_values, {
uint32_t pin_mask) {
check_pio_param(pio); check_pio_param(pio);
pio->chip->pio_sm_set_pins_with_mask(pio, sm, pin_values, pin_mask); pio->chip->pio_sm_set_pins_with_mask(pio, sm, pin_values, pin_mask);
} }
static inline void pio_sm_set_pindirs_with_mask(PIO pio, uint sm, static inline void pio_sm_set_pindirs_with_mask(PIO pio, uint sm, uint32_t pin_dirs, uint32_t pin_mask)
uint32_t pin_dirs, {
uint32_t pin_mask) {
check_pio_param(pio); check_pio_param(pio);
pio->chip->pio_sm_set_pindirs_with_mask(pio, sm, pin_dirs, pin_mask); pio->chip->pio_sm_set_pindirs_with_mask(pio, sm, pin_dirs, pin_mask);
} }
static inline void pio_sm_set_consecutive_pindirs(PIO pio, uint sm, static inline void pio_sm_set_consecutive_pindirs(PIO pio, uint sm, uint pin_base, uint pin_count, bool is_out)
uint pin_base, uint pin_count, {
bool is_out) {
check_pio_param(pio); check_pio_param(pio);
pio->chip->pio_sm_set_consecutive_pindirs(pio, sm, pin_base, pin_count, pio->chip->pio_sm_set_consecutive_pindirs(pio, sm, pin_base, pin_count, is_out);
is_out);
} }
static inline void pio_sm_set_enabled(PIO pio, uint sm, bool enabled) { static inline void pio_sm_set_enabled(PIO pio, uint sm, bool enabled)
{
check_pio_param(pio); check_pio_param(pio);
pio->chip->pio_sm_set_enabled(pio, sm, enabled); pio->chip->pio_sm_set_enabled(pio, sm, enabled);
} }
static inline void pio_set_sm_mask_enabled(PIO pio, uint32_t mask, static inline void pio_set_sm_mask_enabled(PIO pio, uint32_t mask, bool enabled)
bool enabled) { {
check_pio_param(pio); check_pio_param(pio);
pio->chip->pio_sm_set_enabled_mask(pio, mask, enabled); pio->chip->pio_sm_set_enabled_mask(pio, mask, enabled);
} }
static inline void pio_sm_restart(PIO pio, uint sm) { static inline void pio_sm_restart(PIO pio, uint sm)
{
check_pio_param(pio); check_pio_param(pio);
pio->chip->pio_sm_restart(pio, sm); pio->chip->pio_sm_restart(pio, sm);
} }
static inline void pio_restart_sm_mask(PIO pio, uint32_t mask) { static inline void pio_restart_sm_mask(PIO pio, uint32_t mask)
{
check_pio_param(pio); check_pio_param(pio);
pio->chip->pio_sm_restart_mask(pio, mask); pio->chip->pio_sm_restart_mask(pio, mask);
} }
static inline void pio_sm_clkdiv_restart(PIO pio, uint sm) { static inline void pio_sm_clkdiv_restart(PIO pio, uint sm)
{
check_pio_param(pio); check_pio_param(pio);
pio->chip->pio_sm_clkdiv_restart(pio, sm); pio->chip->pio_sm_clkdiv_restart(pio, sm);
} }
static inline void pio_clkdiv_restart_sm_mask(PIO pio, uint32_t mask) { static inline void pio_clkdiv_restart_sm_mask(PIO pio, uint32_t mask)
{
check_pio_param(pio); check_pio_param(pio);
pio->chip->pio_sm_clkdiv_restart_mask(pio, mask); pio->chip->pio_sm_clkdiv_restart_mask(pio, mask);
} }
static inline void pio_enable_sm_in_sync_mask(PIO pio, uint32_t mask) { static inline void pio_enable_sm_in_sync_mask(PIO pio, uint32_t mask)
{
check_pio_param(pio); check_pio_param(pio);
pio->chip->pio_sm_enable_sync(pio, mask); pio->chip->pio_sm_enable_sync(pio, mask);
}; };
static inline void pio_sm_set_dmactrl(PIO pio, uint sm, bool is_tx, static inline void pio_sm_set_dmactrl(PIO pio, uint sm, bool is_tx, uint32_t ctrl)
uint32_t ctrl) { {
check_pio_param(pio); check_pio_param(pio);
pio->chip->pio_sm_set_dmactrl(pio, sm, is_tx, ctrl); pio->chip->pio_sm_set_dmactrl(pio, sm, is_tx, ctrl);
}; };
static inline bool pio_sm_is_rx_fifo_empty(PIO pio, uint sm) { static inline bool pio_sm_is_rx_fifo_empty(PIO pio, uint sm)
{
check_pio_param(pio); check_pio_param(pio);
return pio->chip->pio_sm_is_rx_fifo_empty(pio, sm); return pio->chip->pio_sm_is_rx_fifo_empty(pio, sm);
} }
static inline bool pio_sm_is_rx_fifo_full(PIO pio, uint sm) { static inline bool pio_sm_is_rx_fifo_full(PIO pio, uint sm)
{
check_pio_param(pio); check_pio_param(pio);
return pio->chip->pio_sm_is_rx_fifo_full(pio, sm); return pio->chip->pio_sm_is_rx_fifo_full(pio, sm);
} }
static inline uint pio_sm_get_rx_fifo_level(PIO pio, uint sm) { static inline uint pio_sm_get_rx_fifo_level(PIO pio, uint sm)
{
check_pio_param(pio); check_pio_param(pio);
return pio->chip->pio_sm_get_rx_fifo_level(pio, sm); return pio->chip->pio_sm_get_rx_fifo_level(pio, sm);
} }
static inline bool pio_sm_is_tx_fifo_empty(PIO pio, uint sm) { static inline bool pio_sm_is_tx_fifo_empty(PIO pio, uint sm)
{
check_pio_param(pio); check_pio_param(pio);
return pio->chip->pio_sm_is_tx_fifo_empty(pio, sm); return pio->chip->pio_sm_is_tx_fifo_empty(pio, sm);
} }
static inline bool pio_sm_is_tx_fifo_full(PIO pio, uint sm) { static inline bool pio_sm_is_tx_fifo_full(PIO pio, uint sm)
{
check_pio_param(pio); check_pio_param(pio);
return pio->chip->pio_sm_is_tx_fifo_full(pio, sm); return pio->chip->pio_sm_is_tx_fifo_full(pio, sm);
} }
static inline uint pio_sm_get_tx_fifo_level(PIO pio, uint sm) { static inline uint pio_sm_get_tx_fifo_level(PIO pio, uint sm)
{
check_pio_param(pio); check_pio_param(pio);
return pio->chip->pio_sm_get_tx_fifo_level(pio, sm); return pio->chip->pio_sm_get_tx_fifo_level(pio, sm);
} }
static inline void pio_sm_drain_tx_fifo(PIO pio, uint sm) { static inline void pio_sm_drain_tx_fifo(PIO pio, uint sm)
{
check_pio_param(pio); check_pio_param(pio);
return pio->chip->pio_sm_drain_tx_fifo(pio, sm); return pio->chip->pio_sm_drain_tx_fifo(pio, sm);
} }
static inline void pio_sm_put(PIO pio, uint sm, uint32_t data) { static inline void pio_sm_put(PIO pio, uint sm, uint32_t data)
{
check_pio_param(pio); check_pio_param(pio);
pio->chip->pio_sm_put(pio, sm, data, false); pio->chip->pio_sm_put(pio, sm, data, false);
} }
static inline void pio_sm_put_blocking(PIO pio, uint sm, uint32_t data) { static inline void pio_sm_put_blocking(PIO pio, uint sm, uint32_t data)
{
check_pio_param(pio); check_pio_param(pio);
pio->chip->pio_sm_put(pio, sm, data, true); pio->chip->pio_sm_put(pio, sm, data, true);
} }
static inline uint32_t pio_sm_get(PIO pio, uint sm) { static inline uint32_t pio_sm_get(PIO pio, uint sm)
{
check_pio_param(pio); check_pio_param(pio);
return pio->chip->pio_sm_get(pio, sm, false); return pio->chip->pio_sm_get(pio, sm, false);
} }
static inline uint32_t pio_sm_get_blocking(PIO pio, uint sm) { static inline uint32_t pio_sm_get_blocking(PIO pio, uint sm)
{
check_pio_param(pio); check_pio_param(pio);
return pio->chip->pio_sm_get(pio, sm, true); return pio->chip->pio_sm_get(pio, sm, true);
} }
static inline pio_sm_config pio_get_default_sm_config_for_pio(PIO pio) { static inline pio_sm_config pio_get_default_sm_config_for_pio(PIO pio)
{
check_pio_param(pio); check_pio_param(pio);
return pio->chip->pio_get_default_sm_config(pio); return pio->chip->pio_get_default_sm_config(pio);
} }
static inline pio_sm_config pio_get_default_sm_config(void) { static inline pio_sm_config pio_get_default_sm_config(void)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
return pio->chip->pio_get_default_sm_config(pio); return pio->chip->pio_get_default_sm_config(pio);
} }
static inline void sm_config_set_out_pins(pio_sm_config *c, uint out_base, static inline void sm_config_set_out_pins(pio_sm_config *c, uint out_base, uint out_count)
uint out_count) { {
PIO pio = pio_get_current(); PIO pio = pio_get_current();
pio->chip->smc_set_out_pins(pio, c, out_base, out_count); pio->chip->smc_set_out_pins(pio, c, out_base, out_count);
} }
static inline void sm_config_set_set_pins(pio_sm_config *c, uint set_base, static inline void sm_config_set_set_pins(pio_sm_config *c, uint set_base, uint set_count)
uint set_count) { {
PIO pio = pio_get_current(); PIO pio = pio_get_current();
pio->chip->smc_set_set_pins(pio, c, set_base, set_count); pio->chip->smc_set_set_pins(pio, c, set_base, set_count);
} }
static inline void sm_config_set_in_pins(pio_sm_config *c, uint in_base) { static inline void sm_config_set_in_pins(pio_sm_config *c, uint in_base)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
pio->chip->smc_set_in_pins(pio, c, in_base); pio->chip->smc_set_in_pins(pio, c, in_base);
} }
static inline void sm_config_set_sideset_pins(pio_sm_config *c, static inline void sm_config_set_sideset_pins(pio_sm_config *c, uint sideset_base)
uint sideset_base) { {
PIO pio = pio_get_current(); PIO pio = pio_get_current();
pio->chip->smc_set_sideset_pins(pio, c, sideset_base); pio->chip->smc_set_sideset_pins(pio, c, sideset_base);
} }
static inline void sm_config_set_sideset(pio_sm_config *c, uint bit_count, static inline void sm_config_set_sideset(pio_sm_config *c, uint bit_count, bool optional, bool pindirs)
bool optional, bool pindirs) { {
PIO pio = pio_get_current(); PIO pio = pio_get_current();
pio->chip->smc_set_sideset(pio, c, bit_count, optional, pindirs); pio->chip->smc_set_sideset(pio, c, bit_count, optional, pindirs);
} }
static inline void sm_config_set_clkdiv_int_frac(pio_sm_config *c, static inline void sm_config_set_clkdiv_int_frac(pio_sm_config *c, uint16_t div_int, uint8_t div_frac)
uint16_t div_int, {
uint8_t div_frac) {
PIO pio = pio_get_current(); PIO pio = pio_get_current();
pio->chip->smc_set_clkdiv_int_frac(pio, c, div_int, div_frac); pio->chip->smc_set_clkdiv_int_frac(pio, c, div_int, div_frac);
} }
static inline void sm_config_set_clkdiv(pio_sm_config *c, float div) { static inline void sm_config_set_clkdiv(pio_sm_config *c, float div)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
pio->chip->smc_set_clkdiv(pio, c, div); pio->chip->smc_set_clkdiv(pio, c, div);
} }
static inline void sm_config_set_wrap(pio_sm_config *c, uint wrap_target, static inline void sm_config_set_wrap(pio_sm_config *c, uint wrap_target, uint wrap)
uint wrap) { {
PIO pio = pio_get_current(); PIO pio = pio_get_current();
pio->chip->smc_set_wrap(pio, c, wrap_target, wrap); pio->chip->smc_set_wrap(pio, c, wrap_target, wrap);
} }
static inline void sm_config_set_jmp_pin(pio_sm_config *c, uint pin) { static inline void sm_config_set_jmp_pin(pio_sm_config *c, uint pin)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
pio->chip->smc_set_jmp_pin(pio, c, pin); pio->chip->smc_set_jmp_pin(pio, c, pin);
} }
static inline void sm_config_set_in_shift(pio_sm_config *c, bool shift_right, static inline void sm_config_set_in_shift(pio_sm_config *c, bool shift_right, bool autopush, uint push_threshold)
bool autopush, uint push_threshold) { {
PIO pio = pio_get_current(); PIO pio = pio_get_current();
pio->chip->smc_set_in_shift(pio, c, shift_right, autopush, push_threshold); pio->chip->smc_set_in_shift(pio, c, shift_right, autopush, push_threshold);
} }
static inline void sm_config_set_out_shift(pio_sm_config *c, bool shift_right, static inline void sm_config_set_out_shift(pio_sm_config *c, bool shift_right, bool autopull, uint pull_threshold)
bool autopull, uint pull_threshold) { {
PIO pio = pio_get_current(); PIO pio = pio_get_current();
pio->chip->smc_set_out_shift(pio, c, shift_right, autopull, pull_threshold); pio->chip->smc_set_out_shift(pio, c, shift_right, autopull, pull_threshold);
} }
static inline void sm_config_set_fifo_join(pio_sm_config *c, static inline void sm_config_set_fifo_join(pio_sm_config *c, enum pio_fifo_join join)
enum pio_fifo_join join) { {
PIO pio = pio_get_current(); PIO pio = pio_get_current();
pio->chip->smc_set_fifo_join(pio, c, join); pio->chip->smc_set_fifo_join(pio, c, join);
} }
static inline void sm_config_set_out_special(pio_sm_config *c, bool sticky, static inline void sm_config_set_out_special(pio_sm_config *c, bool sticky, bool has_enable_pin, uint enable_pin_index)
bool has_enable_pin, {
uint enable_pin_index) {
PIO pio = pio_get_current(); PIO pio = pio_get_current();
pio->chip->smc_set_out_special(pio, c, sticky, has_enable_pin, pio->chip->smc_set_out_special(pio, c, sticky, has_enable_pin, enable_pin_index);
enable_pin_index);
} }
static inline void sm_config_set_mov_status(pio_sm_config *c, static inline void sm_config_set_mov_status(pio_sm_config *c, enum pio_mov_status_type status_sel, uint status_n)
enum pio_mov_status_type status_sel, {
uint status_n) {
PIO pio = pio_get_current(); PIO pio = pio_get_current();
pio->chip->smc_set_mov_status(pio, c, status_sel, status_n); pio->chip->smc_set_mov_status(pio, c, status_sel, status_n);
} }
static inline void pio_gpio_init(PIO pio, uint pin) { static inline void pio_gpio_init(PIO pio, uint pin)
{
check_pio_param(pio); check_pio_param(pio);
pio->chip->pio_gpio_init(pio, pin); pio->chip->pio_gpio_init(pio, pin);
} }
static inline uint32_t clock_get_hz(enum clock_index clk_index) { static inline uint32_t clock_get_hz(enum clock_index clk_index)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
return pio->chip->clock_get_hz(pio, clk_index); return pio->chip->clock_get_hz(pio, clk_index);
} }
static inline void gpio_init(uint gpio) { static inline void gpio_init(uint gpio)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
pio->chip->gpio_init(pio, gpio); pio->chip->gpio_init(pio, gpio);
} }
static inline void gpio_set_function(uint gpio, enum gpio_function fn) { static inline void gpio_set_function(uint gpio, enum gpio_function fn)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
pio->chip->gpio_set_function(pio, gpio, fn); pio->chip->gpio_set_function(pio, gpio, fn);
} }
static inline void gpio_set_pulls(uint gpio, bool up, bool down) {
static inline void gpio_set_pulls(uint gpio, bool up, bool down)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
pio->chip->gpio_set_pulls(pio, gpio, up, down); pio->chip->gpio_set_pulls(pio, gpio, up, down);
} }
static inline void gpio_set_outover(uint gpio, uint value) { static inline void gpio_set_outover(uint gpio, uint value)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
pio->chip->gpio_set_outover(pio, gpio, value); pio->chip->gpio_set_outover(pio, gpio, value);
} }
static inline void gpio_set_inover(uint gpio, uint value) { static inline void gpio_set_inover(uint gpio, uint value)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
pio->chip->gpio_set_inover(pio, gpio, value); pio->chip->gpio_set_inover(pio, gpio, value);
} }
static inline void gpio_set_oeover(uint gpio, uint value) { static inline void gpio_set_oeover(uint gpio, uint value)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
pio->chip->gpio_set_oeover(pio, gpio, value); pio->chip->gpio_set_oeover(pio, gpio, value);
} }
static inline void gpio_set_input_enabled(uint gpio, bool enabled) { static inline void gpio_set_input_enabled(uint gpio, bool enabled)
{
PIO pio = pio_get_current(); PIO pio = pio_get_current();
pio->chip->gpio_set_input_enabled(pio, gpio, enabled); pio->chip->gpio_set_input_enabled(pio, gpio, enabled);
} }
static inline void gpio_set_drive_strength(uint gpio, static inline void gpio_set_drive_strength(uint gpio, enum gpio_drive_strength drive)
enum gpio_drive_strength drive) { {
PIO pio = pio_get_current(); PIO pio = pio_get_current();
pio->chip->gpio_set_drive_strength(pio, gpio, drive); pio->chip->gpio_set_drive_strength(pio, gpio, drive);
} }
@ -814,7 +862,9 @@ static inline void gpio_disable_pulls(uint gpio) {
gpio_set_pulls(gpio, false, false); gpio_set_pulls(gpio, false, false);
} }
static inline void stdio_init_all(void) {} static inline void stdio_init_all(void)
{
}
void sleep_us(uint64_t us); void sleep_us(uint64_t us);

View file

@ -9,8 +9,8 @@
#include "pio_platform.h" #include "pio_platform.h"
#define DECLARE_PIO_CHIP(chip) \ #define DECLARE_PIO_CHIP(chip) \
const PIO_CHIP_T *__ptr_##chip __attribute__((section("piochips"))) \ const PIO_CHIP_T *__ptr_ ## chip __attribute__ ((section ("piochips"))) __attribute__ ((used)) = \
__attribute__((used)) = &chip &chip
#endif #endif

View file

@ -8,16 +8,16 @@
#include <sys/ioctl.h> #include <sys/ioctl.h>
#define RP1_PIO_INSTRUCTION_COUNT 32 #define RP1_PIO_INSTRUCTION_COUNT 32
#define RP1_PIO_SM_COUNT 4 #define RP1_PIO_SM_COUNT 4
#define RP1_PIO_GPIO_COUNT 28 #define RP1_PIO_GPIO_COUNT 28
#define RP1_GPIO_FUNC_PIO 7 #define RP1_GPIO_FUNC_PIO 7
#define RP1_PIO_ORIGIN_ANY ((uint16_t)(~0)) #define RP1_PIO_ORIGIN_ANY ((uint16_t)(~0))
#define RP1_PIO_DIR_TO_SM 0 #define RP1_PIO_DIR_TO_SM 0
#define RP1_PIO_DIR_FROM_SM 1 #define RP1_PIO_DIR_FROM_SM 1
#define RP1_PIO_DIR_COUNT 2 #define RP1_PIO_DIR_COUNT 2
typedef struct { typedef struct {
uint32_t clkdiv; uint32_t clkdiv;
@ -125,12 +125,12 @@ struct rp1_pio_sm_set_dmactrl_args {
}; };
struct rp1_pio_sm_fifo_state_args { struct rp1_pio_sm_fifo_state_args {
uint16_t sm; uint16_t sm;
uint8_t tx; uint8_t tx;
uint8_t rsvd; uint8_t rsvd;
uint16_t level; /* OUT */ uint16_t level; /* OUT */
uint8_t empty; /* OUT */ uint8_t empty; /* OUT */
uint8_t full; /* OUT */ uint8_t full; /* OUT */
}; };
struct rp1_gpio_init_args { struct rp1_gpio_init_args {
@ -160,10 +160,25 @@ struct rp1_pio_sm_config_xfer_args {
uint16_t buf_count; uint16_t buf_count;
}; };
struct rp1_pio_sm_config_xfer32_args {
uint16_t sm;
uint16_t dir;
uint32_t buf_size;
uint32_t buf_count;
};
struct rp1_pio_sm_xfer_data_args { struct rp1_pio_sm_xfer_data_args {
uint16_t sm; uint16_t sm;
uint16_t dir; uint16_t dir;
uint16_t data_bytes; uint16_t data_bytes;
uint16_t rsvd;
void *data;
};
struct rp1_pio_sm_xfer_data32_args {
uint16_t sm;
uint16_t dir;
uint32_t data_bytes;
void *data; void *data;
}; };
@ -175,75 +190,47 @@ struct rp1_access_hw_args {
#define PIO_IOC_MAGIC 102 #define PIO_IOC_MAGIC 102
#define PIO_IOC_SM_CONFIG_XFER \ #define PIO_IOC_SM_CONFIG_XFER _IOW(PIO_IOC_MAGIC, 0, struct rp1_pio_sm_config_xfer_args)
_IOW(PIO_IOC_MAGIC, 0, struct rp1_pio_sm_config_xfer_args) #define PIO_IOC_SM_XFER_DATA _IOW(PIO_IOC_MAGIC, 1, struct rp1_pio_sm_xfer_data_args)
#define PIO_IOC_SM_XFER_DATA \ #define PIO_IOC_SM_XFER_DATA32 _IOW(PIO_IOC_MAGIC, 2, struct rp1_pio_sm_xfer_data32_args)
_IOW(PIO_IOC_MAGIC, 1, struct rp1_pio_sm_xfer_data_args) #define PIO_IOC_SM_CONFIG_XFER32 _IOW(PIO_IOC_MAGIC, 3, struct rp1_pio_sm_config_xfer32_args)
#ifdef CONFIG_COMPAT
// XXX #define PIO_IOC_SM_XFER_DATA32 _IOW(PIO_IOC_MAGIC, 2, struct
// pio_sm_xfer_data_args)
#endif
#define PIO_IOC_READ_HW _IOW(PIO_IOC_MAGIC, 8, struct rp1_access_hw_args) #define PIO_IOC_READ_HW _IOW(PIO_IOC_MAGIC, 8, struct rp1_access_hw_args)
#define PIO_IOC_WRITE_HW _IOW(PIO_IOC_MAGIC, 9, struct rp1_access_hw_args) #define PIO_IOC_WRITE_HW _IOW(PIO_IOC_MAGIC, 9, struct rp1_access_hw_args)
#define PIO_IOC_CAN_ADD_PROGRAM \ #define PIO_IOC_CAN_ADD_PROGRAM _IOW(PIO_IOC_MAGIC, 10, struct rp1_pio_add_program_args)
_IOW(PIO_IOC_MAGIC, 10, struct rp1_pio_add_program_args) #define PIO_IOC_ADD_PROGRAM _IOW(PIO_IOC_MAGIC, 11, struct rp1_pio_add_program_args)
#define PIO_IOC_ADD_PROGRAM \ #define PIO_IOC_REMOVE_PROGRAM _IOW(PIO_IOC_MAGIC, 12, struct rp1_pio_remove_program_args)
_IOW(PIO_IOC_MAGIC, 11, struct rp1_pio_add_program_args)
#define PIO_IOC_REMOVE_PROGRAM \
_IOW(PIO_IOC_MAGIC, 12, struct rp1_pio_remove_program_args)
#define PIO_IOC_CLEAR_INSTR_MEM _IO(PIO_IOC_MAGIC, 13) #define PIO_IOC_CLEAR_INSTR_MEM _IO(PIO_IOC_MAGIC, 13)
#define PIO_IOC_SM_CLAIM _IOW(PIO_IOC_MAGIC, 20, struct rp1_pio_sm_claim_args) #define PIO_IOC_SM_CLAIM _IOW(PIO_IOC_MAGIC, 20, struct rp1_pio_sm_claim_args)
#define PIO_IOC_SM_UNCLAIM _IOW(PIO_IOC_MAGIC, 21, struct rp1_pio_sm_claim_args) #define PIO_IOC_SM_UNCLAIM _IOW(PIO_IOC_MAGIC, 21, struct rp1_pio_sm_claim_args)
#define PIO_IOC_SM_IS_CLAIMED \ #define PIO_IOC_SM_IS_CLAIMED _IOW(PIO_IOC_MAGIC, 22, struct rp1_pio_sm_claim_args)
_IOW(PIO_IOC_MAGIC, 22, struct rp1_pio_sm_claim_args)
#define PIO_IOC_SM_INIT _IOW(PIO_IOC_MAGIC, 30, struct rp1_pio_sm_init_args) #define PIO_IOC_SM_INIT _IOW(PIO_IOC_MAGIC, 30, struct rp1_pio_sm_init_args)
#define PIO_IOC_SM_SET_CONFIG \ #define PIO_IOC_SM_SET_CONFIG _IOW(PIO_IOC_MAGIC, 31, struct rp1_pio_sm_set_config_args)
_IOW(PIO_IOC_MAGIC, 31, struct rp1_pio_sm_set_config_args)
#define PIO_IOC_SM_EXEC _IOW(PIO_IOC_MAGIC, 32, struct rp1_pio_sm_exec_args) #define PIO_IOC_SM_EXEC _IOW(PIO_IOC_MAGIC, 32, struct rp1_pio_sm_exec_args)
#define PIO_IOC_SM_CLEAR_FIFOS \ #define PIO_IOC_SM_CLEAR_FIFOS _IOW(PIO_IOC_MAGIC, 33, struct rp1_pio_sm_clear_fifos_args)
_IOW(PIO_IOC_MAGIC, 33, struct rp1_pio_sm_clear_fifos_args) #define PIO_IOC_SM_SET_CLKDIV _IOW(PIO_IOC_MAGIC, 34, struct rp1_pio_sm_set_clkdiv_args)
#define PIO_IOC_SM_SET_CLKDIV \ #define PIO_IOC_SM_SET_PINS _IOW(PIO_IOC_MAGIC, 35, struct rp1_pio_sm_set_pins_args)
_IOW(PIO_IOC_MAGIC, 34, struct rp1_pio_sm_set_clkdiv_args) #define PIO_IOC_SM_SET_PINDIRS _IOW(PIO_IOC_MAGIC, 36, struct rp1_pio_sm_set_pindirs_args)
#define PIO_IOC_SM_SET_PINS \ #define PIO_IOC_SM_SET_ENABLED _IOW(PIO_IOC_MAGIC, 37, struct rp1_pio_sm_set_enabled_args)
_IOW(PIO_IOC_MAGIC, 35, struct rp1_pio_sm_set_pins_args) #define PIO_IOC_SM_RESTART _IOW(PIO_IOC_MAGIC, 38, struct rp1_pio_sm_restart_args)
#define PIO_IOC_SM_SET_PINDIRS \ #define PIO_IOC_SM_CLKDIV_RESTART _IOW(PIO_IOC_MAGIC, 39, struct rp1_pio_sm_restart_args)
_IOW(PIO_IOC_MAGIC, 36, struct rp1_pio_sm_set_pindirs_args) #define PIO_IOC_SM_ENABLE_SYNC _IOW(PIO_IOC_MAGIC, 40, struct rp1_pio_sm_enable_sync_args)
#define PIO_IOC_SM_SET_ENABLED \
_IOW(PIO_IOC_MAGIC, 37, struct rp1_pio_sm_set_enabled_args)
#define PIO_IOC_SM_RESTART \
_IOW(PIO_IOC_MAGIC, 38, struct rp1_pio_sm_restart_args)
#define PIO_IOC_SM_CLKDIV_RESTART \
_IOW(PIO_IOC_MAGIC, 39, struct rp1_pio_sm_restart_args)
#define PIO_IOC_SM_ENABLE_SYNC \
_IOW(PIO_IOC_MAGIC, 40, struct rp1_pio_sm_enable_sync_args)
#define PIO_IOC_SM_PUT _IOW(PIO_IOC_MAGIC, 41, struct rp1_pio_sm_put_args) #define PIO_IOC_SM_PUT _IOW(PIO_IOC_MAGIC, 41, struct rp1_pio_sm_put_args)
#define PIO_IOC_SM_GET _IOWR(PIO_IOC_MAGIC, 42, struct rp1_pio_sm_get_args) #define PIO_IOC_SM_GET _IOWR(PIO_IOC_MAGIC, 42, struct rp1_pio_sm_get_args)
#define PIO_IOC_SM_SET_DMACTRL \ #define PIO_IOC_SM_SET_DMACTRL _IOW(PIO_IOC_MAGIC, 43, struct rp1_pio_sm_set_dmactrl_args)
_IOW(PIO_IOC_MAGIC, 43, struct rp1_pio_sm_set_dmactrl_args) #define PIO_IOC_SM_FIFO_STATE _IOW(PIO_IOC_MAGIC, 44, struct rp1_pio_sm_fifo_state_args)
#define PIO_IOC_SM_FIFO_STATE \ #define PIO_IOC_SM_DRAIN_TX _IOW(PIO_IOC_MAGIC, 45, struct rp1_pio_sm_clear_fifos_args)
_IOW(PIO_IOC_MAGIC, 44, struct rp1_pio_sm_fifo_state_args)
#define PIO_IOC_SM_DRAIN_TX \
_IOW(PIO_IOC_MAGIC, 45, struct rp1_pio_sm_clear_fifos_args)
#define PIO_IOC_GPIO_INIT _IOW(PIO_IOC_MAGIC, 50, struct rp1_gpio_init_args) #define PIO_IOC_GPIO_INIT _IOW(PIO_IOC_MAGIC, 50, struct rp1_gpio_init_args)
#define PIO_IOC_GPIO_SET_FUNCTION \ #define PIO_IOC_GPIO_SET_FUNCTION _IOW(PIO_IOC_MAGIC, 51, struct rp1_gpio_set_function_args)
_IOW(PIO_IOC_MAGIC, 51, struct rp1_gpio_set_function_args) #define PIO_IOC_GPIO_SET_PULLS _IOW(PIO_IOC_MAGIC, 52, struct rp1_gpio_set_pulls_args)
#define PIO_IOC_GPIO_SET_PULLS \ #define PIO_IOC_GPIO_SET_OUTOVER _IOW(PIO_IOC_MAGIC, 53, struct rp1_gpio_set_args)
_IOW(PIO_IOC_MAGIC, 52, struct rp1_gpio_set_pulls_args) #define PIO_IOC_GPIO_SET_INOVER _IOW(PIO_IOC_MAGIC, 54, struct rp1_gpio_set_args)
#define PIO_IOC_GPIO_SET_OUTOVER \ #define PIO_IOC_GPIO_SET_OEOVER _IOW(PIO_IOC_MAGIC, 55, struct rp1_gpio_set_args)
_IOW(PIO_IOC_MAGIC, 53, struct rp1_gpio_set_args) #define PIO_IOC_GPIO_SET_INPUT_ENABLED _IOW(PIO_IOC_MAGIC, 56, struct rp1_gpio_set_args)
#define PIO_IOC_GPIO_SET_INOVER \ #define PIO_IOC_GPIO_SET_DRIVE_STRENGTH _IOW(PIO_IOC_MAGIC, 57, struct rp1_gpio_set_args)
_IOW(PIO_IOC_MAGIC, 54, struct rp1_gpio_set_args)
#define PIO_IOC_GPIO_SET_OEOVER \
_IOW(PIO_IOC_MAGIC, 55, struct rp1_gpio_set_args)
#define PIO_IOC_GPIO_SET_INPUT_ENABLED \
_IOW(PIO_IOC_MAGIC, 56, struct rp1_gpio_set_args)
#define PIO_IOC_GPIO_SET_DRIVE_STRENGTH \
_IOW(PIO_IOC_MAGIC, 57, struct rp1_gpio_set_args)
#endif #endif

File diff suppressed because it is too large Load diff

View file

@ -28,26 +28,33 @@ static PIO pio_instances[PIO_MAX_INSTANCES];
static uint num_instances; static uint num_instances;
static pthread_mutex_t pio_handle_lock; static pthread_mutex_t pio_handle_lock;
void pio_select(PIO pio) { __pio = pio; } void pio_select(PIO pio)
{
__pio = pio;
}
PIO pio_get_current(void) { PIO pio_get_current(void)
{
PIO pio = __pio; PIO pio = __pio;
check_pio_param(pio); check_pio_param(pio);
return pio; return pio;
} }
int pio_get_index(PIO pio) { int pio_get_index(PIO pio)
{
int i; int i;
for (i = 0; i < PIO_MAX_INSTANCES; i++) { for (i = 0; i < PIO_MAX_INSTANCES; i++)
{
if (pio == pio_instances[i]) if (pio == pio_instances[i])
return i; return i;
} }
return -1; return -1;
} }
int pio_init(void) { int pio_init(void)
{
static bool initialised; static bool initialised;
const PIO_CHIP_T *const *p; const PIO_CHIP_T * const *p;
uint i = 0; uint i = 0;
int err; int err;
@ -55,7 +62,8 @@ int pio_init(void) {
return 0; return 0;
num_instances = 0; num_instances = 0;
p = &__start_piochips; p = &__start_piochips;
while (p < &__stop_piochips && num_instances < PIO_MAX_INSTANCES) { while (p < &__stop_piochips && num_instances < PIO_MAX_INSTANCES)
{
PIO_CHIP_T *chip = *p; PIO_CHIP_T *chip = *p;
PIO pio = chip->create_instance(chip, i); PIO pio = chip->create_instance(chip, i);
if (pio && !PIO_IS_ERR(pio)) { if (pio && !PIO_IS_ERR(pio)) {
@ -75,7 +83,8 @@ int pio_init(void) {
return 0; return 0;
} }
PIO pio_open(uint idx) { PIO pio_open(uint idx)
{
PIO pio = NULL; PIO pio = NULL;
int err; int err;
@ -112,7 +121,8 @@ PIO pio_open(uint idx) {
return pio; return pio;
} }
PIO pio_open_by_name(const char *name) { PIO pio_open_by_name(const char *name)
{
int err = -ENOENT; int err = -ENOENT;
uint i; uint i;
@ -132,33 +142,38 @@ PIO pio_open_by_name(const char *name) {
return pio_open(i); return pio_open(i);
} }
PIO pio_open_helper(uint idx) { PIO pio_open_helper(uint idx)
{
PIO pio = pio_instances[idx]; PIO pio = pio_instances[idx];
if (!pio || !pio->in_use) { if (!pio || !pio->in_use) {
pio = pio_open(idx); pio = pio_open(idx);
if (PIO_IS_ERR(pio)) { if (PIO_IS_ERR(pio)) {
printf("* Failed to open PIO device %d (error %d)\n", idx, printf("* Failed to open PIO device %d (error %d)\n",
PIO_ERR_VAL(pio)); idx, PIO_ERR_VAL(pio));
exit(1); exit(1);
} }
} }
return pio; return pio;
} }
void pio_close(PIO pio) { void pio_close(PIO pio)
{
pio->chip->close_instance(pio); pio->chip->close_instance(pio);
pthread_mutex_lock(&pio_handle_lock); pthread_mutex_lock(&pio_handle_lock);
pio->in_use = 0; pio->in_use = 0;
pthread_mutex_unlock(&pio_handle_lock); pthread_mutex_unlock(&pio_handle_lock);
} }
void pio_panic(const char *msg) { void pio_panic(const char *msg)
{
fprintf(stderr, "PANIC: %s\n", msg); fprintf(stderr, "PANIC: %s\n", msg);
exit(1); exit(1);
} }
void sleep_us(uint64_t us) { void sleep_us(uint64_t us) {
const struct timespec tv = {.tv_sec = (us / 1000000), const struct timespec tv = {
.tv_nsec = 1000ull * (us % 1000000)}; .tv_sec = (us / 1000000),
.tv_nsec = 1000ull * (us % 1000000)
};
nanosleep(&tv, NULL); nanosleep(&tv, NULL);
} }

View file

@ -4,6 +4,7 @@
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <ctime> #include <ctime>
#include <map>
#include <vector> #include <vector>
#include "piomatter/piomatter.h" #include "piomatter/piomatter.h"
@ -61,7 +62,7 @@ uint32_t pixels[height][width] = {
#undef w #undef w
#undef _ #undef _
#define rgb(r, g, b) ((r << 16) | (g << 8) | b) #define rgb(r, g, b) (((r) << 16) | ((g) << 8) | (b))
uint32_t colorwheel(int i) { uint32_t colorwheel(int i) {
i = i & 0xff; i = i & 0xff;
@ -102,28 +103,42 @@ static void print_dither_schedule(const piomatter::schedule_sequence &ss) {
} }
printf("\n"); printf("\n");
} }
printf(" -> ");
std::map<int, int> sums;
for (auto s : ss) {
for (auto i : s) {
sums[-i.shift] += i.active_time;
}
}
for (auto const &i : sums) {
printf("{%d %d} ", -i.first, i.second);
}
printf("\n"); printf("\n");
} }
static void test_simple_dither_schedule(int n_planes, int pixels_across) { static void test_simple_dither_schedule(int n_planes, int pixels_across) {
auto ss = piomatter::make_simple_schedule(n_planes, pixels_across); auto ss = piomatter::make_simple_schedule(n_planes, pixels_across);
print_dither_schedule(ss); print_dither_schedule(ss);
printf("\n");
} }
static void test_temporal_dither_schedule(int n_planes, int pixels_across, static void test_temporal_dither_schedule(int n_planes, int pixels_across,
int n_temporal_frames) { int n_temporal_frames) {
auto ss = piomatter::make_temporal_dither_schedule(n_planes, pixels_across, auto ss = piomatter::make_temporal_dither_schedule(n_planes, pixels_across,
n_temporal_frames); n_temporal_frames);
print_dither_schedule(ss); print_dither_schedule(ss);
printf("\n");
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
int n = argc > 1 ? atoi(argv[1]) : 0; int n = argc > 1 ? atoi(argv[1]) : 0;
test_simple_dither_schedule(5, 1); test_simple_dither_schedule(7, 1);
test_temporal_dither_schedule(5, 1, 0); test_temporal_dither_schedule(7, 1, 2);
test_temporal_dither_schedule(5, 1, 2); test_temporal_dither_schedule(7, 1, 3);
test_temporal_dither_schedule(5, 1, 4); test_temporal_dither_schedule(7, 1, 4);
test_temporal_dither_schedule(7, 1, 5);
return 0;
test_simple_dither_schedule(6, 1); test_simple_dither_schedule(6, 1);
test_temporal_dither_schedule(6, 1, 0); test_temporal_dither_schedule(6, 1, 0);
test_temporal_dither_schedule(6, 1, 2); test_temporal_dither_schedule(6, 1, 2);
@ -131,6 +146,7 @@ int main(int argc, char **argv) {
test_simple_dither_schedule(5, 16); test_simple_dither_schedule(5, 16);
test_temporal_dither_schedule(5, 16, 2); test_temporal_dither_schedule(5, 16, 2);
test_temporal_dither_schedule(5, 16, 3);
test_temporal_dither_schedule(5, 16, 4); test_temporal_dither_schedule(5, 16, 4);
test_simple_dither_schedule(5, 24); test_simple_dither_schedule(5, 24);
@ -140,6 +156,8 @@ int main(int argc, char **argv) {
test_simple_dither_schedule(10, 24); test_simple_dither_schedule(10, 24);
test_temporal_dither_schedule(10, 24, 8); test_temporal_dither_schedule(10, 24, 8);
test_temporal_dither_schedule(5, 128, 3);
test_temporal_dither_schedule(5, 192, 3);
test_temporal_dither_schedule(5, 128, 4); test_temporal_dither_schedule(5, 128, 4);
test_temporal_dither_schedule(5, 192, 4); test_temporal_dither_schedule(5, 192, 4);
return 0; return 0;

View file

@ -166,9 +166,11 @@ The number of pixels in the shift register is automatically computed from these
layout. Decreasing ``n_planes`` can increase FPS at the cost of reduced color fidelity. layout. Decreasing ``n_planes`` can increase FPS at the cost of reduced color fidelity.
The default, 10, is the maximum value. The default, 10, is the maximum value.
``n_temporal_planes`` controls temporal dithering of the panel. The acceptable values ``n_temporal_planes`` controls temporal dithering of the panel.
are 0 (the default), 2, and 4. A higher setting can increase FPS at the cost of 0 or 1 behave the same: All `n_planes` are transmitted every time.
slightly increasing the variation of brightness across subsequent frames. A higher value sets the number of planes that are only transmitted every `1/n_temporal_frames` times.
A higher setting can increase FPS at the cost of slightly increasing the variation of brightness across subsequent frames.
Settings above 4 are allowed, but generally do not give good results.
For simple panels with just 1 connector (2 color lanes), the following constructor arguments are available: For simple panels with just 1 connector (2 color lanes), the following constructor arguments are available: