Compare commits

..

No commits in common. "main" and "make-package" have entirely different histories.

29 changed files with 2510 additions and 2566 deletions

View file

@ -50,7 +50,7 @@ jobs:
submodules: true
fetch-depth: 0
- uses: pypa/cibuildwheel@v2.23.0
- uses: pypa/cibuildwheel@v2.22.0
env:
CIBW_ARCHS_LINUX: ${{ matrix.arch_linux }}
CIBW_BUILD: "cp311-manylinux* cp312-manylinux* cp313-manylinux*"

View file

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

View file

@ -35,6 +35,21 @@ with open("/sys/class/graphics/fb0/stride") as f:
linux_framebuffer = np.memmap('/dev/fb0',mode='r', shape=(screeny, stride // bytes_per_pixel), dtype=dtype)
def make_pixelmap_multilane(width, height, n_addr_lines, n_lanes):
calc_height = n_lanes << n_addr_lines
if height != calc_height:
raise RuntimeError(f"Calculated height {calc_height} does not match requested height {height}")
n_addr = 1 << n_addr_lines
m = []
for addr in range(n_addr):
for x in range(width):
for lane in range(n_lanes):
y = addr + lane * n_addr
m.append(x + width * y)
print(m)
return m
@click.command
@click.option("--x-offset", "xoffset", type=int, help="The x offset of top left corner of the region to mirror", default=0)
@click.option("--y-offset", "yoffset", type=int, help="The y offset of top left corner of the region to mirror", default=0)
@ -44,7 +59,7 @@ def main(xoffset, yoffset, width, height, serpentine, rotation, pinout, n_planes
pixelmap = simple_multilane_mapper(width, height, n_addr_lines, n_lanes)
geometry = piomatter.Geometry(width=width, height=height, n_planes=n_planes, n_addr_lines=n_addr_lines, n_temporal_planes=n_temporal_planes, n_lanes=n_lanes, map=pixelmap)
else:
geometry = piomatter.Geometry(width=width, height=height, n_planes=n_planes, n_addr_lines=n_addr_lines, n_temporal_planes=n_temporal_planes, rotation=rotation, serpentine=serpentine)
geometry = piomatter.Geometry(width=width, height=height, n_planes=n_planes, n_addr_lines=n_addr_lines, n_temporal_planes=n_temporal_planes, rotation=rotation)
framebuffer = np.zeros(shape=(geometry.height, geometry.width), dtype=dtype)
matrix = piomatter.PioMatter(colorspace=piomatter.Colorspace.RGB565, pinout=pinout, framebuffer=framebuffer, geometry=geometry)

View file

@ -72,7 +72,7 @@ def main(xoffset, yoffset, scale, width, height, serpentine, rotation, pinout, n
pixelmap = simple_multilane_mapper(width, height, n_addr_lines, n_lanes)
geometry = piomatter.Geometry(width=width, height=height, n_planes=n_planes, n_addr_lines=n_addr_lines, n_temporal_planes=n_temporal_planes, n_lanes=n_lanes, map=pixelmap)
else:
geometry = piomatter.Geometry(width=width, height=height, n_planes=n_planes, n_temporal_planes=n_temporal_planes, n_addr_lines=n_addr_lines, rotation=rotation, serpentine=serpentine)
geometry = piomatter.Geometry(width=width, height=height, n_planes=n_planes, n_temporal_planes=n_temporal_planes, n_addr_lines=n_addr_lines, rotation=rotation)
matrix_framebuffer = np.zeros(shape=(geometry.height, geometry.width, 3), dtype=np.uint8)
matrix = piomatter.PioMatter(colorspace=piomatter.Colorspace.RGB888Packed, pinout=pinout, framebuffer=matrix_framebuffer, geometry=geometry)

View file

@ -30,7 +30,7 @@ pixelmap = simple_multilane_mapper(width, height, n_addr_lines, n_lanes)
geometry = piomatter.Geometry(width=width, height=height, n_addr_lines=n_addr_lines, n_planes=10, n_temporal_planes=4, map=pixelmap, n_lanes=n_lanes)
framebuffer = np.asarray(canvas) + 0 # Make a mutable copy
matrix = piomatter.PioMatter(colorspace=piomatter.Colorspace.RGB888Packed,
pinout=piomatter.Pinout.Active3BGR,
pinout=piomatter.Pinout.Active3,
framebuffer=framebuffer,
geometry=geometry)
@ -66,7 +66,7 @@ def darken_color(hex_color, darkness_factor):
return darkened_hex_color
step_count = 8
step_count = 4
darkness_factor = 0.5
clearing = False

View file

@ -1,46 +0,0 @@
#!/usr/bin/python3
# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""
Display a simple test pattern of 3 shapes on three 64x64 matrix panels
using Active3 compatible connections.
Run like this:
$ python triple_matrix_active3_simpletest.py
"""
import numpy as np
from PIL import Image, ImageDraw
import adafruit_blinka_raspberry_pi5_piomatter as piomatter
from adafruit_blinka_raspberry_pi5_piomatter.pixelmappers import simple_multilane_mapper
width = 64
n_lanes = 6
n_addr_lines = 5
height = n_lanes << n_addr_lines
pen_radius = 1
canvas = Image.new('RGB', (width, height), (0, 0, 0))
draw = ImageDraw.Draw(canvas)
pixelmap = simple_multilane_mapper(width, height, n_addr_lines, n_lanes)
geometry = piomatter.Geometry(width=width, height=height, n_addr_lines=n_addr_lines, n_planes=10, n_temporal_planes=4, map=pixelmap, n_lanes=n_lanes)
framebuffer = np.asarray(canvas) + 0 # Make a mutable copy
matrix = piomatter.PioMatter(colorspace=piomatter.Colorspace.RGB888Packed,
pinout=piomatter.Pinout.Active3,
framebuffer=framebuffer,
geometry=geometry)
draw.rectangle((8, 8, width-8, width-8), fill=0x008800)
draw.circle((32, 64+32), 22, fill=0x880000)
draw.polygon([(32, 136), (54, 180), (10, 180)], fill=0x000088)
framebuffer[:] = np.asarray(canvas)
matrix.show()
input("Press enter to exit")

View file

@ -20,17 +20,18 @@ 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
"""
# To run a nice emulator:
import shlex
from subprocess import Popen
import click
import numpy as np
from PIL import ImageEnhance
from pyvirtualdisplay.smartdisplay import SmartDisplay
import adafruit_blinka_raspberry_pi5_piomatter as piomatter
import adafruit_blinka_raspberry_pi5_piomatter.click as piomatter_click
from adafruit_blinka_raspberry_pi5_piomatter.pixelmappers import simple_multilane_mapper
@click.command
@ -38,38 +39,25 @@ from adafruit_blinka_raspberry_pi5_piomatter.pixelmappers import simple_multilan
@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("--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)
@piomatter_click.standard_options
@click.argument("command", nargs=-1)
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):
def main(scale, backend, use_xauth, extra_args, rfbport, width, height, serpentine, rotation, pinout, n_planes, n_addr_lines, command):
kwargs = {}
if backend == "xvnc":
kwargs['rfbport'] = rfbport
if extra_args:
kwargs['extra_args'] = shlex.split(extra_args)
print("xauth", use_xauth)
if n_lanes != 2:
pixelmap = simple_multilane_mapper(width, height, n_addr_lines, n_lanes)
geometry = piomatter.Geometry(width=width, height=height, n_planes=n_planes, n_addr_lines=n_addr_lines,
n_temporal_planes=n_temporal_planes, n_lanes=n_lanes, map=pixelmap)
else:
geometry = piomatter.Geometry(width=width, height=height, n_planes=n_planes, n_addr_lines=n_addr_lines,
n_temporal_planes=n_temporal_planes, rotation=rotation, serpentine=serpentine)
geometry = piomatter.Geometry(width=width, height=height, n_planes=n_planes, n_addr_lines=n_addr_lines, rotation=rotation)
framebuffer = np.zeros(shape=(geometry.height, geometry.width, 3), dtype=np.uint8)
matrix = piomatter.PioMatter(colorspace=piomatter.Colorspace.RGB888Packed, pinout=pinout, framebuffer=framebuffer, geometry=geometry)
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:
img = disp.grab(autocrop=False)
if img is None:
continue
if brightness != 1.0:
darkener = ImageEnhance.Brightness(img)
img = darkener.enhance(brightness)
img = img.resize((width, height))
framebuffer[:, :] = np.array(img)
matrix.show()

View file

@ -0,0 +1,179 @@
#!/usr/bin/python3
"""
Display a (possibly scaled) X session to a matrix
The display runs until the graphical program exits.
Raw keyboard inputs are read from stdin and then injected into the running programs session with xdotool.
For help with commandline arguments, run `python virtualdisplay.py --help`
This needs additional software to be installed (besides a graphical program to run). At a minimum you have to
install a virtual display server program (xvfb) and the pyvirtualdisplay importable Python module:
$ sudo apt install -y xvfb xdotool
$ pip install pyvirtualdisplay
Here's an example for running an emulator using a rom stored in "/tmp/snesrom.smc" on a virtual 128x128 panel made from 4 64x64 panels:
$ python virtualdisplay_keyboard.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 os
import selectors
import shlex
import string
import sys
import termios
import tty
from subprocess import Popen, run
import click
import numpy as np
from pyvirtualdisplay.smartdisplay import SmartDisplay
import adafruit_blinka_raspberry_pi5_piomatter as piomatter
import adafruit_blinka_raspberry_pi5_piomatter.click as piomatter_click
from adafruit_blinka_raspberry_pi5_piomatter.pixelmappers import simple_multilane_mapper
keyboard_debug = False
keys_down = set()
basic_characters = string.ascii_letters + string.digits
key_map = {
# https://gitlab.com/nokun/gestures/-/wikis/xdotool-list-of-key-codes
b' ': "space",
b'/': "slash",
b'\\': "backslash",
b"'": "apostrophe",
b'\x7f': "BackSpace",
b'.': "period",
b',': "comma",
b'\t': "Tab",
b'\r': "Return",
b'!': "exclam",
b'?': "question",
b'@': "at",
b'<': "less",
b'>': "greater",
b'=': "equal",
b';': "semicolon",
b':': "colon",
b'+': "plus",
b'-': "minus",
b'*': "asterisk",
b'(': "parenleft",
b')': "parenright",
b'&': "ampersand",
b'%': "percent",
b'$': "dollar",
b'#': "numbersign",
b'\x1b[A': "Up",
b'\x1b[B': "Down",
b'\x1b[C': "Right",
b'\x1b[D': "Left",
b'\x1b': "Escape",
b'^': "caret",
b'[': "bracketleft",
b']': "bracketright",
b'{': "braceleft",
b'}': "braceright",
b'_': "underscore",
#b'': "",
}
ctrl_modified_range = (1, 26)
@click.command
@click.option("--scale", type=float, help="The scale factor, larger numbers mean more virtual pixels", default=1)
@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("--rfbport", help="The port number for the --backend xvnc", default=None, type=int)
@click.option("--use-xauth/--no-use-xauth", help="If a Xauthority file should be created", default=False)
@click.option("--ctrl-c-interrupt/--no-ctrl-c-interrupt", help="If Ctrl+C should be handled as an interrupt.", default=True)
@piomatter_click.standard_options
@click.argument("command", nargs=-1)
def main(scale, backend, use_xauth, extra_args, rfbport, width, height, serpentine, rotation, pinout, n_planes, n_temporal_planes,
n_addr_lines, n_lanes, ctrl_c_interrupt, command):
def handle_key_event(evt_data):
if evt_data in key_map.keys():
keys_down.add(key_map[evt_data])
run(["xdotool", "keydown", key_map[evt_data]], env=disp.env())
elif evt_data.decode() in basic_characters:
run(["xdotool", "keydown", f"{evt_data.decode()}"], env=disp.env())
keys_down.add(evt_data.decode())
elif ctrl_modified_range[0] <= int.from_bytes(evt_data) <= ctrl_modified_range[1]:
if evt_data == b'\x03' and ctrl_c_interrupt:
raise KeyboardInterrupt
keys_down.add("Control_L")
run(["xdotool", "keydown", "Control_L"], env=disp.env())
modified_key = chr(int.from_bytes(evt_data) + 96)
if keyboard_debug:
print(f"ctrl modified {modified_key}")
keys_down.add(modified_key)
run(["xdotool", "keydown", modified_key], env=disp.env())
elif len(evt_data) > 1:
if keyboard_debug:
print("recvd multiple")
for char_val in evt_data:
if keyboard_debug:
print(f"{char_val} {chr(char_val)}")
char_bytes = char_val.to_bytes(1)
handle_key_event(char_bytes)
else:
print(f"unknown input data: {evt_data}")
old_settings = termios.tcgetattr(sys.stdin)
selector = selectors.DefaultSelector()
selector.register(fileobj=sys.stdin, events=selectors.EVENT_READ)
tty.setraw(sys.stdin.fileno())
kwargs = {}
if backend == "xvnc":
kwargs['rfbport'] = rfbport
if extra_args:
kwargs['extra_args'] = shlex.split(extra_args)
print("xauth", use_xauth)
if n_lanes != 2:
pixelmap = simple_multilane_mapper(width, height, n_addr_lines, n_lanes)
geometry = piomatter.Geometry(width=width, height=height, n_planes=n_planes, n_addr_lines=n_addr_lines, n_temporal_planes=n_temporal_planes, n_lanes=n_lanes, map=pixelmap)
else:
geometry = piomatter.Geometry(width=width, height=height, n_planes=n_planes, n_temporal_planes=n_temporal_planes, n_addr_lines=n_addr_lines, rotation=rotation)
framebuffer = np.zeros(shape=(geometry.height, geometry.width, 3), dtype=np.uint8)
matrix = piomatter.PioMatter(colorspace=piomatter.Colorspace.RGB888Packed, pinout=pinout, framebuffer=framebuffer,
geometry=geometry)
try:
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:
img = disp.grab(autocrop=False)
# print(disp.env())
if img is None:
continue
img = img.resize((width, height))
framebuffer[:, :] = np.array(img)
matrix.show()
event_count = 0
for key, __ in selector.select(timeout=0):
event_count += 1
# read up 3 bytes, so we full data for arrow keys
kbd_data = os.read(key.fileobj.fileno(), 3)
if keyboard_debug:
print(kbd_data)
handle_key_event(kbd_data)
# no kbd events, so keyup all keys
if event_count == 0:
for key in keys_down:
run(["xdotool", "keyup", key], env=disp.env())
keys_down.clear()
finally:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)
if __name__ == '__main__':
main()

View file

@ -1,83 +0,0 @@
#!/usr/bin/python3
"""
Display a (possibly scaled) X display to a matrix
The display runs until this script exits.
The display doesn't get a keyboard or mouse, so you have to use a program that
will get its input in some other way, such as from a gamepad.
For help with commandline arguments, run `python xdisplay_mirror.py --help`
This example command will mirror the entire display scaled onto a 2x2 grid of 64px panels, total matrix size 128x128.
$ python xdisplay_mirror.py --pinout AdafruitMatrixHatBGR --width 128 --height 128 --serpentine --num-address-lines 5 --num-planes 8
This example command will mirror a 128x128 pixel square from the top left of the display at real size on the same matrix panels
$ python xdisplay_mirror.py --pinout AdafruitMatrixHatBGR --width 128 --height 128 --serpentine --num-address-lines 5 --num-planes 8 --mirror-region 0,0,128,128
"""
import click
import numpy as np
from PIL import Image, ImageEnhance, ImageGrab
import adafruit_blinka_raspberry_pi5_piomatter as piomatter
import adafruit_blinka_raspberry_pi5_piomatter.click as piomatter_click
from adafruit_blinka_raspberry_pi5_piomatter.pixelmappers import simple_multilane_mapper
RESAMPLE_MAP = {
"nearest": Image.NEAREST,
"bilinear": Image.BILINEAR,
"lanczos": Image.LANCZOS,
"bicubic": Image.BICUBIC
}
@click.command
@click.option("--mirror-region", help="Region of X display to mirror. Comma seperated x,y,w,h. "
"Default will mirror entire display.", default="")
@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",
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)
def main(width, height, serpentine, rotation, pinout, n_planes,
n_temporal_planes, n_addr_lines, n_lanes, mirror_region, x_display, resample_method, brightness):
if n_lanes != 2:
pixelmap = simple_multilane_mapper(width, height, n_addr_lines, n_lanes)
geometry = piomatter.Geometry(width=width, height=height, n_planes=n_planes, n_addr_lines=n_addr_lines,
n_temporal_planes=n_temporal_planes, n_lanes=n_lanes, map=pixelmap)
else:
geometry = piomatter.Geometry(width=width, height=height, n_planes=n_planes, n_addr_lines=n_addr_lines,
n_temporal_planes=n_temporal_planes, rotation=rotation, serpentine=serpentine)
framebuffer = np.zeros(shape=(geometry.height, geometry.width, 3), dtype=np.uint8)
matrix = piomatter.PioMatter(colorspace=piomatter.Colorspace.RGB888Packed, pinout=pinout, framebuffer=framebuffer,
geometry=geometry)
if mirror_region:
mirror_region = tuple(int(_) for _ in mirror_region.split(','))
else:
mirror_region = None
size_measure = ImageGrab.grab(xdisplay=":0")
print(f"Mirroring full display: {size_measure.width}, {size_measure.height}")
while True:
img = ImageGrab.grab(xdisplay=x_display)
if mirror_region is not None:
img = img.crop((mirror_region[0], mirror_region[1], # left,top
mirror_region[0] + mirror_region[2], # right
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])
framebuffer[:, :] = np.array(img)
matrix.show()
if __name__ == '__main__':
main()

View file

@ -1,20 +0,0 @@
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)

7
src/Makefile Normal file
View file

@ -0,0 +1,7 @@
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
def _validate_temporal_planes(ctx, param, value):
if value not in (0, 1, 2, 3, 4, 5):
raise click.BadParameter("must be from 0 to 5 (0 and 1 both disable temporal planes)")
if value not in (0, 2, 4):
raise click.BadParameter("must be 0, 2, or 4")
return value
def standard_options(

View file

@ -27,4 +27,5 @@ def simple_multilane_mapper(width, height, n_addr_lines, n_lanes):
for lane in range(n_lanes):
y = addr + lane * n_addr
m.append(x + width * y)
print(m)
return m

View file

@ -134,27 +134,47 @@ schedule_sequence make_temporal_dither_schedule(int n_planes,
if (n_temporal_planes >= 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;
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;
auto add_sched = [&result, n_real_planes,
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);
}
auto add_sched = [&result, &base_sched](int plane, int count) {
auto sched = base_sched;
sched.emplace_back(9 - plane, count);
result.emplace_back(sched);
};
for (int i = 0; i < n_temporal_planes; i++) {
add_sched(i, n_real_planes + i, 1 << (n_temporal_planes - i - 1));
add_sched(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);
;
}
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_latch_delay = 0;
static constexpr uint32_t post_addr_delay = 5;
static constexpr uint32_t post_addr_delay = 500;
};
struct adafruit_matrix_bonnet_pinout_bgr {
@ -37,29 +37,10 @@ struct adafruit_matrix_bonnet_pinout_bgr {
static constexpr uint32_t post_oe_delay = 0;
static constexpr uint32_t post_latch_delay = 0;
static constexpr uint32_t post_addr_delay = 5;
static constexpr uint32_t post_addr_delay = 500;
};
struct active3_pinout {
static constexpr pin_t PIN_RGB[] = {11, 27, 7, 8, 9, 10, 12, 5, 6,
19, 13, 20, 14, 2, 3, 26, 16, 21};
static constexpr pin_t PIN_ADDR[] = {22, 23, 24, 25, 15};
static constexpr pin_t PIN_OE = 18; // /OE: output enable when LOW
static constexpr pin_t PIN_CLK = 17; // SRCLK: clocks on RISING edge
static constexpr pin_t PIN_LAT = 4; // RCLK: latches on RISING edge
static constexpr uint32_t clk_bit = 1u << PIN_CLK;
static constexpr uint32_t lat_bit = 1u << PIN_LAT;
static constexpr uint32_t oe_bit = 1u << PIN_OE;
static constexpr uint32_t oe_active = 0;
static constexpr uint32_t oe_inactive = oe_bit;
static constexpr uint32_t post_oe_delay = 0;
static constexpr uint32_t post_latch_delay = 0;
static constexpr uint32_t post_addr_delay = 5;
};
struct active3_pinout_bgr {
static constexpr pin_t PIN_RGB[] = {7, 27, 11, 10, 9, 8, 6, 5, 12,
20, 13, 19, 3, 2, 14, 21, 16, 26};
static constexpr pin_t PIN_ADDR[] = {22, 23, 24, 25, 15};
@ -75,7 +56,26 @@ struct active3_pinout_bgr {
static constexpr uint32_t post_oe_delay = 0;
static constexpr uint32_t post_latch_delay = 0;
static constexpr uint32_t post_addr_delay = 5;
static constexpr uint32_t post_addr_delay = 500;
};
struct active3_pinout_bgr {
static constexpr pin_t PIN_RGB[] = {11, 27, 7, 8, 9, 10, 12, 5, 6,
19, 13, 20, 14, 2, 3, 26, 16, 21};
static constexpr pin_t PIN_ADDR[] = {22, 23, 24, 25, 15};
static constexpr pin_t PIN_OE = 18; // /OE: output enable when LOW
static constexpr pin_t PIN_CLK = 17; // SRCLK: clocks on RISING edge
static constexpr pin_t PIN_LAT = 4; // RCLK: latches on RISING edge
static constexpr uint32_t clk_bit = 1u << PIN_CLK;
static constexpr uint32_t lat_bit = 1u << PIN_LAT;
static constexpr uint32_t oe_bit = 1u << PIN_OE;
static constexpr uint32_t oe_active = 0;
static constexpr uint32_t oe_inactive = oe_bit;
static constexpr uint32_t post_oe_delay = 0;
static constexpr uint32_t post_latch_delay = 0;
static constexpr uint32_t post_addr_delay = 500;
};
} // namespace piomatter

View file

@ -12,42 +12,6 @@
namespace piomatter {
static int pio_sm_xfer_data_large(PIO pio, int sm, int direction, size_t size,
uint32_t *databuf) {
#if 0
// it would be NICE to gracefully fall back to blocked transfer, but sadly
// once the large xfer ioctl fails, future small xfers fail too.
static enum { UNKNOWN, OK, BAD } large_xfer_status = UNKNOWN;
printf("large_xfer_status=%d\n", large_xfer_status);
if (large_xfer_status != BAD) {
int r = pio_sm_xfer_data(pio, sm, direction, size, databuf);
if (large_xfer_status == UNKNOWN && r != 0) {
large_xfer_status = BAD;
fprintf(stderr,
"Transmission limit workaround engaged. May reduce quality of "
"output.\nSee https://github.com/raspberrypi/utils/issues/123 "
"for details.\n");
} else {
if (large_xfer_status == UNKNOWN && r == 0) {
large_xfer_status = OK;
}
return r;
}
}
#endif
constexpr size_t MAX_XFER = 65532;
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 != 0) {
return r;
}
size -= xfersize;
databuf += xfersize / sizeof(*databuf);
}
return 0;
}
static uint64_t monotonicns64() {
struct timespec tp;
clock_gettime(CLOCK_MONOTONIC, &tp);
@ -56,13 +20,27 @@ static uint64_t monotonicns64() {
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 {
piomatter_base() {}
piomatter_base(const piomatter_base &) = delete;
piomatter_base &operator=(const piomatter_base &) = delete;
virtual ~piomatter_base() {}
virtual int show() = 0;
virtual void show() = 0;
double fps;
};
@ -84,11 +62,7 @@ struct piomatter : piomatter_base {
show();
}
int show() override {
int err = pending_error_errno.exchange(0); // we're handling this error
if (err != 0) {
return err;
}
void show() override {
int buffer_idx = manager.get_free_buffer();
auto &bufseq = buffers[buffer_idx];
bufseq.resize(geometry.schedules.size());
@ -101,7 +75,6 @@ struct piomatter : piomatter_base {
old_active_time = geometry.schedules[i].back().active_time;
}
manager.put_filled_buffer(buffer_idx);
return 0;
}
~piomatter() {
@ -133,7 +106,7 @@ struct piomatter : piomatter_base {
if (sm < 0) {
throw std::runtime_error("pio_claim_unused_sm");
}
int r = pio_sm_config_xfer(pio, sm, PIO_DIR_TO_SM, MAX_XFER, 3);
int r = pio_sm_config_xfer(pio, sm, PIO_DIR_TO_SM, MAX_XFER, 2);
if (r) {
throw std::runtime_error("pio_sm_config_xfer");
}
@ -215,15 +188,8 @@ struct piomatter : piomatter_base {
const auto &data = cur_buf[seq_idx];
auto datasize = sizeof(uint32_t) * data.size();
auto dataptr = const_cast<uint32_t *>(&data[0]);
// returns err = rp1_ioctl.... which seems to be a negative
// errno value
int r = pio_sm_xfer_data_large(pio, sm, PIO_DIR_TO_SM, datasize,
dataptr);
if (r != 0) {
pending_error_errno.store(errno);
printf("xfer_data() returned error %d (errno=%s)\n", r,
strerror(errno));
}
pio_sm_xfer_data_large(pio, sm, PIO_DIR_TO_SM, datasize,
dataptr);
t1 = monotonicns64();
if (t0 != t1) {
fps = 1e9 / (t1 - t0);
@ -243,7 +209,6 @@ struct piomatter : piomatter_base {
matrix_geometry geometry;
colorspace converter;
std::thread blitter_thread;
std::atomic<int> pending_error_errno;
};
} // namespace piomatter

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

@ -1,11 +0,0 @@
// 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,17 +25,27 @@
#define PARAM_ASSERTIONS_DISABLE_ALL 0
#endif
#define PARAM_ASSERTIONS_ENABLED(x) ((PARAM_ASSERTIONS_ENABLED_ ## x || PARAM_ASSERTIONS_ENABLE_ALL) && !PARAM_ASSERTIONS_DISABLE_ALL)
#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 PARAM_ASSERTIONS_ENABLED(x) \
((PARAM_ASSERTIONS_ENABLED_##x || PARAM_ASSERTIONS_ENABLE_ALL) && \
!PARAM_ASSERTIONS_DISABLE_ALL)
#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 _u(x) ((uint)(x))
#define bool_to_bit(x) ((uint)!!(x))
#define bool_to_bit(x) ((uint) !!(x))
#ifndef count_of
#define count_of(a) (sizeof(a)/sizeof((a)[0]))
#define count_of(a) (sizeof(a) / sizeof((a)[0]))
#endif
typedef unsigned int uint;

View file

@ -11,39 +11,32 @@
extern "C" {
#endif
#include "pio_platform.h"
#include "hardware/clocks.h"
#include "hardware/gpio.h"
#include "pio_platform.h"
#ifndef PARAM_ASSERTIONS_ENABLED_PIO
#define PARAM_ASSERTIONS_ENABLED_PIO 0
#endif
#define PIO_ERR(x)((PIO)(uintptr_t)(x))
#define PIO_IS_ERR(x)(((uintptr_t)(x) >= (uintptr_t)-200))
#define PIO_ERR_VAL(x)((int)(uintptr_t)(x))
#define PIO_ERR(x) ((PIO)(uintptr_t)(x))
#define PIO_IS_ERR(x) (((uintptr_t)(x) >= (uintptr_t)-200))
#define PIO_ERR_VAL(x) ((int)(uintptr_t)(x))
#define PIO_ORIGIN_ANY ((uint)(~0))
#define PIO_ORIGIN_INVALID PIO_ORIGIN_ANY
#define PIO_ORIGIN_ANY ((uint)(~0))
#define PIO_ORIGIN_INVALID PIO_ORIGIN_ANY
#define pio0 pio_open_helper(0)
enum pio_fifo_join {
PIO_FIFO_JOIN_NONE = 0,
PIO_FIFO_JOIN_TX = 1,
PIO_FIFO_JOIN_RX = 2,
PIO_FIFO_JOIN_NONE = 0,
PIO_FIFO_JOIN_TX = 1,
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
@ -60,16 +53,16 @@ enum pio_instr_bits {
};
#ifndef NDEBUG
#define _PIO_INVALID_IN_SRC 0x08u
#define _PIO_INVALID_IN_SRC 0x08u
#define _PIO_INVALID_OUT_DEST 0x10u
#define _PIO_INVALID_SET_DEST 0x20u
#define _PIO_INVALID_MOV_SRC 0x40u
#define _PIO_INVALID_MOV_SRC 0x40u
#define _PIO_INVALID_MOV_DEST 0x80u
#else
#define _PIO_INVALID_IN_SRC 0u
#define _PIO_INVALID_IN_SRC 0u
#define _PIO_INVALID_OUT_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
#endif
@ -78,13 +71,18 @@ enum pio_src_dest {
pio_x = 1u,
pio_y = 2u,
pio_null = 3u | _PIO_INVALID_SET_DEST | _PIO_INVALID_MOV_DEST,
pio_pindirs = 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_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_pindirs =
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_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_osr = 7u | _PIO_INVALID_OUT_DEST | _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_exec_out = 7u | _PIO_INVALID_IN_SRC | _PIO_INVALID_SET_DEST |
_PIO_INVALID_MOV_SRC | _PIO_INVALID_MOV_DEST,
};
#endif
@ -115,12 +113,17 @@ struct pio_chip {
int (*open_instance)(PIO pio);
void (*close_instance)(PIO pio);
int (*pio_sm_config_xfer)(PIO pio, uint sm, uint dir, uint buf_size, uint buf_count);
int (*pio_sm_xfer_data)(PIO pio, uint sm, uint dir, uint data_bytes, void *data);
int (*pio_sm_config_xfer)(PIO pio, uint sm, uint dir, uint buf_size,
uint buf_count);
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, uint offset);
uint (*pio_add_program_at_offset)(PIO pio, const pio_program_t *program, uint offset);
bool (*pio_remove_program)(PIO pio, const pio_program_t *program, uint loaded_offset);
bool (*pio_can_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,
uint offset);
bool (*pio_remove_program)(PIO pio, const pio_program_t *program,
uint loaded_offset);
bool (*pio_clear_instruction_memory)(PIO pio);
uint (*pio_encode_delay)(PIO pio, uint cycles);
uint (*pio_encode_sideset)(PIO pio, uint sideset_bit_count, uint value);
@ -135,14 +138,18 @@ struct pio_chip {
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_pin)(PIO pio, bool polarity, uint pin);
uint (*pio_encode_wait_irq)(PIO pio, bool polarity, bool relative, uint irq);
uint (*pio_encode_wait_irq)(PIO pio, bool polarity, bool relative,
uint irq);
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_push)(PIO pio, bool if_full, bool block);
uint (*pio_encode_pull)(PIO pio, bool if_empty, bool block);
uint (*pio_encode_mov)(PIO pio, enum pio_src_dest dest, 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_reverse)(PIO pio, enum pio_src_dest dest, enum pio_src_dest src);
uint (*pio_encode_mov)(PIO pio, enum pio_src_dest dest,
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_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_wait)(PIO pio, bool relative, uint irq);
uint (*pio_encode_irq_clear)(PIO pio, bool relative, uint irq);
@ -155,16 +162,21 @@ struct pio_chip {
bool (*pio_sm_unclaim)(PIO pio, uint sm);
bool (*pio_sm_is_claimed)(PIO pio, uint sm);
void (*pio_sm_init)(PIO pio, uint sm, uint initial_pc, const pio_sm_config *config);
void (*pio_sm_init)(PIO pio, uint sm, uint initial_pc,
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_clear_fifos)(PIO pio, uint sm);
void (*pio_sm_set_clkdiv_int_frac)(PIO pio, uint sm, uint16_t div_int, uint8_t div_frac);
void (*pio_sm_set_clkdiv_int_frac)(PIO pio, uint sm, uint16_t div_int,
uint8_t div_frac);
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_with_mask)(PIO pio, uint sm, uint32_t pin_values, 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_consecutive_pindirs)(PIO pio, uint sm, uint pin_base, uint pin_count, bool is_out);
void (*pio_sm_set_pins_with_mask)(PIO pio, uint sm, uint32_t pin_values,
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_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_mask)(PIO pio, uint32_t mask, bool enabled);
void (*pio_sm_restart)(PIO pio, uint sm);
@ -184,23 +196,34 @@ struct pio_chip {
void (*pio_sm_drain_tx_fifo)(PIO pio, uint sm);
pio_sm_config (*pio_get_default_sm_config)(PIO pio);
void (*smc_set_out_pins)(PIO pio, pio_sm_config *c, uint out_base, uint out_count);
void (*smc_set_set_pins)(PIO pio, pio_sm_config *c, uint set_base, uint set_count);
void (*smc_set_out_pins)(PIO pio, pio_sm_config *c, uint out_base,
uint out_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_sideset_pins)(PIO pio, pio_sm_config *c, uint sideset_base);
void (*smc_set_sideset)(PIO pio, pio_sm_config *c, uint bit_count, 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_sideset)(PIO pio, pio_sm_config *c, uint bit_count,
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)(PIO pio, pio_sm_config *c, float div);
void (*smc_set_wrap)(PIO pio, pio_sm_config *c, uint wrap_target, uint wrap);
void (*smc_set_wrap)(PIO pio, pio_sm_config *c, uint wrap_target,
uint wrap);
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, 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_fifo_join)(PIO pio, pio_sm_config *c, 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);
void (*smc_set_in_shift)(PIO pio, pio_sm_config *c, bool shift_right,
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_fifo_join)(PIO pio, pio_sm_config *c,
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);
void (*pio_gpio_init)(PIO, uint pin);
void (*pio_gpio_init)(PIO pio, uint pin);
void (*gpio_init)(PIO pio, uint gpio);
void (*gpio_set_function)(PIO pio, uint gpio, enum gpio_function fn);
void (*gpio_set_pulls)(PIO pio, uint gpio, bool up, bool down);
@ -208,7 +231,8 @@ struct pio_chip {
void (*gpio_set_inover)(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_drive_strength)(PIO pio, uint gpio, enum gpio_drive_strength drive);
void (*gpio_set_drive_strength)(PIO pio, uint gpio,
enum gpio_drive_strength drive);
};
struct pio_instance {
@ -228,74 +252,58 @@ int pio_get_index(PIO pio);
void pio_select(PIO pio);
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;
if (pio->errors_are_fatal)
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;
}
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;
}
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);
}
static inline int pio_sm_config_xfer(PIO pio, uint sm, uint dir, uint buf_size, uint buf_count)
{
static inline int pio_sm_config_xfer(PIO pio, uint sm, uint dir, uint buf_size,
uint buf_count) {
check_pio_param(pio);
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, void *data)
{
static inline int pio_sm_xfer_data(PIO pio, uint sm, uint dir, uint data_bytes,
void *data) {
check_pio_param(pio);
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);
return pio->chip->pio_can_add_program_at_offset(pio, program, PIO_ORIGIN_ANY);
return pio->chip->pio_can_add_program_at_offset(pio, program,
PIO_ORIGIN_ANY);
}
static inline bool pio_can_add_program_at_offset(PIO pio, const pio_program_t *program, uint offset)
{
static inline bool pio_can_add_program_at_offset(PIO pio,
const pio_program_t *program,
uint offset) {
check_pio_param(pio);
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;
check_pio_param(pio);
offset = pio->chip->pio_add_program_at_offset(pio, program, PIO_ORIGIN_ANY);
@ -304,548 +312,492 @@ static inline uint pio_add_program(PIO pio, const pio_program_t *program)
return offset;
}
static inline void pio_add_program_at_offset(PIO pio, const pio_program_t *program, uint offset)
{
static inline void
pio_add_program_at_offset(PIO pio, const pio_program_t *program, uint offset) {
check_pio_param(pio);
if (pio->chip->pio_add_program_at_offset(pio, program, offset) == PIO_ORIGIN_INVALID)
if (pio->chip->pio_add_program_at_offset(pio, program, offset) ==
PIO_ORIGIN_INVALID)
pio_error(pio, "No program space");
}
static inline void pio_remove_program(PIO pio, const pio_program_t *program, uint loaded_offset)
{
static inline void pio_remove_program(PIO pio, const pio_program_t *program,
uint loaded_offset) {
check_pio_param(pio);
if (!pio->chip->pio_remove_program(pio, program, loaded_offset))
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);
if (!pio->chip->pio_clear_instruction_memory(pio))
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();
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();
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();
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();
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();
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();
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();
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();
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();
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();
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();
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();
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();
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();
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();
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();
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();
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();
return pio->chip->pio_encode_pull(pio, if_empty, block);
}
static inline uint pio_encode_mov(enum pio_src_dest dest, enum pio_src_dest src)
{
static inline uint pio_encode_mov(enum pio_src_dest dest,
enum pio_src_dest src) {
PIO pio = pio_get_current();
return pio->chip->pio_encode_mov(pio, dest, src);
}
static inline uint pio_encode_mov_not(enum pio_src_dest dest, enum pio_src_dest src)
{
static inline uint pio_encode_mov_not(enum pio_src_dest dest,
enum pio_src_dest src) {
PIO pio = pio_get_current();
return pio->chip->pio_encode_mov_not(pio, dest, src);
}
static inline uint pio_encode_mov_reverse(enum pio_src_dest dest, enum pio_src_dest src)
{
static inline uint pio_encode_mov_reverse(enum pio_src_dest dest,
enum pio_src_dest src) {
PIO pio = pio_get_current();
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();
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();
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();
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();
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();
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);
if (!pio->chip->pio_sm_claim(pio, 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);
if (!pio->chip->pio_sm_claim_mask(pio, mask))
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);
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);
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);
return pio->chip->pio_sm_is_claimed(pio, sm);
}
static inline void pio_sm_init(PIO pio, uint sm, uint initial_pc, const pio_sm_config *config)
{
static inline void pio_sm_init(PIO pio, uint sm, uint initial_pc,
const pio_sm_config *config) {
check_pio_param(pio);
pio->chip->pio_sm_init(pio, sm, initial_pc, config);
}
static inline void pio_sm_set_config(PIO pio, uint sm, const pio_sm_config *config)
{
static inline void pio_sm_set_config(PIO pio, uint sm,
const pio_sm_config *config) {
check_pio_param(pio);
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);
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);
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);
pio->chip->pio_sm_clear_fifos(pio, sm);
}
static inline void pio_sm_set_clkdiv_int_frac(PIO pio, uint sm, uint16_t div_int, uint8_t div_frac)
{
static inline void pio_sm_set_clkdiv_int_frac(PIO pio, uint sm,
uint16_t div_int,
uint8_t div_frac) {
check_pio_param(pio);
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);
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);
pio->chip->pio_sm_set_pins(pio, sm, pin_values);
}
static inline void pio_sm_set_pins_with_mask(PIO pio, uint sm, uint32_t pin_values, uint32_t pin_mask)
{
static inline void pio_sm_set_pins_with_mask(PIO pio, uint sm,
uint32_t pin_values,
uint32_t pin_mask) {
check_pio_param(pio);
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, uint32_t pin_dirs, uint32_t pin_mask)
{
static inline void pio_sm_set_pindirs_with_mask(PIO pio, uint sm,
uint32_t pin_dirs,
uint32_t pin_mask) {
check_pio_param(pio);
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, uint pin_base, uint pin_count, bool is_out)
{
static inline void pio_sm_set_consecutive_pindirs(PIO pio, uint sm,
uint pin_base, uint pin_count,
bool is_out) {
check_pio_param(pio);
pio->chip->pio_sm_set_consecutive_pindirs(pio, sm, pin_base, pin_count, is_out);
pio->chip->pio_sm_set_consecutive_pindirs(pio, sm, pin_base, pin_count,
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);
pio->chip->pio_sm_set_enabled(pio, sm, enabled);
}
static inline void pio_set_sm_mask_enabled(PIO pio, uint32_t mask, bool enabled)
{
static inline void pio_set_sm_mask_enabled(PIO pio, uint32_t mask,
bool enabled) {
check_pio_param(pio);
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);
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);
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);
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);
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);
pio->chip->pio_sm_enable_sync(pio, mask);
};
static inline void pio_sm_set_dmactrl(PIO pio, uint sm, bool is_tx, uint32_t ctrl)
{
static inline void pio_sm_set_dmactrl(PIO pio, uint sm, bool is_tx,
uint32_t ctrl) {
check_pio_param(pio);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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();
return pio->chip->pio_get_default_sm_config(pio);
}
static inline void sm_config_set_out_pins(pio_sm_config *c, uint out_base, uint out_count)
{
static inline void sm_config_set_out_pins(pio_sm_config *c, uint out_base,
uint out_count) {
PIO pio = pio_get_current();
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, uint set_count)
{
static inline void sm_config_set_set_pins(pio_sm_config *c, uint set_base,
uint set_count) {
PIO pio = pio_get_current();
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->chip->smc_set_in_pins(pio, c, in_base);
}
static inline void sm_config_set_sideset_pins(pio_sm_config *c, uint sideset_base)
{
static inline void sm_config_set_sideset_pins(pio_sm_config *c,
uint sideset_base) {
PIO pio = pio_get_current();
pio->chip->smc_set_sideset_pins(pio, c, sideset_base);
}
static inline void sm_config_set_sideset(pio_sm_config *c, uint bit_count, bool optional, bool pindirs)
{
static inline void sm_config_set_sideset(pio_sm_config *c, uint bit_count,
bool optional, bool pindirs) {
PIO pio = pio_get_current();
pio->chip->smc_set_sideset(pio, c, bit_count, optional, pindirs);
}
static inline void sm_config_set_clkdiv_int_frac(pio_sm_config *c, uint16_t div_int, uint8_t div_frac)
{
static inline void sm_config_set_clkdiv_int_frac(pio_sm_config *c,
uint16_t div_int,
uint8_t div_frac) {
PIO pio = pio_get_current();
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->chip->smc_set_clkdiv(pio, c, div);
}
static inline void sm_config_set_wrap(pio_sm_config *c, uint wrap_target, uint wrap)
{
static inline void sm_config_set_wrap(pio_sm_config *c, uint wrap_target,
uint wrap) {
PIO pio = pio_get_current();
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->chip->smc_set_jmp_pin(pio, c, pin);
}
static inline void sm_config_set_in_shift(pio_sm_config *c, bool shift_right, bool autopush, uint push_threshold)
{
static inline void sm_config_set_in_shift(pio_sm_config *c, bool shift_right,
bool autopush, uint push_threshold) {
PIO pio = pio_get_current();
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, bool autopull, uint pull_threshold)
{
static inline void sm_config_set_out_shift(pio_sm_config *c, bool shift_right,
bool autopull, uint pull_threshold) {
PIO pio = pio_get_current();
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, enum pio_fifo_join join)
{
static inline void sm_config_set_fifo_join(pio_sm_config *c,
enum pio_fifo_join join) {
PIO pio = pio_get_current();
pio->chip->smc_set_fifo_join(pio, c, join);
}
static inline void sm_config_set_out_special(pio_sm_config *c, bool sticky, bool has_enable_pin, uint enable_pin_index)
{
static inline void sm_config_set_out_special(pio_sm_config *c, bool sticky,
bool has_enable_pin,
uint enable_pin_index) {
PIO pio = pio_get_current();
pio->chip->smc_set_out_special(pio, c, sticky, has_enable_pin, enable_pin_index);
pio->chip->smc_set_out_special(pio, c, sticky, has_enable_pin,
enable_pin_index);
}
static inline void sm_config_set_mov_status(pio_sm_config *c, enum pio_mov_status_type status_sel, uint status_n)
{
static inline void sm_config_set_mov_status(pio_sm_config *c,
enum pio_mov_status_type status_sel,
uint status_n) {
PIO pio = pio_get_current();
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);
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();
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->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->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->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->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->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->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->chip->gpio_set_input_enabled(pio, gpio, enabled);
}
static inline void gpio_set_drive_strength(uint gpio, enum gpio_drive_strength drive)
{
static inline void gpio_set_drive_strength(uint gpio,
enum gpio_drive_strength drive) {
PIO pio = pio_get_current();
pio->chip->gpio_set_drive_strength(pio, gpio, drive);
}
@ -862,9 +814,7 @@ static inline void gpio_disable_pulls(uint gpio) {
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);

View file

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

View file

@ -8,16 +8,16 @@
#include <sys/ioctl.h>
#define RP1_PIO_INSTRUCTION_COUNT 32
#define RP1_PIO_SM_COUNT 4
#define RP1_PIO_GPIO_COUNT 28
#define RP1_GPIO_FUNC_PIO 7
#define RP1_PIO_INSTRUCTION_COUNT 32
#define RP1_PIO_SM_COUNT 4
#define RP1_PIO_GPIO_COUNT 28
#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_FROM_SM 1
#define RP1_PIO_DIR_COUNT 2
#define RP1_PIO_DIR_TO_SM 0
#define RP1_PIO_DIR_FROM_SM 1
#define RP1_PIO_DIR_COUNT 2
typedef struct {
uint32_t clkdiv;
@ -125,12 +125,12 @@ struct rp1_pio_sm_set_dmactrl_args {
};
struct rp1_pio_sm_fifo_state_args {
uint16_t sm;
uint8_t tx;
uint8_t rsvd;
uint16_t level; /* OUT */
uint8_t empty; /* OUT */
uint8_t full; /* OUT */
uint16_t sm;
uint8_t tx;
uint8_t rsvd;
uint16_t level; /* OUT */
uint8_t empty; /* OUT */
uint8_t full; /* OUT */
};
struct rp1_gpio_init_args {
@ -160,25 +160,10 @@ struct rp1_pio_sm_config_xfer_args {
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 {
uint16_t sm;
uint16_t dir;
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;
};
@ -190,47 +175,75 @@ struct rp1_access_hw_args {
#define PIO_IOC_MAGIC 102
#define PIO_IOC_SM_CONFIG_XFER _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_DATA32 _IOW(PIO_IOC_MAGIC, 2, struct rp1_pio_sm_xfer_data32_args)
#define PIO_IOC_SM_CONFIG_XFER32 _IOW(PIO_IOC_MAGIC, 3, struct rp1_pio_sm_config_xfer32_args)
#define PIO_IOC_SM_CONFIG_XFER \
_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)
#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_WRITE_HW _IOW(PIO_IOC_MAGIC, 9, struct rp1_access_hw_args)
#define PIO_IOC_CAN_ADD_PROGRAM _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_REMOVE_PROGRAM _IOW(PIO_IOC_MAGIC, 12, struct rp1_pio_remove_program_args)
#define PIO_IOC_CAN_ADD_PROGRAM \
_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_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_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_IS_CLAIMED _IOW(PIO_IOC_MAGIC, 22, struct rp1_pio_sm_claim_args)
#define PIO_IOC_SM_IS_CLAIMED \
_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_SET_CONFIG _IOW(PIO_IOC_MAGIC, 31, struct rp1_pio_sm_set_config_args)
#define PIO_IOC_SM_SET_CONFIG \
_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_CLEAR_FIFOS _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_PINS _IOW(PIO_IOC_MAGIC, 35, struct rp1_pio_sm_set_pins_args)
#define PIO_IOC_SM_SET_PINDIRS _IOW(PIO_IOC_MAGIC, 36, struct rp1_pio_sm_set_pindirs_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_CLEAR_FIFOS \
_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_PINS \
_IOW(PIO_IOC_MAGIC, 35, struct rp1_pio_sm_set_pins_args)
#define PIO_IOC_SM_SET_PINDIRS \
_IOW(PIO_IOC_MAGIC, 36, struct rp1_pio_sm_set_pindirs_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_GET _IOWR(PIO_IOC_MAGIC, 42, struct rp1_pio_sm_get_args)
#define PIO_IOC_SM_SET_DMACTRL _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_DRAIN_TX _IOW(PIO_IOC_MAGIC, 45, struct rp1_pio_sm_clear_fifos_args)
#define PIO_IOC_SM_SET_DMACTRL \
_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_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_SET_FUNCTION _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_OUTOVER _IOW(PIO_IOC_MAGIC, 53, struct rp1_gpio_set_args)
#define PIO_IOC_GPIO_SET_INOVER _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)
#define PIO_IOC_GPIO_SET_FUNCTION \
_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_OUTOVER \
_IOW(PIO_IOC_MAGIC, 53, struct rp1_gpio_set_args)
#define PIO_IOC_GPIO_SET_INOVER \
_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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

@ -18,14 +18,7 @@ struct PyPiomatter {
py::buffer buffer;
std::unique_ptr<piomatter::piomatter_base> matter;
void show() {
int err = matter->show();
if (err != 0) {
errno = err;
PyErr_SetFromErrno(PyExc_OSError);
throw py::error_already_set();
}
}
void show() { matter->show(); }
double fps() const { return matter->fps; }
};
@ -173,11 +166,9 @@ 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.
The default, 10, is the maximum value.
``n_temporal_planes`` controls temporal dithering of the panel.
0 or 1 behave the same: All `n_planes` are transmitted every time.
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.
``n_temporal_planes`` controls temporal dithering of the panel. The acceptable values
are 0 (the default), 2, and 4. A higher setting can increase FPS at the cost of
slightly increasing the variation of brightness across subsequent frames.
For simple panels with just 1 connector (2 color lanes), the following constructor arguments are available: