WIP
This commit is contained in:
commit
833043f7fd
18 changed files with 6358 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
*.pio.h
|
||||
prototest
|
||||
5
Makefile
Normal file
5
Makefile
Normal 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
27
assemble.py
Normal 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()
|
||||
24
piolib/include/hardware/clocks.h
Normal file
24
piolib/include/hardware/clocks.h
Normal 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
|
||||
65
piolib/include/hardware/gpio.h
Normal file
65
piolib/include/hardware/gpio.h
Normal 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
|
||||
11
piolib/include/hardware/pio.h
Normal file
11
piolib/include/hardware/pio.h
Normal 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
|
||||
511
piolib/include/hardware/pio_instructions.h
Normal file
511
piolib/include/hardware/pio_instructions.h
Normal 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
|
||||
3222
piolib/include/hardware/regs/proc_pio.h
Normal file
3222
piolib/include/hardware/regs/proc_pio.h
Normal file
File diff suppressed because it is too large
Load diff
16
piolib/include/pico/stdlib.h
Normal file
16
piolib/include/pico/stdlib.h
Normal 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
|
||||
53
piolib/include/pio_platform.h
Normal file
53
piolib/include/pio_platform.h
Normal 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
829
piolib/include/piolib.h
Normal 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
|
||||
16
piolib/include/piolib_priv.h
Normal file
16
piolib/include/piolib_priv.h
Normal 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
249
piolib/include/rp1_pio_if.h
Normal 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
946
piolib/pio_rp1.c
Normal 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
164
piolib/piolib.c
Normal 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
BIN
protodemo
Executable file
Binary file not shown.
173
protodemo.c
Normal file
173
protodemo.c
Normal 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
45
protomatter.pio
Normal 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
|
||||
Loading…
Reference in a new issue