This commit is contained in:
Jeff Epler 2024-12-12 13:55:19 -06:00
commit 833043f7fd
18 changed files with 6358 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
*.pio.h
prototest

5
Makefile Normal file
View file

@ -0,0 +1,5 @@
protodemo: protodemo.c piolib/*.c | protomatter.pio.h
g++ -Og -ggdb -x c++ -Ipiolib/include -o $@ $^ -Wno-narrowing
protomatter.pio.h: protomatter.pio assemble.py
python assemble.py $< $@

27
assemble.py Normal file
View file

@ -0,0 +1,27 @@
import sys
from contextlib import contextmanager
import click
import adafruit_pioasm
@contextmanager
def temporary_stdout(filename):
old_stdout = sys.stdout
try:
with open(filename, "w", encoding="utf-8") as sys.stdout:
yield sys.stdout
finally:
sys.stdout = old_stdout
@click.command
@click.argument("infile")
@click.argument("outfile")
def main(infile, outfile):
program_name = infile.rpartition("/")[2].partition(".")[0]
print(program_name)
program = adafruit_pioasm.Program.from_file(infile, build_debuginfo=True)
with temporary_stdout(outfile):
program.print_c_program(program_name)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,24 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2024 Raspberry Pi Ltd.
* All rights reserved.
*/
#ifndef _HARDWARE_CLOCKS_H
#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_COUNT
};
#endif

View file

@ -0,0 +1,65 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2024 Raspberry Pi Ltd.
* All rights reserved.
*/
#ifndef _HARDWARE_GPIO_H
#define _HARDWARE_GPIO_H
#include "pio_platform.h"
#ifndef PARAM_ASSERTIONS_ENABLED_GPIO
#define PARAM_ASSERTIONS_ENABLED_GPIO 0
#endif
#define NUM_BANK0_GPIOS 32
enum gpio_function {
GPIO_FUNC_XIP = 0,
GPIO_FUNC_SPI = 1,
GPIO_FUNC_UART = 2,
GPIO_FUNC_I2C = 3,
GPIO_FUNC_PWM = 4,
GPIO_FUNC_SIO = 5,
GPIO_FUNC_PIO0 = 6,
GPIO_FUNC_PIO1 = 7,
GPIO_FUNC_GPCK = 8,
GPIO_FUNC_USB = 9,
GPIO_FUNC_NULL = 0x1f,
};
#define GPIO_OUT 1
#define GPIO_IN 0
enum gpio_irq_level {
GPIO_IRQ_LEVEL_LOW = 0x1u,
GPIO_IRQ_LEVEL_HIGH = 0x2u,
GPIO_IRQ_EDGE_FALL = 0x4u,
GPIO_IRQ_EDGE_RISE = 0x8u,
};
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
};
enum gpio_slew_rate {
GPIO_SLEW_RATE_SLOW = 0, ///< Slew rate limiting enabled
GPIO_SLEW_RATE_FAST = 1 ///< Slew rate limiting disabled
};
enum gpio_drive_strength {
GPIO_DRIVE_STRENGTH_2MA = 0, ///< 2 mA nominal drive strength
GPIO_DRIVE_STRENGTH_4MA = 1, ///< 4 mA nominal drive strength
GPIO_DRIVE_STRENGTH_8MA = 2, ///< 8 mA nominal drive strength
GPIO_DRIVE_STRENGTH_12MA = 3 ///< 12 mA nominal drive strength
};
static inline void check_gpio_param(__unused uint gpio) {
invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
}
#endif

View file

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

View file

@ -0,0 +1,511 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _HARDWARE_PIO_INSTRUCTIONS_H
#define _HARDWARE_PIO_INSTRUCTIONS_H
//#include "pico.h"
/** \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"
*/
// 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
#ifdef __cplusplus
extern "C" {
#endif
enum pio_instr_bits {
pio_instr_bits_jmp = 0x0000,
pio_instr_bits_wait = 0x2000,
pio_instr_bits_in = 0x4000,
pio_instr_bits_out = 0x6000,
pio_instr_bits_push = 0x8000,
pio_instr_bits_pull = 0x8080,
pio_instr_bits_mov = 0xa000,
pio_instr_bits_irq = 0xc000,
pio_instr_bits_set = 0xe000,
};
#ifndef NDEBUG
#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_DEST 0x80u
#else
#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_DEST 0u
#endif
/*! \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
*/
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_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,
};
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) {
valid_params_if(PIO_INSTRUCTIONS, arg1 <= 0x7);
#if PARAM_ASSERTIONS_ENABLED(PIO_INSTRUCTIONS)
uint32_t major = _pio_major_instr_bits(instr_bits);
if (major == pio_instr_bits_in || major == pio_instr_bits_out) {
assert(arg2 && arg2 <= 32);
} else {
assert(arg2 <= 31);
}
#endif
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) {
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.
*
* \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
*/
static inline uint pio_encode_delay(uint cycles) {
// note that the maximum cycles will be smaller if sideset_bit_count > 0
valid_params_if(PIO_INSTRUCTIONS, cycles <= 0x1f);
return cycles << 8u;
}
/*! \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.
*
* \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, 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
*
* \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
* \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, value <= ((1u << sideset_bit_count) - 1));
return 0x1000u | value << (12u - sideset_bit_count);
}
/*! \brief Encode an unconditional JMP instruction
* \ingroup pio_instructions
*
* 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
*/
static inline uint pio_encode_jmp(uint addr) {
return _pio_encode_instr_and_args(pio_instr_bits_jmp, 0, addr);
}
/*! \brief Encode a conditional JMP if scratch X zero 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
*/
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
*
* 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
*/
static inline uint pio_encode_jmp_x_dec(uint addr) {
return _pio_encode_instr_and_args(pio_instr_bits_jmp, 2, addr);
}
/*! \brief Encode a conditional JMP if scratch Y zero 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
*/
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
*
* 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
*/
static inline uint pio_encode_jmp_y_dec(uint addr) {
return _pio_encode_instr_and_args(pio_instr_bits_jmp, 4, addr);
}
/*! \brief Encode a conditional JMP if scratch X not equal scratch Y instruction
* \ingroup pio_instructions
*
* 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
*/
static inline uint pio_encode_jmp_x_ne_y(uint addr) {
return _pio_encode_instr_and_args(pio_instr_bits_jmp, 5, addr);
}
/*! \brief Encode a conditional JMP if input pin high instruction
* \ingroup pio_instructions
*
* 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
*/
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
*
* 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
*/
static inline uint pio_encode_jmp_not_osre(uint addr) {
return _pio_encode_instr_and_args(pio_instr_bits_jmp, 7, addr);
}
static inline uint _pio_encode_irq(bool relative, uint irq) {
valid_params_if(PIO_INSTRUCTIONS, irq <= 7);
return (relative ? 0x10u : 0x0u) | irq;
}
/*! \brief Encode a WAIT for GPIO pin instruction
* \ingroup pio_instructions
*
* This is the equivalent of `WAIT <polarity> GPIO <gpio>`
*
* \param polarity true for `WAIT 1`, false for `WAIT 0`
* \param gpio The real GPIO number 0-31
* \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_gpio(bool polarity, uint gpio) {
return _pio_encode_instr_and_args(pio_instr_bits_wait,
0u | (polarity ? 4u : 0u), gpio);
}
/*! \brief Encode a WAIT for pin instruction
* \ingroup pio_instructions
*
* 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
* \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);
}
/*! \brief Encode a WAIT for IRQ instruction
* \ingroup pio_instructions
*
* 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
*/
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));
}
/*! \brief Encode an IN instruction
* \ingroup pio_instructions
*
* This is the equivalent of `IN <src>, <count>`
*
* \param src The source to take data from
* \param count The number of bits 1-32
* \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_in(enum pio_src_dest src, uint count) {
valid_params_if(PIO_INSTRUCTIONS, !(src & _PIO_INVALID_IN_SRC));
return _pio_encode_instr_and_src_dest(pio_instr_bits_in, src, count);
}
/*! \brief Encode an OUT instruction
* \ingroup pio_instructions
*
* This is the equivalent of `OUT <src>, <count>`
*
* \param dest The destination to write data to
* \param count The number of bits 1-32
* \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_out(enum pio_src_dest dest, uint count) {
valid_params_if(PIO_INSTRUCTIONS, !(dest & _PIO_INVALID_OUT_DEST));
return _pio_encode_instr_and_src_dest(pio_instr_bits_out, dest, count);
}
/*! \brief Encode a PUSH instruction
* \ingroup pio_instructions
*
* This is the equivalent of `PUSH <if_full>, <block>`
*
* \param if_full true for `PUSH IF_FULL ...`, false for `PUSH ...`
* \param block true for `PUSH ... BLOCK`, false for `PUSH ...`
* \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_push(bool if_full, bool block) {
return _pio_encode_instr_and_args(
pio_instr_bits_push, (if_full ? 2u : 0u) | (block ? 1u : 0u), 0);
}
/*! \brief Encode a PULL instruction
* \ingroup pio_instructions
*
* This is the equivalent of `PULL <if_empty>, <block>`
*
* \param if_empty true for `PULL IF_EMPTY ...`, false for `PULL ...`
* \param block true for `PULL ... BLOCK`, false for `PULL ...`
* \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_pull(bool if_empty, bool block) {
return _pio_encode_instr_and_args(
pio_instr_bits_pull, (if_empty ? 2u : 0u) | (block ? 1u : 0u), 0);
}
/*! \brief Encode a MOV instruction
* \ingroup pio_instructions
*
* This is the equivalent of `MOV <dest>, <src>`
*
* \param dest The destination to write data to
* \param src The source to take data from
* \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) {
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);
}
/*! \brief Encode a MOV instruction with bit invert
* \ingroup pio_instructions
*
* This is the equivalent of `MOV <dest>, ~<src>`
*
* \param dest The destination to write inverted data to
* \param src The source to take data from
* \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) {
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));
}
/*! \brief Encode a MOV instruction with bit reverse
* \ingroup pio_instructions
*
* This is the equivalent of `MOV <dest>, ::<src>`
*
* \param dest The destination to write bit reversed data to
* \param src The source to take data from
* \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) {
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));
}
/*! \brief Encode a IRQ SET instruction
* \ingroup pio_instructions
*
* 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
*/
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));
}
/*! \brief Encode a IRQ WAIT instruction
* \ingroup pio_instructions
*
* 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
*/
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));
}
/*! \brief Encode a IRQ CLEAR instruction
* \ingroup pio_instructions
*
* 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
*/
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));
}
/*! \brief Encode a SET instruction
* \ingroup pio_instructions
*
* This is the equivalent of `SET <dest>, <value>`
*
* \param dest The destination to apply the value to
* \param value The value 0-31
* \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_set(enum pio_src_dest dest, uint value) {
valid_params_if(PIO_INSTRUCTIONS, !(dest & _PIO_INVALID_SET_DEST));
return _pio_encode_instr_and_src_dest(pio_instr_bits_set, dest, value);
}
/*! \brief Encode a NOP instruction
* \ingroup pio_instructions
*
* This is the equivalent of `NOP` which is itself encoded as `MOV y, y`
*
* \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); }
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,16 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_STDLIB_H_
#define _PICO_STDLIB_H_
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include "piolib.h"
#endif

View file

@ -0,0 +1,53 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2024 Raspberry Pi Ltd.
* All rights reserved.
*/
#ifndef _PIO_PLATFORM_H
#define _PIO_PLATFORM_H
#include <assert.h>
#include <inttypes.h>
#include <stdbool.h>
#ifndef __unused
#define __unused __attribute__((unused))
#endif
#define PICO_DEFAULT_LED_PIN 4
#ifndef PARAM_ASSERTIONS_ENABLE_ALL
#define PARAM_ASSERTIONS_ENABLE_ALL 0
#endif
#ifndef PARAM_ASSERTIONS_DISABLE_ALL
#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 STATIC_ASSERT(cond) static_assert(cond, #cond)
#define _u(x) ((uint)(x))
#define bool_to_bit(x) ((uint) !!(x))
#ifndef count_of
#define count_of(a) (sizeof(a) / sizeof((a)[0]))
#endif
typedef unsigned int uint;
#endif

829
piolib/include/piolib.h Normal file
View file

@ -0,0 +1,829 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2023-24 Raspberry Pi Ltd.
* All rights reserved.
*/
#ifndef _PIOLIB_H
#define _PIOLIB_H
#ifdef __cplusplus
extern "C" {
#endif
#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_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,
};
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 };
#ifndef PIOLIB_INTERNALS
enum pio_instr_bits {
pio_instr_bits_jmp = 0x0000,
pio_instr_bits_wait = 0x2000,
pio_instr_bits_in = 0x4000,
pio_instr_bits_out = 0x6000,
pio_instr_bits_push = 0x8000,
pio_instr_bits_pull = 0x8080,
pio_instr_bits_mov = 0xa000,
pio_instr_bits_irq = 0xc000,
pio_instr_bits_set = 0xe000,
};
#ifndef NDEBUG
#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_DEST 0x80u
#else
#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_DEST 0u
#endif
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_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,
};
#endif
typedef struct pio_program {
const uint16_t *instructions;
uint8_t length;
int8_t origin; // required instruction memory origin or -1
uint8_t pio_version;
} pio_program_t;
typedef struct {
uint32_t content[4];
} pio_sm_config;
typedef struct pio_instance *PIO;
typedef const struct pio_chip PIO_CHIP_T;
struct pio_chip {
const char *name;
const char *compatible;
uint16_t instr_count;
uint16_t sm_count;
uint16_t fifo_depth;
void *hw_state;
PIO (*create_instance)(PIO_CHIP_T *chip, uint index);
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);
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);
uint (*pio_encode_sideset_opt)(PIO pio, uint sideset_bit_count, uint value);
uint (*pio_encode_jmp)(PIO pio, uint addr);
uint (*pio_encode_jmp_not_x)(PIO pio, uint addr);
uint (*pio_encode_jmp_x_dec)(PIO pio, uint addr);
uint (*pio_encode_jmp_not_y)(PIO pio, uint addr);
uint (*pio_encode_jmp_y_dec)(PIO pio, uint addr);
uint (*pio_encode_jmp_x_ne_y)(PIO pio, uint addr);
uint (*pio_encode_jmp_pin)(PIO pio, uint addr);
uint (*pio_encode_jmp_not_osre)(PIO pio, uint addr);
uint (*pio_encode_wait_gpio)(PIO pio, bool polarity, uint gpio);
uint (*pio_encode_wait_pin)(PIO pio, bool polarity, uint pin);
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_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);
uint (*pio_encode_set)(PIO pio, enum pio_src_dest dest, uint value);
uint (*pio_encode_nop)(PIO pio);
bool (*pio_sm_claim)(PIO pio, uint sm);
bool (*pio_sm_claim_mask)(PIO pio, uint mask);
int (*pio_sm_claim_unused)(PIO pio, bool required);
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_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)(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_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);
void (*pio_sm_restart_mask)(PIO pio, uint32_t mask);
void (*pio_sm_clkdiv_restart)(PIO pio, uint sm);
void (*pio_sm_clkdiv_restart_mask)(PIO pio, uint32_t mask);
void (*pio_sm_enable_sync)(PIO pio, uint32_t mask);
void (*pio_sm_put)(PIO pio, uint sm, uint32_t data, bool blocking);
uint32_t (*pio_sm_get)(PIO pio, uint sm, bool blocking);
void (*pio_sm_set_dmactrl)(PIO pio, uint sm, bool is_tx, uint32_t ctrl);
bool (*pio_sm_is_rx_fifo_empty)(PIO pio, uint sm);
bool (*pio_sm_is_rx_fifo_full)(PIO pio, uint sm);
uint (*pio_sm_get_rx_fifo_level)(PIO pio, uint sm);
bool (*pio_sm_is_tx_fifo_empty)(PIO pio, uint sm);
bool (*pio_sm_is_tx_fifo_full)(PIO pio, uint sm);
uint (*pio_sm_get_tx_fifo_level)(PIO pio, uint sm);
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_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_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_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);
uint32_t (*clock_get_hz)(PIO pio, enum clock_index clk_index);
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);
void (*gpio_set_outover)(PIO pio, uint gpio, uint value);
void (*gpio_set_inover)(PIO pio, uint gpio, uint value);
void (*gpio_set_oeover)(PIO pio, uint gpio, uint value);
void (*gpio_set_input_enabled)(PIO pio, uint gpio, bool enabled);
void (*gpio_set_drive_strength)(PIO pio, uint gpio,
enum gpio_drive_strength drive);
};
struct pio_instance {
const PIO_CHIP_T *chip;
int in_use;
bool errors_are_fatal;
bool error;
};
int pio_init(void);
PIO pio_open(uint idx);
PIO pio_open_by_name(const char *name);
PIO pio_open_helper(uint idx);
void pio_close(PIO pio);
void pio_panic(const char *msg);
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) {
pio->error = true;
if (pio->errors_are_fatal)
pio_panic(msg);
}
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_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_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 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) {
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) {
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) {
check_pio_param(pio);
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) {
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) {
uint offset;
check_pio_param(pio);
offset = pio->chip->pio_add_program_at_offset(pio, program, PIO_ORIGIN_ANY);
if (offset == PIO_ORIGIN_INVALID)
pio_error(pio, "No program space");
return 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)
pio_error(pio, "No program space");
}
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) {
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) {
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) {
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) {
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) {
PIO pio = pio_get_current();
return pio->chip->pio_encode_jmp(pio, 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) {
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) {
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) {
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) {
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) {
PIO pio = pio_get_current();
return pio->chip->pio_encode_jmp_pin(pio, 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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
PIO pio = pio_get_current();
return pio->chip->pio_encode_set(pio, dest, value);
}
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) {
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) {
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) {
check_pio_param(pio);
pio->chip->pio_sm_unclaim(pio, sm);
}
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) {
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) {
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) {
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) {
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) {
check_pio_param(pio);
pio->chip->pio_sm_exec(pio, sm, instr, true);
}
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) {
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) {
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) {
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) {
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) {
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) {
check_pio_param(pio);
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) {
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) {
check_pio_param(pio);
pio->chip->pio_sm_set_enabled_mask(pio, mask, enabled);
}
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) {
check_pio_param(pio);
pio->chip->pio_sm_restart_mask(pio, mask);
}
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
check_pio_param(pio);
pio->chip->pio_sm_put(pio, sm, data, true);
}
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) {
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) {
check_pio_param(pio);
return pio->chip->pio_get_default_sm_config(pio);
}
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
PIO pio = pio_get_current();
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) {
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) {
check_pio_param(pio);
pio->chip->pio_gpio_init(pio, pin);
}
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) {
PIO pio = pio_get_current();
pio->chip->gpio_init(pio, gpio);
}
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) {
PIO pio = pio_get_current();
pio->chip->gpio_set_pulls(pio, gpio, up, down);
}
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) {
PIO pio = pio_get_current();
pio->chip->gpio_set_inover(pio, gpio, 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) {
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) {
PIO pio = pio_get_current();
pio->chip->gpio_set_drive_strength(pio, gpio, drive);
}
static inline void gpio_pull_up(uint gpio) {
gpio_set_pulls(gpio, true, false);
}
static inline void gpio_pull_down(uint gpio) {
gpio_set_pulls(gpio, false, true);
}
static inline void gpio_disable_pulls(uint gpio) {
gpio_set_pulls(gpio, false, false);
}
static inline void stdio_init_all(void) {}
void sleep_us(uint64_t us);
static inline void sleep_ms(uint32_t ms) {
sleep_us((uint64_t)(ms * (uint64_t)1000));
}
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,16 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2023-24 Raspberry Pi Ltd.
* All rights reserved.
*/
#ifndef _PIOLIB_PRIV_H
#define _PIOLIB_PRIV_H
#include "pio_platform.h"
#define DECLARE_PIO_CHIP(chip) \
const PIO_CHIP_T *__ptr_##chip __attribute__((section("piochips"))) \
__attribute__((used)) = &chip
#endif

249
piolib/include/rp1_pio_if.h Normal file
View file

@ -0,0 +1,249 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2023-24 Raspberry Pi Ltd.
* All rights reserved.
*/
#ifndef _RP1_PIO_IF_H
#define _RP1_PIO_IF_H
#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_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
typedef struct {
uint32_t clkdiv;
uint32_t execctrl;
uint32_t shiftctrl;
uint32_t pinctrl;
} rp1_pio_sm_config;
struct rp1_pio_add_program_args {
uint16_t num_instrs;
uint16_t origin;
uint16_t instrs[RP1_PIO_INSTRUCTION_COUNT];
};
struct rp1_pio_remove_program_args {
uint16_t num_instrs;
uint16_t origin;
};
struct rp1_pio_sm_claim_args {
uint16_t mask;
};
struct rp1_pio_sm_init_args {
uint16_t sm;
uint16_t initial_pc;
rp1_pio_sm_config config;
};
struct rp1_pio_sm_set_config_args {
uint16_t sm;
uint16_t rsvd;
rp1_pio_sm_config config;
};
struct rp1_pio_sm_exec_args {
uint16_t sm;
uint16_t instr;
uint8_t blocking;
uint8_t rsvd;
};
struct rp1_pio_sm_clear_fifos_args {
uint16_t sm;
};
struct rp1_pio_sm_set_clkdiv_args {
uint16_t sm;
uint16_t div_int;
uint8_t div_frac;
uint8_t rsvd;
};
struct rp1_pio_sm_set_pins_args {
uint16_t sm;
uint16_t rsvd;
uint32_t values;
uint32_t mask;
};
struct rp1_pio_sm_set_pindirs_args {
uint16_t sm;
uint16_t rsvd;
uint32_t dirs;
uint32_t mask;
};
struct rp1_pio_sm_set_enabled_args {
uint16_t mask;
uint8_t enable;
uint8_t rsvd;
};
struct rp1_pio_sm_restart_args {
uint16_t mask;
};
struct rp1_pio_sm_clkdiv_restart_args {
uint16_t mask;
};
struct rp1_pio_sm_enable_sync_args {
uint16_t mask;
};
struct rp1_pio_sm_put_args {
uint16_t sm;
uint8_t blocking;
uint8_t rsvd;
uint32_t data;
};
struct rp1_pio_sm_get_args {
uint16_t sm;
uint8_t blocking;
uint8_t rsvd;
uint32_t data; /* OUT */
};
struct rp1_pio_sm_set_dmactrl_args {
uint16_t sm;
uint8_t is_tx;
uint8_t rsvd;
uint32_t ctrl;
};
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 */
};
struct rp1_gpio_init_args {
uint16_t gpio;
};
struct rp1_gpio_set_function_args {
uint16_t gpio;
uint16_t fn;
};
struct rp1_gpio_set_pulls_args {
uint16_t gpio;
uint8_t up;
uint8_t down;
};
struct rp1_gpio_set_args {
uint16_t gpio;
uint16_t value;
};
struct rp1_pio_sm_config_xfer_args {
uint16_t sm;
uint16_t dir;
uint16_t buf_size;
uint16_t buf_count;
};
struct rp1_pio_sm_xfer_data_args {
uint16_t sm;
uint16_t dir;
uint16_t data_bytes;
void *data;
};
struct rp1_access_hw_args {
uint32_t addr;
uint32_t len;
void *data;
};
#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)
#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_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_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_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_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_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)
#endif

946
piolib/pio_rp1.c Normal file
View file

@ -0,0 +1,946 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2024 Raspberry Pi Ltd.
* All rights reserved.
*/
#include <errno.h>
#include <fcntl.h>
#include <malloc.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define PIOLIB_INTERNALS
#include "pio_platform.h"
#define pio_encode_delay _pio_encode_delay
#define pio_encode_sideset _pio_encode_sideset
#define pio_encode_sideset_opt _pio_encode_sideset_opt
#define pio_encode_jmp _pio_encode_jmp
#define pio_encode_jmp_not_x _pio_encode_jmp_not_x
#define pio_encode_jmp_x_dec _pio_encode_jmp_x_dec
#define pio_encode_jmp_not_y _pio_encode_jmp_not_y
#define pio_encode_jmp_y_dec _pio_encode_jmp_y_dec
#define pio_encode_jmp_x_ne_y _pio_encode_jmp_x_ne_y
#define pio_encode_jmp_pin _pio_encode_jmp_pin
#define pio_encode_jmp_not_osre _pio_encode_jmp_not_osre
#define pio_encode_wait_gpio _pio_encode_wait_gpio
#define pio_encode_wait_pin _pio_encode_wait_pin
#define pio_encode_wait_irq _pio_encode_wait_irq
#define pio_encode_in _pio_encode_in
#define pio_encode_out _pio_encode_out
#define pio_encode_push _pio_encode_push
#define pio_encode_pull _pio_encode_pull
#define pio_encode_mov _pio_encode_mov
#define pio_encode_mov_not _pio_encode_mov_not
#define pio_encode_mov_reverse _pio_encode_mov_reverse
#define pio_encode_irq_set _pio_encode_irq_set
#define pio_encode_irq_wait _pio_encode_irq_wait
#define pio_encode_irq_clear _pio_encode_irq_clear
#define pio_encode_set _pio_encode_set
#define pio_encode_nop _pio_encode_nop
#include "hardware/pio_instructions.h"
#undef pio_encode_delay
#undef pio_encode_sideset
#undef pio_encode_sideset_opt
#undef pio_encode_jmp
#undef pio_encode_jmp_not_x
#undef pio_encode_jmp_x_dec
#undef pio_encode_jmp_not_y
#undef pio_encode_jmp_y_dec
#undef pio_encode_jmp_x_ne_y
#undef pio_encode_jmp_pin
#undef pio_encode_jmp_not_osre
#undef pio_encode_wait_gpio
#undef pio_encode_wait_pin
#undef pio_encode_wait_irq
#undef pio_encode_in
#undef pio_encode_out
#undef pio_encode_push
#undef pio_encode_pull
#undef pio_encode_mov
#undef pio_encode_mov_not
#undef pio_encode_mov_reverse
#undef pio_encode_irq_set
#undef pio_encode_irq_wait
#undef pio_encode_irq_clear
#undef pio_encode_set
#undef pio_encode_nop
#include "hardware/gpio.h"
#include "hardware/pio.h"
#include "hardware/regs/proc_pio.h"
#include "piolib.h"
#include "piolib_priv.h"
#include "rp1_pio_if.h"
typedef struct rp1_pio_handle {
struct pio_instance base;
const char *devname;
int fd;
} * RP1_PIO;
#define smc_to_rp1(_config, _c) \
rp1_pio_sm_config *_c = (rp1_pio_sm_config *)_config
#define GPIOS_MASK ((1 << RP1_PIO_GPIO_COUNT) - 1)
STATIC_ASSERT(sizeof(rp1_pio_sm_config) <= sizeof(pio_sm_config));
static inline void check_sm_param(__unused uint sm) {
valid_params_if(PIO, sm < RP1_PIO_SM_COUNT);
}
static inline void check_sm_mask(__unused uint mask) {
valid_params_if(PIO, mask < (1u << RP1_PIO_SM_COUNT));
}
static pio_sm_config rp1_pio_get_default_sm_config(PIO pio) {
pio_sm_config c = {{0}};
sm_config_set_clkdiv_int_frac(&c, 1, 0);
sm_config_set_wrap(&c, 0, 31);
sm_config_set_in_shift(&c, true, false, 32);
sm_config_set_out_shift(&c, true, false, 32);
return c;
}
static uint rp1_pio_encode_delay(PIO pio, uint cycles) {
return _pio_encode_delay(cycles);
}
static uint rp1_pio_encode_sideset(PIO pio, uint sideset_bit_count,
uint value) {
return _pio_encode_sideset(sideset_bit_count, value);
}
static uint rp1_pio_encode_sideset_opt(PIO pio, uint sideset_bit_count,
uint value) {
return _pio_encode_sideset_opt(sideset_bit_count, value);
}
static uint rp1_pio_encode_jmp(PIO pio, uint addr) {
return _pio_encode_jmp(addr);
}
static uint rp1_pio_encode_jmp_not_x(PIO pio, uint addr) {
return _pio_encode_jmp_not_x(addr);
}
static uint rp1_pio_encode_jmp_x_dec(PIO pio, uint addr) {
return _pio_encode_jmp_x_dec(addr);
}
static uint rp1_pio_encode_jmp_not_y(PIO pio, uint addr) {
return _pio_encode_jmp_not_y(addr);
}
static uint rp1_pio_encode_jmp_y_dec(PIO pio, uint addr) {
return _pio_encode_jmp_y_dec(addr);
}
static uint rp1_pio_encode_jmp_x_ne_y(PIO pio, uint addr) {
return _pio_encode_jmp_x_ne_y(addr);
}
static uint rp1_pio_encode_jmp_pin(PIO pio, uint addr) {
return _pio_encode_jmp_pin(addr);
}
static uint rp1_pio_encode_jmp_not_osre(PIO pio, uint addr) {
return _pio_encode_jmp_not_osre(addr);
}
static uint rp1_pio_encode_wait_gpio(PIO pio, bool polarity, uint gpio) {
return _pio_encode_wait_gpio(polarity, gpio);
}
static uint rp1_pio_encode_wait_pin(PIO pio, bool polarity, uint pin) {
return _pio_encode_wait_pin(polarity, pin);
}
static uint rp1_pio_encode_wait_irq(PIO pio, bool polarity, bool relative,
uint irq) {
return _pio_encode_wait_irq(polarity, relative, irq);
}
static uint rp1_pio_encode_in(PIO pio, enum pio_src_dest src, uint count) {
return _pio_encode_in(src, count);
}
static uint rp1_pio_encode_out(PIO pio, enum pio_src_dest dest, uint count) {
return _pio_encode_out(dest, count);
}
static uint rp1_pio_encode_push(PIO pio, bool if_full, bool block) {
return _pio_encode_push(if_full, block);
}
static uint rp1_pio_encode_pull(PIO pio, bool if_empty, bool block) {
return _pio_encode_pull(if_empty, block);
}
static uint rp1_pio_encode_mov(PIO pio, enum pio_src_dest dest,
enum pio_src_dest src) {
return _pio_encode_mov(dest, src);
}
static uint rp1_pio_encode_mov_not(PIO pio, enum pio_src_dest dest,
enum pio_src_dest src) {
return _pio_encode_mov_not(dest, src);
}
static uint rp1_pio_encode_mov_reverse(PIO pio, enum pio_src_dest dest,
enum pio_src_dest src) {
return _pio_encode_mov_reverse(dest, src);
}
static uint rp1_pio_encode_irq_set(PIO pio, bool relative, uint irq) {
return _pio_encode_irq_set(relative, irq);
}
static uint rp1_pio_encode_irq_wait(PIO pio, bool relative, uint irq) {
return _pio_encode_irq_wait(relative, irq);
}
static uint rp1_pio_encode_irq_clear(PIO pio, bool relative, uint irq) {
return _pio_encode_irq_clear(relative, irq);
}
static uint rp1_pio_encode_set(PIO pio, enum pio_src_dest dest, uint value) {
return _pio_encode_set(dest, value);
}
static uint rp1_pio_encode_nop(PIO pio) { return _pio_encode_nop(); }
static int rp1_ioctl(PIO pio, int request, void *args) {
RP1_PIO rp = (RP1_PIO)pio;
int err = ioctl(rp->fd, request, args);
switch (err) {
case -EREMOTEIO:
case -ETIMEDOUT:
pio_panic("Error communicating with RP1");
break;
default:
break;
}
return err;
}
static int rp1_pio_sm_config_xfer(PIO pio, uint sm, uint dir, uint buf_size,
uint buf_count) {
struct rp1_pio_sm_config_xfer_args args = {
.sm = sm, .dir = dir, .buf_size = buf_size, .buf_count = buf_count};
int err;
check_sm_param(sm);
err = rp1_ioctl(pio, PIO_IOC_SM_CONFIG_XFER, &args);
return (err > 0);
}
static int rp1_pio_sm_xfer_data(PIO pio, uint sm, uint dir, uint data_bytes,
void *data) {
struct rp1_pio_sm_xfer_data_args args = {
.sm = sm, .dir = dir, .data_bytes = data_bytes, .data = data};
int err;
check_sm_param(sm);
err = rp1_ioctl(pio, PIO_IOC_SM_XFER_DATA, &args);
return (err > 0);
}
static bool rp1_pio_can_add_program_at_offset(PIO pio,
const pio_program_t *program,
uint offset) {
struct rp1_pio_add_program_args args = {.num_instrs = program->length,
.origin = program->origin};
int err;
valid_params_if(PIO, offset < RP1_PIO_INSTRUCTION_COUNT ||
offset == PIO_ORIGIN_ANY);
valid_params_if(PIO, program->length <= RP1_PIO_INSTRUCTION_COUNT);
valid_params_if(PIO,
offset + program->length <= RP1_PIO_INSTRUCTION_COUNT ||
offset == PIO_ORIGIN_ANY);
if (program->origin >= 0 && (uint)program->origin != offset)
return false;
if (offset != PIO_ORIGIN_ANY)
args.origin = offset;
memcpy(args.instrs, program->instructions,
program->length * sizeof(uint16_t));
err = rp1_ioctl(pio, PIO_IOC_CAN_ADD_PROGRAM, &args);
return (err > 0);
}
static uint rp1_pio_add_program_at_offset(PIO pio, const pio_program_t *program,
uint offset) {
struct rp1_pio_add_program_args args = {.num_instrs = program->length,
.origin = program->origin};
valid_params_if(PIO, offset < RP1_PIO_INSTRUCTION_COUNT ||
offset == PIO_ORIGIN_ANY);
valid_params_if(PIO, program->length <= RP1_PIO_INSTRUCTION_COUNT);
valid_params_if(PIO,
offset + program->length <= RP1_PIO_INSTRUCTION_COUNT ||
offset == PIO_ORIGIN_ANY);
if (offset != PIO_ORIGIN_ANY)
args.origin = offset;
memcpy(args.instrs, program->instructions,
program->length * sizeof(uint16_t));
return rp1_ioctl(pio, PIO_IOC_ADD_PROGRAM, &args);
}
static bool rp1_pio_remove_program(PIO pio, const pio_program_t *program,
uint offset) {
struct rp1_pio_remove_program_args args = {.num_instrs = program->length,
.origin = offset};
valid_params_if(PIO, offset < RP1_PIO_INSTRUCTION_COUNT);
valid_params_if(PIO, offset + program->length <= RP1_PIO_INSTRUCTION_COUNT);
return !rp1_ioctl(pio, PIO_IOC_REMOVE_PROGRAM, &args);
}
static bool rp1_pio_clear_instruction_memory(PIO pio) {
return !rp1_ioctl(pio, PIO_IOC_CLEAR_INSTR_MEM, NULL);
}
static bool rp1_pio_sm_claim(PIO pio, uint sm) {
struct rp1_pio_sm_claim_args args = {.mask = (1 << sm)};
check_sm_param(sm);
return (rp1_ioctl(pio, PIO_IOC_SM_CLAIM, &args) >= 0);
}
static bool rp1_pio_sm_claim_mask(PIO pio, uint mask) {
struct rp1_pio_sm_claim_args args = {.mask = mask};
valid_params_if(PIO, !!mask);
check_sm_mask(mask);
return (rp1_ioctl(pio, PIO_IOC_SM_CLAIM, &args) >= 0);
}
static bool rp1_pio_sm_unclaim(PIO pio, uint sm) {
struct rp1_pio_sm_claim_args args = {.mask = (1 << sm)};
check_sm_param(sm);
return !rp1_ioctl(pio, PIO_IOC_SM_UNCLAIM, &args);
}
static int rp1_pio_sm_claim_unused(PIO pio, bool required) {
struct rp1_pio_sm_claim_args args = {.mask = 0};
int sm = rp1_ioctl(pio, PIO_IOC_SM_CLAIM, &args);
if (sm < 0 && required)
pio_panic("No PIO state machines are available");
return sm;
}
static bool rp1_pio_sm_is_claimed(PIO pio, uint sm) {
struct rp1_pio_sm_claim_args args = {.mask = (1 << sm)};
check_sm_param(sm);
int err = rp1_ioctl(pio, PIO_IOC_SM_IS_CLAIMED, &args);
return (err > 0);
}
static void rp1_pio_sm_init(PIO pio, uint sm, uint initial_pc,
const pio_sm_config *config) {
smc_to_rp1(config, c);
struct rp1_pio_sm_init_args args = {
.sm = sm, .initial_pc = initial_pc, .config = *c};
valid_params_if(PIO, initial_pc < RP1_PIO_INSTRUCTION_COUNT);
(void)rp1_ioctl(pio, PIO_IOC_SM_INIT, &args);
}
static void rp1_pio_sm_set_config(PIO pio, uint sm,
const pio_sm_config *config) {
smc_to_rp1(config, c);
struct rp1_pio_sm_init_args args = {.sm = sm, .config = *c};
check_sm_param(sm);
(void)rp1_ioctl(pio, PIO_IOC_SM_SET_CONFIG, &args);
}
static void rp1_pio_sm_exec(PIO pio, uint sm, uint instr, bool blocking) {
struct rp1_pio_sm_exec_args args = {
.sm = sm, .instr = instr, .blocking = blocking};
check_sm_param(sm);
(void)rp1_ioctl(pio, PIO_IOC_SM_EXEC, &args);
}
static void rp1_pio_sm_clear_fifos(PIO pio, uint sm) {
struct rp1_pio_sm_clear_fifos_args args = {.sm = sm};
check_sm_param(sm);
(void)rp1_ioctl(pio, PIO_IOC_SM_CLEAR_FIFOS, &args);
}
static void rp1_pio_calculate_clkdiv_from_float(float div, uint16_t *div_int,
uint8_t *div_frac) {
valid_params_if(PIO, div >= 1 && div <= 65536);
*div_int = (uint16_t)div;
if (*div_int == 0) {
*div_frac = 0;
} else {
*div_frac = (uint8_t)((div - (float)*div_int) * (1u << 8u));
}
}
static void rp1_pio_sm_set_clkdiv_int_frac(PIO pio, uint sm, uint16_t div_int,
uint8_t div_frac) {
struct rp1_pio_sm_set_clkdiv_args args = {
.sm = sm, .div_int = div_int, .div_frac = div_frac};
check_sm_param(sm);
invalid_params_if(PIO, div_int == 0 && div_frac != 0);
(void)rp1_ioctl(pio, PIO_IOC_SM_SET_CLKDIV, &args);
}
static void rp1_pio_sm_set_clkdiv(PIO pio, uint sm, float div) {
uint16_t div_int;
uint8_t div_frac;
check_sm_param(sm);
rp1_pio_calculate_clkdiv_from_float(div, &div_int, &div_frac);
rp1_pio_sm_set_clkdiv_int_frac(pio, sm, div_int, div_frac);
}
static void rp1_pio_sm_set_pins(PIO pio, uint sm, uint32_t pin_values) {
struct rp1_pio_sm_set_pins_args args = {
.sm = sm, .values = pin_values, .mask = GPIOS_MASK};
check_sm_param(sm);
(void)rp1_ioctl(pio, PIO_IOC_SM_SET_PINS, &args);
}
static void rp1_pio_sm_set_pins_with_mask(PIO pio, uint sm, uint32_t pin_values,
uint32_t pin_mask) {
struct rp1_pio_sm_set_pins_args args = {
.sm = sm, .values = pin_values, .mask = pin_mask};
check_sm_param(sm);
(void)rp1_ioctl(pio, PIO_IOC_SM_SET_PINS, &args);
}
static void rp1_pio_sm_set_pindirs_with_mask(PIO pio, uint sm,
uint32_t pin_dirs,
uint32_t pin_mask) {
struct rp1_pio_sm_set_pindirs_args args = {
.sm = sm, .dirs = pin_dirs, .mask = pin_mask};
check_sm_param(sm);
valid_params_if(PIO, (pin_dirs & GPIOS_MASK) == pin_dirs);
valid_params_if(PIO, (pin_mask & pin_mask) == pin_mask);
(void)rp1_ioctl(pio, PIO_IOC_SM_SET_PINDIRS, &args);
}
static void rp1_pio_sm_set_consecutive_pindirs(PIO pio, uint sm, uint pin_base,
uint pin_count, bool is_out) {
uint32_t mask = ((1 << pin_count) - 1) << pin_base;
struct rp1_pio_sm_set_pindirs_args args = {
.sm = sm, .dirs = is_out ? mask : 0, .mask = mask};
check_sm_param(sm);
valid_params_if(PIO, pin_base < RP1_PIO_GPIO_COUNT &&
pin_count < RP1_PIO_GPIO_COUNT &&
(pin_base + pin_count) < RP1_PIO_GPIO_COUNT);
(void)rp1_ioctl(pio, PIO_IOC_SM_SET_PINDIRS, &args);
}
static void rp1_pio_sm_set_enabled(PIO pio, uint sm, bool enabled) {
struct rp1_pio_sm_set_enabled_args args = {.mask = (1 << sm),
.enable = enabled};
check_sm_param(sm);
(void)rp1_ioctl(pio, PIO_IOC_SM_SET_ENABLED, &args);
}
static void rp1_pio_sm_set_enabled_mask(PIO pio, uint32_t mask, bool enabled) {
struct rp1_pio_sm_set_enabled_args args = {.mask = (uint16_t)mask,
.enable = enabled};
check_sm_mask(mask);
(void)rp1_ioctl(pio, PIO_IOC_SM_SET_ENABLED, &args);
}
static void rp1_pio_sm_restart(PIO pio, uint sm) {
struct rp1_pio_sm_restart_args args = {.mask = (1 << sm)};
check_sm_param(sm);
(void)rp1_ioctl(pio, PIO_IOC_SM_RESTART, &args);
}
static void rp1_pio_sm_restart_mask(PIO pio, uint32_t mask) {
struct rp1_pio_sm_restart_args args = {.mask = (uint16_t)mask};
check_sm_mask(mask);
(void)rp1_ioctl(pio, PIO_IOC_SM_RESTART, &args);
}
static void rp1_pio_sm_clkdiv_restart(PIO pio, uint sm) {
struct rp1_pio_sm_restart_args args = {.mask = (1 << sm)};
check_sm_param(sm);
(void)rp1_ioctl(pio, PIO_IOC_SM_CLKDIV_RESTART, &args);
}
static void rp1_pio_sm_clkdiv_restart_mask(PIO pio, uint32_t mask) {
struct rp1_pio_sm_restart_args args = {.mask = (uint16_t)mask};
check_sm_mask(mask);
(void)rp1_ioctl(pio, PIO_IOC_SM_CLKDIV_RESTART, &args);
}
static void rp1_pio_sm_enable_sync(PIO pio, uint32_t mask) {
struct rp1_pio_sm_enable_sync_args args = {.mask = (uint16_t)mask};
check_sm_mask(mask);
(void)rp1_ioctl(pio, PIO_IOC_SM_ENABLE_SYNC, &args);
}
static void rp1_pio_sm_put(PIO pio, uint sm, uint32_t data, bool blocking) {
struct rp1_pio_sm_put_args args = {
.sm = (uint16_t)sm, .blocking = blocking, .data = data};
check_sm_param(sm);
(void)rp1_ioctl(pio, PIO_IOC_SM_PUT, &args);
}
static uint32_t rp1_pio_sm_get(PIO pio, uint sm, bool blocking) {
struct rp1_pio_sm_get_args args = {.sm = (uint16_t)sm,
.blocking = blocking};
check_sm_param(sm);
(void)rp1_ioctl(pio, PIO_IOC_SM_GET, &args);
return args.data;
}
static void rp1_pio_sm_set_dmactrl(PIO pio, uint sm, bool is_tx,
uint32_t ctrl) {
struct rp1_pio_sm_set_dmactrl_args args = {
.sm = sm, .is_tx = is_tx, .ctrl = ctrl};
check_sm_param(sm);
(void)rp1_ioctl(pio, PIO_IOC_SM_SET_DMACTRL, &args);
}
static bool rp1_pio_sm_is_rx_fifo_empty(PIO pio, uint sm) {
struct rp1_pio_sm_fifo_state_args args = {.sm = sm, .tx = false};
check_sm_param(sm);
(void)rp1_ioctl(pio, PIO_IOC_SM_FIFO_STATE, &args);
return args.empty;
}
static bool rp1_pio_sm_is_rx_fifo_full(PIO pio, uint sm) {
struct rp1_pio_sm_fifo_state_args args = {.sm = sm, .tx = false};
check_sm_param(sm);
(void)rp1_ioctl(pio, PIO_IOC_SM_FIFO_STATE, &args);
return args.full;
}
static uint rp1_pio_sm_get_rx_fifo_level(PIO pio, uint sm) {
struct rp1_pio_sm_fifo_state_args args = {.sm = sm, .tx = false};
check_sm_param(sm);
(void)rp1_ioctl(pio, PIO_IOC_SM_FIFO_STATE, &args);
return args.level;
}
static bool rp1_pio_sm_is_tx_fifo_empty(PIO pio, uint sm) {
struct rp1_pio_sm_fifo_state_args args = {.sm = sm, .tx = true};
check_sm_param(sm);
(void)rp1_ioctl(pio, PIO_IOC_SM_FIFO_STATE, &args);
return args.empty;
}
static bool rp1_pio_sm_is_tx_fifo_full(PIO pio, uint sm) {
struct rp1_pio_sm_fifo_state_args args = {.sm = sm, .tx = true};
check_sm_param(sm);
(void)rp1_ioctl(pio, PIO_IOC_SM_FIFO_STATE, &args);
return args.full;
}
static uint rp1_pio_sm_get_tx_fifo_level(PIO pio, uint sm) {
struct rp1_pio_sm_fifo_state_args args = {.sm = sm, .tx = true};
check_sm_param(sm);
(void)rp1_ioctl(pio, PIO_IOC_SM_FIFO_STATE, &args);
return args.level;
}
static void rp1_pio_sm_drain_tx_fifo(PIO pio, uint sm) {
struct rp1_pio_sm_clear_fifos_args args = {.sm = sm};
check_sm_param(sm);
(void)rp1_ioctl(pio, PIO_IOC_SM_DRAIN_TX, &args);
}
static void rp1_smc_set_out_pins(PIO pio, pio_sm_config *config, uint out_base,
uint out_count) {
smc_to_rp1(config, c);
valid_params_if(PIO, out_base < RP1_PIO_GPIO_COUNT);
valid_params_if(PIO, out_count <= RP1_PIO_GPIO_COUNT);
c->pinctrl = (c->pinctrl & ~(PROC_PIO_SM0_PINCTRL_OUT_BASE_BITS |
PROC_PIO_SM0_PINCTRL_OUT_COUNT_BITS)) |
(out_base << PROC_PIO_SM0_PINCTRL_OUT_BASE_LSB) |
(out_count << PROC_PIO_SM0_PINCTRL_OUT_COUNT_LSB);
}
static void rp1_smc_set_set_pins(PIO pio, pio_sm_config *config, uint set_base,
uint set_count) {
smc_to_rp1(config, c);
valid_params_if(PIO, set_base < RP1_PIO_GPIO_COUNT);
valid_params_if(PIO, set_count <= 5);
c->pinctrl = (c->pinctrl & ~(PROC_PIO_SM0_PINCTRL_SET_BASE_BITS |
PROC_PIO_SM0_PINCTRL_SET_COUNT_BITS)) |
(set_base << PROC_PIO_SM0_PINCTRL_SET_BASE_LSB) |
(set_count << PROC_PIO_SM0_PINCTRL_SET_COUNT_LSB);
}
static void rp1_smc_set_in_pins(PIO pio, pio_sm_config *config, uint in_base) {
smc_to_rp1(config, c);
valid_params_if(PIO, in_base < RP1_PIO_GPIO_COUNT);
c->pinctrl = (c->pinctrl & ~PROC_PIO_SM0_PINCTRL_IN_BASE_BITS) |
(in_base << PROC_PIO_SM0_PINCTRL_IN_BASE_LSB);
}
static void rp1_smc_set_sideset_pins(PIO pio, pio_sm_config *config,
uint sideset_base) {
smc_to_rp1(config, c);
valid_params_if(PIO, sideset_base < RP1_PIO_GPIO_COUNT);
c->pinctrl = (c->pinctrl & ~PROC_PIO_SM0_PINCTRL_SIDESET_BASE_BITS) |
(sideset_base << PROC_PIO_SM0_PINCTRL_SIDESET_BASE_LSB);
}
static void rp1_smc_set_sideset(PIO pio, pio_sm_config *config, uint bit_count,
bool optional, bool pindirs) {
smc_to_rp1(config, c);
valid_params_if(PIO, bit_count <= 5);
valid_params_if(PIO, !optional || bit_count >= 1);
c->pinctrl = (c->pinctrl & ~PROC_PIO_SM0_PINCTRL_SIDESET_COUNT_BITS) |
(bit_count << PROC_PIO_SM0_PINCTRL_SIDESET_COUNT_LSB);
c->execctrl =
(c->execctrl & ~(PROC_PIO_SM0_EXECCTRL_SIDE_EN_BITS |
PROC_PIO_SM0_EXECCTRL_SIDE_PINDIR_BITS)) |
(bool_to_bit(optional) << PROC_PIO_SM0_EXECCTRL_SIDE_EN_LSB) |
(bool_to_bit(pindirs) << PROC_PIO_SM0_EXECCTRL_SIDE_PINDIR_LSB);
}
static void rp1_smc_set_clkdiv_int_frac(PIO pio, pio_sm_config *config,
uint16_t div_int, uint8_t div_frac) {
smc_to_rp1(config, c);
invalid_params_if(PIO, div_int == 0 && div_frac != 0);
c->clkdiv = (((uint)div_frac) << PROC_PIO_SM0_CLKDIV_FRAC_LSB) |
(((uint)div_int) << PROC_PIO_SM0_CLKDIV_INT_LSB);
}
static void rp1_smc_set_clkdiv(PIO pio, pio_sm_config *config, float div) {
uint16_t div_int;
uint8_t div_frac;
rp1_pio_calculate_clkdiv_from_float(div, &div_int, &div_frac);
sm_config_set_clkdiv_int_frac(config, div_int, div_frac);
}
static void rp1_smc_set_wrap(PIO pio, pio_sm_config *config, uint wrap_target,
uint wrap) {
smc_to_rp1(config, c);
valid_params_if(PIO, wrap < RP1_PIO_INSTRUCTION_COUNT);
valid_params_if(PIO, wrap_target < RP1_PIO_INSTRUCTION_COUNT);
c->execctrl = (c->execctrl & ~(PROC_PIO_SM0_EXECCTRL_WRAP_TOP_BITS |
PROC_PIO_SM0_EXECCTRL_WRAP_BOTTOM_BITS)) |
(wrap_target << PROC_PIO_SM0_EXECCTRL_WRAP_BOTTOM_LSB) |
(wrap << PROC_PIO_SM0_EXECCTRL_WRAP_TOP_LSB);
}
static void rp1_smc_set_jmp_pin(PIO pio, pio_sm_config *config, uint pin) {
smc_to_rp1(config, c);
valid_params_if(PIO, pin < RP1_PIO_GPIO_COUNT);
c->execctrl = (c->execctrl & ~PROC_PIO_SM0_EXECCTRL_JMP_PIN_BITS) |
(pin << PROC_PIO_SM0_EXECCTRL_JMP_PIN_LSB);
}
static void rp1_smc_set_in_shift(PIO pio, pio_sm_config *config,
bool shift_right, bool autopush,
uint push_threshold) {
smc_to_rp1(config, c);
valid_params_if(PIO, push_threshold <= 32);
c->shiftctrl =
(c->shiftctrl & ~(PROC_PIO_SM0_SHIFTCTRL_IN_SHIFTDIR_BITS |
PROC_PIO_SM0_SHIFTCTRL_AUTOPUSH_BITS |
PROC_PIO_SM0_SHIFTCTRL_PUSH_THRESH_BITS)) |
(bool_to_bit(shift_right) << PROC_PIO_SM0_SHIFTCTRL_IN_SHIFTDIR_LSB) |
(bool_to_bit(autopush) << PROC_PIO_SM0_SHIFTCTRL_AUTOPUSH_LSB) |
((push_threshold & 0x1fu) << PROC_PIO_SM0_SHIFTCTRL_PUSH_THRESH_LSB);
}
static void rp1_smc_set_out_shift(PIO pio, pio_sm_config *config,
bool shift_right, bool autopull,
uint pull_threshold) {
smc_to_rp1(config, c);
valid_params_if(PIO, pull_threshold <= 32);
c->shiftctrl =
(c->shiftctrl & ~(PROC_PIO_SM0_SHIFTCTRL_OUT_SHIFTDIR_BITS |
PROC_PIO_SM0_SHIFTCTRL_AUTOPULL_BITS |
PROC_PIO_SM0_SHIFTCTRL_PULL_THRESH_BITS)) |
(bool_to_bit(shift_right) << PROC_PIO_SM0_SHIFTCTRL_OUT_SHIFTDIR_LSB) |
(bool_to_bit(autopull) << PROC_PIO_SM0_SHIFTCTRL_AUTOPULL_LSB) |
((pull_threshold & 0x1fu) << PROC_PIO_SM0_SHIFTCTRL_PULL_THRESH_LSB);
}
static void rp1_smc_set_fifo_join(PIO pio, pio_sm_config *config,
enum pio_fifo_join join) {
smc_to_rp1(config, c);
valid_params_if(PIO, join == PIO_FIFO_JOIN_NONE ||
join == PIO_FIFO_JOIN_TX ||
join == PIO_FIFO_JOIN_RX);
c->shiftctrl =
(c->shiftctrl & (uint) ~(PROC_PIO_SM0_SHIFTCTRL_FJOIN_TX_BITS |
PROC_PIO_SM0_SHIFTCTRL_FJOIN_RX_BITS)) |
(((uint)join) << PROC_PIO_SM0_SHIFTCTRL_FJOIN_TX_LSB);
}
static void rp1_smc_set_out_special(PIO pio, pio_sm_config *config, bool sticky,
bool has_enable_pin,
uint enable_pin_index) {
smc_to_rp1(config, c);
c->execctrl =
(c->execctrl & (uint) ~(PROC_PIO_SM0_EXECCTRL_OUT_STICKY_BITS |
PROC_PIO_SM0_EXECCTRL_INLINE_OUT_EN_BITS |
PROC_PIO_SM0_EXECCTRL_OUT_EN_SEL_BITS)) |
(bool_to_bit(sticky) << PROC_PIO_SM0_EXECCTRL_OUT_STICKY_LSB) |
(bool_to_bit(has_enable_pin)
<< PROC_PIO_SM0_EXECCTRL_INLINE_OUT_EN_LSB) |
((enable_pin_index << PROC_PIO_SM0_EXECCTRL_OUT_EN_SEL_LSB) &
PROC_PIO_SM0_EXECCTRL_OUT_EN_SEL_BITS);
}
static void rp1_smc_set_mov_status(PIO pio, pio_sm_config *config,
enum pio_mov_status_type status_sel,
uint status_n) {
smc_to_rp1(config, c);
valid_params_if(PIO, status_sel == STATUS_TX_LESSTHAN ||
status_sel == STATUS_RX_LESSTHAN);
c->execctrl =
(c->execctrl & ~(PROC_PIO_SM0_EXECCTRL_STATUS_SEL_BITS |
PROC_PIO_SM0_EXECCTRL_STATUS_N_BITS)) |
((((uint)status_sel) << PROC_PIO_SM0_EXECCTRL_STATUS_SEL_LSB) &
PROC_PIO_SM0_EXECCTRL_STATUS_SEL_BITS) |
((status_n << PROC_PIO_SM0_EXECCTRL_STATUS_N_LSB) &
PROC_PIO_SM0_EXECCTRL_STATUS_N_BITS);
}
static uint32_t rp1_clock_get_hz(PIO pio, enum clock_index clk_index) {
const uint32_t MHZ = 1000000;
switch (clk_index) {
case clk_sys:
return 200 * MHZ;
default:
break;
}
return PIO_ORIGIN_ANY;
}
static void rp1_gpio_init(PIO pio, uint gpio) {
struct rp1_gpio_init_args args = {.gpio = gpio};
valid_params_if(PIO, gpio < RP1_PIO_GPIO_COUNT);
(void)rp1_ioctl(pio, PIO_IOC_GPIO_INIT, &args);
}
static void rp1_gpio_set_function(PIO pio, uint gpio, enum gpio_function fn) {
struct rp1_gpio_set_function_args args = {.gpio = gpio, .fn = fn};
valid_params_if(PIO, gpio < RP1_PIO_GPIO_COUNT);
(void)rp1_ioctl(pio, PIO_IOC_GPIO_SET_FUNCTION, &args);
}
static void rp1_gpio_set_pulls(PIO pio, uint gpio, bool up, bool down) {
struct rp1_gpio_set_pulls_args args = {
.gpio = gpio, .up = up, .down = down};
valid_params_if(PIO, gpio < RP1_PIO_GPIO_COUNT);
(void)rp1_ioctl(pio, PIO_IOC_GPIO_SET_PULLS, &args);
}
static void rp1_gpio_set_outover(PIO pio, uint gpio, uint value) {
struct rp1_gpio_set_args args = {.gpio = gpio, .value = value};
valid_params_if(PIO, gpio < RP1_PIO_GPIO_COUNT);
(void)rp1_ioctl(pio, PIO_IOC_GPIO_SET_OUTOVER, &args);
}
static void rp1_gpio_set_inover(PIO pio, uint gpio, uint value) {
struct rp1_gpio_set_args args = {.gpio = gpio, .value = value};
valid_params_if(PIO, gpio < RP1_PIO_GPIO_COUNT);
(void)rp1_ioctl(pio, PIO_IOC_GPIO_SET_INOVER, &args);
}
static void rp1_gpio_set_oeover(PIO pio, uint gpio, uint value) {
struct rp1_gpio_set_args args = {.gpio = gpio, .value = value};
valid_params_if(PIO, gpio < RP1_PIO_GPIO_COUNT);
(void)rp1_ioctl(pio, PIO_IOC_GPIO_SET_OEOVER, &args);
}
static void rp1_gpio_set_input_enabled(PIO pio, uint gpio, bool enabled) {
struct rp1_gpio_set_args args = {.gpio = gpio, .value = enabled};
valid_params_if(PIO, gpio < RP1_PIO_GPIO_COUNT);
(void)rp1_ioctl(pio, PIO_IOC_GPIO_SET_INPUT_ENABLED, &args);
}
static void rp1_gpio_set_drive_strength(PIO pio, uint gpio,
enum gpio_drive_strength drive) {
struct rp1_gpio_set_args args = {.gpio = gpio, .value = drive};
valid_params_if(PIO, gpio < RP1_PIO_GPIO_COUNT);
(void)rp1_ioctl(pio, PIO_IOC_GPIO_SET_DRIVE_STRENGTH, &args);
}
static void rp1_pio_gpio_init(PIO pio, uint pin) {
valid_params_if(PIO, pin < RP1_PIO_GPIO_COUNT);
rp1_gpio_set_function(pio, pin, (gpio_function)RP1_GPIO_FUNC_PIO);
}
PIO rp1_create_instance(PIO_CHIP_T *chip, uint index) {
char pathbuf[20];
RP1_PIO pio = NULL;
sprintf(pathbuf, "/dev/pio%u", index);
if (access(pathbuf, F_OK) != 0)
return NULL;
pio = (RP1_PIO)calloc(1, sizeof(*pio));
if (!pio)
return PIO_ERR(-ENOMEM);
pio->base.chip = chip;
pio->fd = -1;
pio->devname = strdup(pathbuf);
rp1_pio_clear_instruction_memory(&pio->base);
return &pio->base;
}
int rp1_open_instance(PIO pio) {
RP1_PIO rp = (RP1_PIO)pio;
int fd;
fd = open(rp->devname, O_RDWR, O_CLOEXEC);
if (fd < 0)
return -errno;
rp->fd = fd;
return 0;
}
void rp1_close_instance(PIO pio) {
RP1_PIO rp = (RP1_PIO)pio;
close(rp->fd);
}
static const PIO_CHIP_T rp1_pio_chip = {
.name = "rp1",
.compatible = "raspberrypi,rp1-pio",
.instr_count = RP1_PIO_INSTRUCTION_COUNT,
.sm_count = RP1_PIO_SM_COUNT,
.fifo_depth = 8,
.create_instance = rp1_create_instance,
.open_instance = rp1_open_instance,
.close_instance = rp1_close_instance,
.pio_sm_config_xfer = rp1_pio_sm_config_xfer,
.pio_sm_xfer_data = rp1_pio_sm_xfer_data,
.pio_can_add_program_at_offset = rp1_pio_can_add_program_at_offset,
.pio_add_program_at_offset = rp1_pio_add_program_at_offset,
.pio_remove_program = rp1_pio_remove_program,
.pio_clear_instruction_memory = rp1_pio_clear_instruction_memory,
.pio_encode_delay = rp1_pio_encode_delay,
.pio_encode_sideset = rp1_pio_encode_sideset,
.pio_encode_sideset_opt = rp1_pio_encode_sideset_opt,
.pio_encode_jmp = rp1_pio_encode_jmp,
.pio_encode_jmp_not_x = rp1_pio_encode_jmp_not_x,
.pio_encode_jmp_x_dec = rp1_pio_encode_jmp_x_dec,
.pio_encode_jmp_not_y = rp1_pio_encode_jmp_not_y,
.pio_encode_jmp_y_dec = rp1_pio_encode_jmp_y_dec,
.pio_encode_jmp_x_ne_y = rp1_pio_encode_jmp_x_ne_y,
.pio_encode_jmp_pin = rp1_pio_encode_jmp_pin,
.pio_encode_jmp_not_osre = rp1_pio_encode_jmp_not_osre,
.pio_encode_wait_gpio = rp1_pio_encode_wait_gpio,
.pio_encode_wait_pin = rp1_pio_encode_wait_pin,
.pio_encode_wait_irq = rp1_pio_encode_wait_irq,
.pio_encode_in = rp1_pio_encode_in,
.pio_encode_out = rp1_pio_encode_out,
.pio_encode_push = rp1_pio_encode_push,
.pio_encode_pull = rp1_pio_encode_pull,
.pio_encode_mov = rp1_pio_encode_mov,
.pio_encode_mov_not = rp1_pio_encode_mov_not,
.pio_encode_mov_reverse = rp1_pio_encode_mov_reverse,
.pio_encode_irq_set = rp1_pio_encode_irq_set,
.pio_encode_irq_wait = rp1_pio_encode_irq_wait,
.pio_encode_irq_clear = rp1_pio_encode_irq_clear,
.pio_encode_set = rp1_pio_encode_set,
.pio_encode_nop = rp1_pio_encode_nop,
.pio_sm_claim = rp1_pio_sm_claim,
.pio_sm_claim_mask = rp1_pio_sm_claim_mask,
.pio_sm_claim_unused = rp1_pio_sm_claim_unused,
.pio_sm_unclaim = rp1_pio_sm_unclaim,
.pio_sm_is_claimed = rp1_pio_sm_is_claimed,
.pio_sm_init = rp1_pio_sm_init,
.pio_sm_set_config = rp1_pio_sm_set_config,
.pio_sm_exec = rp1_pio_sm_exec,
.pio_sm_clear_fifos = rp1_pio_sm_clear_fifos,
.pio_sm_set_clkdiv_int_frac = &rp1_pio_sm_set_clkdiv_int_frac,
.pio_sm_set_clkdiv = rp1_pio_sm_set_clkdiv,
.pio_sm_set_pins = rp1_pio_sm_set_pins,
.pio_sm_set_pins_with_mask = rp1_pio_sm_set_pins_with_mask,
.pio_sm_set_pindirs_with_mask = rp1_pio_sm_set_pindirs_with_mask,
.pio_sm_set_consecutive_pindirs = rp1_pio_sm_set_consecutive_pindirs,
.pio_sm_set_enabled = rp1_pio_sm_set_enabled,
.pio_sm_set_enabled_mask = rp1_pio_sm_set_enabled_mask,
.pio_sm_restart = rp1_pio_sm_restart,
.pio_sm_restart_mask = rp1_pio_sm_restart_mask,
.pio_sm_clkdiv_restart = rp1_pio_sm_clkdiv_restart,
.pio_sm_clkdiv_restart_mask = rp1_pio_sm_clkdiv_restart_mask,
.pio_sm_enable_sync = rp1_pio_sm_enable_sync,
.pio_sm_put = rp1_pio_sm_put,
.pio_sm_get = rp1_pio_sm_get,
.pio_sm_set_dmactrl = rp1_pio_sm_set_dmactrl,
.pio_sm_is_rx_fifo_empty = rp1_pio_sm_is_rx_fifo_empty,
.pio_sm_is_rx_fifo_full = rp1_pio_sm_is_rx_fifo_full,
.pio_sm_get_rx_fifo_level = rp1_pio_sm_get_rx_fifo_level,
.pio_sm_is_tx_fifo_empty = rp1_pio_sm_is_tx_fifo_empty,
.pio_sm_is_tx_fifo_full = rp1_pio_sm_is_tx_fifo_full,
.pio_sm_get_tx_fifo_level = rp1_pio_sm_get_tx_fifo_level,
.pio_sm_drain_tx_fifo = rp1_pio_sm_drain_tx_fifo,
.pio_get_default_sm_config = rp1_pio_get_default_sm_config,
.smc_set_out_pins = rp1_smc_set_out_pins,
.smc_set_set_pins = rp1_smc_set_set_pins,
.smc_set_in_pins = rp1_smc_set_in_pins,
.smc_set_sideset_pins = rp1_smc_set_sideset_pins,
.smc_set_sideset = rp1_smc_set_sideset,
.smc_set_clkdiv_int_frac = rp1_smc_set_clkdiv_int_frac,
.smc_set_clkdiv = rp1_smc_set_clkdiv,
.smc_set_wrap = rp1_smc_set_wrap,
.smc_set_jmp_pin = rp1_smc_set_jmp_pin,
.smc_set_in_shift = rp1_smc_set_in_shift,
.smc_set_out_shift = rp1_smc_set_out_shift,
.smc_set_fifo_join = rp1_smc_set_fifo_join,
.smc_set_out_special = rp1_smc_set_out_special,
.smc_set_mov_status = rp1_smc_set_mov_status,
.clock_get_hz = rp1_clock_get_hz,
.pio_gpio_init = rp1_pio_gpio_init,
.gpio_init = rp1_gpio_init,
.gpio_set_function = rp1_gpio_set_function,
.gpio_set_pulls = rp1_gpio_set_pulls,
.gpio_set_outover = rp1_gpio_set_outover,
.gpio_set_inover = rp1_gpio_set_inover,
.gpio_set_oeover = rp1_gpio_set_oeover,
.gpio_set_input_enabled = rp1_gpio_set_input_enabled,
.gpio_set_drive_strength = rp1_gpio_set_drive_strength,
};
DECLARE_PIO_CHIP(rp1_pio_chip);

164
piolib/piolib.c Normal file
View file

@ -0,0 +1,164 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2023-24 Raspberry Pi Ltd.
* All rights reserved.
*/
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include "piolib.h"
#include "piolib_priv.h"
#define PIO_MAX_INSTANCES 4
extern PIO_CHIP_T *__start_piochips;
extern PIO_CHIP_T *__stop_piochips;
static __thread PIO __pio;
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; }
PIO pio_get_current(void) {
PIO pio = __pio;
check_pio_param(pio);
return pio;
}
int pio_get_index(PIO pio) {
int i;
for (i = 0; i < PIO_MAX_INSTANCES; i++) {
if (pio == pio_instances[i])
return i;
}
return -1;
}
int pio_init(void) {
static bool initialised;
const PIO_CHIP_T *const *p;
uint i = 0;
int err;
if (initialised)
return 0;
num_instances = 0;
p = &__start_piochips;
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)) {
pio_instances[num_instances++] = pio;
i++;
} else {
p++;
i = 0;
}
}
err = pthread_mutex_init(&pio_handle_lock, NULL);
if (err)
return err;
initialised = true;
return 0;
}
PIO pio_open(uint idx) {
PIO pio = NULL;
int err;
err = pio_init();
if (err)
return PIO_ERR(err);
if (idx >= num_instances)
return PIO_ERR(-EINVAL);
pthread_mutex_lock(&pio_handle_lock);
pio = pio_instances[idx];
if (pio) {
if (pio->in_use)
err = -EBUSY;
else
pio->in_use = 1;
}
pthread_mutex_unlock(&pio_handle_lock);
if (err)
return PIO_ERR(err);
err = pio->chip->open_instance(pio);
if (err) {
pio->in_use = 0;
return PIO_ERR(err);
}
pio_select(pio);
return pio;
}
PIO pio_open_by_name(const char *name) {
int err = -ENOENT;
uint i;
err = pio_init();
if (err)
return PIO_ERR(err);
for (i = 0; i < num_instances; i++) {
PIO p = pio_instances[i];
if (!strcmp(name, p->chip->name))
break;
}
if (i == num_instances)
return PIO_ERR(-ENOENT);
return pio_open(i);
}
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));
exit(1);
}
}
return 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) {
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)};
nanosleep(&tv, NULL);
}

BIN
protodemo Executable file

Binary file not shown.

173
protodemo.c Normal file
View file

@ -0,0 +1,173 @@
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include <vector>
#include "hardware/pio.h"
#include "protomatter.pio.h"
#define PIN_R0 (5)
#define PIN_G0 (13)
#define PIN_B0 (6)
#define PIN_R1 (12)
#define PIN_G1 (16)
#define PIN_B1 (23)
#define PIN_ADDR_A (22)
#define PIN_ADDR_B (26)
#define PIN_ADDR_C (27)
#define PIN_ADDR_D (20)
#define PIN_ADDR_E (24)
#define PIN_OE (4) // /OE: output enable when LOW
#define PIN_CLK (17) // SRCLK: clocks on RISING edge
#define PIN_LAT (21) // RCLK: latches on RISING edge
const uint8_t all_pins[] = {
PIN_R0,
PIN_G0,
PIN_B0,
PIN_R1,
PIN_G1,
PIN_B1,
PIN_ADDR_A,
PIN_ADDR_B,
PIN_ADDR_C,
// PIN_ADDR_D,
// PIN_ADDR_E,
PIN_OE,
PIN_CLK,
PIN_LAT,
};
#define DATA_OVERHEAD (5)
#define DELAY_OVERHEAD (3)
#define CLOCKS_PER_DELAY (1)
// so for example a DATA word with a delay of 3 will take DATA_OVERHEAD+3*CLOCKS_PER_DELAY
static const struct pio_program protomatter_program = {
.instructions = protomatter,
.length = 32,
.origin = -1,
};
static inline pio_sm_config protomatter_program_get_default_config(uint offset) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, offset + protomatter_wrap_target, offset + protomatter_wrap);
return c;
}
static inline void protomatter_program_init(PIO pio, int sm, uint offset) {
for(int i=0; i<sizeof(all_pins); i++) {
int pin = all_pins[i];
pio_gpio_init(pio, pin);
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true);
}
pio_sm_config c = protomatter_program_get_default_config(offset);
}
#define ACROSS (32)
#define DOWN (16)
#define _ (1)
#define r (1)
#define g (2)
#define b (4)
#define y (r|g)
#define c (g|b)
#define m (r|b)
#define w (7)
uint8_t pixels[DOWN][ACROSS] = {
{_,w,_,_,r,r,_,_,_,g,_,_,b,b,b,_,c,c,_,_,y,_,y,_,m,m,m,_,w,w,w,_}, // 0
{w,_,w,_,r,_,r,_,g,_,g,_,b,_,_,_,c,_,c,_,y,_,y,_,_,m,_,_,_,w,_,_}, // 1
{w,w,w,_,r,_,r,_,g,g,g,_,b,b,_,_,c,c,_,_,y,_,y,_,_,m,_,_,_,w,_,_}, // 2
{w,_,w,_,r,_,r,_,g,_,g,_,b,_,_,_,c,_,c,_,y,_,y,_,_,m,_,_,_,w,_,_}, // 3
{w,_,w,_,r,r,_,_,g,_,g,_,b,_,_,_,c,_,c,_,_,y,_,_,m,m,m,_,_,w,_,_}, // 4
{_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_}, // 5
{r,_,r,_,r,_,r,_,r,_,r,_,r,_,r,_,r,_,r,_,r,_,r,_,r,_,r,_,r,_,r,_}, // 6
{r,r,_,_,r,r,_,_,r,r,_,_,r,r,_,_,r,r,_,_,r,r,_,_,r,r,_,_,r,r,_,_}, // 7
{g,_,g,_,g,_,g,_,g,_,g,_,g,_,g,_,g,_,g,_,g,_,g,_,g,_,g,_,g,_,g,_}, // 8
{g,g,_,_,g,g,_,_,g,g,_,_,g,g,_,_,g,g,_,_,g,g,_,_,g,g,_,_,g,g,_,_}, // 9
{b,_,b,_,b,_,b,_,b,_,b,_,b,_,b,_,b,_,b,_,b,_,b,_,b,_,b,_,b,_,b,_}, // 10
{b,b,_,_,b,b,_,_,b,b,_,_,b,b,_,_,b,b,_,_,b,b,_,_,b,b,_,_,b,b,_,_}, // 11
{w,_,w,_,w,_,w,_,w,_,w,_,w,_,w,_,w,_,w,_,w,_,w,_,w,_,w,_,w,_,w,_}, // 12
{w,w,_,_,w,w,_,_,w,w,_,_,w,w,_,_,w,w,_,_,w,w,_,_,w,w,_,_,w,w,_,_}, // 13
{_,w,_,w,_,w,_,w,_,w,_,w,_,w,_,w,_,w,_,w,_,w,_,w,_,w,_,w,_,w,_,w}, // 13
{_,w,w,_,_,w,w,_,_,w,w,_,_,w,w,_,_,w,w,_,_,w,w,_,_,w,w,_,_,w,w,_}, // 15
};
constexpr uint32_t data_delay = 1;
constexpr uint32_t clock_delay = 3;
constexpr uint32_t latch_delay = 3;
constexpr uint32_t data_bit = 1u <<31;
constexpr uint32_t delay_bit = 0;
constexpr uint32_t clk_bit = 1u << PIN_CLK;
constexpr uint32_t lat_bit = 1u << PIN_LAT;
constexpr uint32_t oe_bit = 1u << PIN_LAT;
constexpr uint32_t oe_active = 0;
constexpr uint32_t oe_inactive = oe_bit;
constexpr uint32_t pre_latch_delay = 10;
constexpr uint32_t post_latch_delay = 15;
std::vector<uint32_t> test_pattern() {
std::vector<uint32_t> result;
auto add_data_word = [&](bool r0, bool g0, bool b0, bool r1, bool g1, bool b1) {
uint32_t data = data_bit;
if(r0) data |= (1 << PIN_R0);
if(g0) data |= (1 << PIN_G0);
if(b0) data |= (1 << PIN_B0);
if(r1) data |= (1 << PIN_R1);
if(g1) data |= (1 << PIN_G1);
if(b1) data |= (1 << PIN_B1);
data |= oe_inactive;
result.push_back(data | data_delay);
result.push_back(data | clk_bit | clock_delay);
};
for(int addr = 0; addr < 8; addr++) {
for(int across = 0; across < ACROSS; across++) {
auto pixel0 = pixels[addr][across];
auto r0 = pixel0 & r;
auto g0 = pixel0 & g;
auto b0 = pixel0 & b;
auto pixel1 = pixels[addr][across];
auto r1 = pixel1 & r;
auto g1 = pixel1 & g;
auto b1 = pixel1 & b;
add_data_word(r0, g0, b0, r1, g1, b1);
}
result.push_back(delay_bit | oe_inactive | pre_latch_delay);
result.push_back(data_bit | oe_inactive | lat_bit | post_latch_delay);
}
return result;
}
int main() {
PIO pio = pio0;
int sm = pio_claim_unused_sm(pio, true);
pio_sm_config_xfer(pio, sm, PIO_DIR_TO_SM, 256, 1);
uint offset = pio_add_program(pio, &protomatter_program);
printf("Loaded program at %d, using sm %d\n", offset, sm);
pio_sm_clear_fifos(pio, sm);
pio_sm_set_clkdiv(pio, sm, 1.0);
protomatter_program_init(pio, sm, offset);
std::vector<uint32_t> data = test_pattern();
uint32_t *databuf = &data[0];
size_t datasize = data.size() * sizeof(uint32_t);
assert(datasize < 65536);
while(true) {
pio_sm_xfer_data(pio, sm, PIO_DIR_TO_SM, datasize, databuf);
}
}

45
protomatter.pio Normal file
View file

@ -0,0 +1,45 @@
; data format (out-shift-right):
; MSB ... LSB
; 0 ddd........ddd: 31-bit delay
; 1 ppp....ppp ddd: 28 bit data + 3-bit delay
.wrap_target
top:
; pull ;; use auto-pull
out x, 1
jmp !x do_delay
out pins, 27
out x, 4
jmp delay_loop
do_delay:
out x, 31
delay_loop:
jmp x--, delay_loop
.wrap
;; fill program out to 32 instructions
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop