Build for 32-bit armhf
Because manylinux2014's compiler encounters errors with the upstream piolib, I took the easy way out and copied the files in and edited them. (They were also reformatted by clang-format, sigh) Tested in a partially 32-bit, partially 64-bit raspbian os install with a 32-bit python executable (arm-linux-gnueabihf). This required the `kernel=kernel8.img` line in /boot/firmware/config.txt.
This commit is contained in:
parent
4ec7bf8680
commit
fbc23c5591
19 changed files with 6261 additions and 11 deletions
8
.github/workflows/wheels.yml
vendored
8
.github/workflows/wheels.yml
vendored
|
|
@ -37,13 +37,13 @@ jobs:
|
||||||
|
|
||||||
|
|
||||||
build_wheels:
|
build_wheels:
|
||||||
name: Wheels on ${{ matrix.os }}${{ matrix.extra }}
|
name: Wheels on ${{ matrix.os }} ${{ matrix.arch }}
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: ["ubuntu-latest"]
|
os: ["ubuntu-latest"]
|
||||||
arch_linux: ["aarch64"]
|
arch: ["aarch64", "armv7l"]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
|
|
@ -57,7 +57,7 @@ jobs:
|
||||||
|
|
||||||
- uses: pypa/cibuildwheel@v2.22.0
|
- uses: pypa/cibuildwheel@v2.22.0
|
||||||
env:
|
env:
|
||||||
CIBW_ARCHS_LINUX: ${{ matrix.arch_linux }}
|
CIBW_ARCHS_LINUX: ${{ matrix.arch }}
|
||||||
CIBW_BUILD: "cp311-manylinux* cp312-manylinux* cp313-manylinux*"
|
CIBW_BUILD: "cp311-manylinux* cp312-manylinux* cp313-manylinux*"
|
||||||
CIBW_MANYLINUX_AARCH64_IMAGE: "manylinux_2_28"
|
CIBW_MANYLINUX_AARCH64_IMAGE: "manylinux_2_28"
|
||||||
- name: Verify clean directory
|
- name: Verify clean directory
|
||||||
|
|
@ -67,7 +67,7 @@ jobs:
|
||||||
- name: Upload wheels
|
- name: Upload wheels
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: wheel-${{ matrix.os }}${{ matrix.artifact-extra }}
|
name: wheel-${{ matrix.os }}${{ matrix.arch }}
|
||||||
path: wheelhouse/*.whl
|
path: wheelhouse/*.whl
|
||||||
compression-level: 0
|
compression-level: 0
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
|
||||||
3
.gitmodules
vendored
3
.gitmodules
vendored
|
|
@ -1,3 +0,0 @@
|
||||||
[submodule "src/utils"]
|
|
||||||
path = src/utils
|
|
||||||
url = https://github.com/raspberrypi/utils
|
|
||||||
4
setup.py
4
setup.py
|
|
@ -12,9 +12,9 @@ __version__ = get_version()
|
||||||
|
|
||||||
ext_modules = [
|
ext_modules = [
|
||||||
Pybind11Extension("adafruit_raspberry_pi5_neopixel_write",
|
Pybind11Extension("adafruit_raspberry_pi5_neopixel_write",
|
||||||
["src/main.cpp", "src/utils/piolib/piolib.c", "src/utils/piolib/pio_rp1.c"],
|
["src/main.cpp", "src/piolib.c", "src/pio_rp1.c"],
|
||||||
define_macros = [('VERSION_INFO', __version__)],
|
define_macros = [('VERSION_INFO', __version__)],
|
||||||
include_dirs = ['./src/utils/piolib/include'],
|
include_dirs = ['./src/include'],
|
||||||
# use this setting when debugging
|
# use this setting when debugging
|
||||||
#extra_compile_args = ["-g3", "-Og"],
|
#extra_compile_args = ["-g3", "-Og"],
|
||||||
),
|
),
|
||||||
|
|
|
||||||
29
src/README_piolib.md
Normal file
29
src/README_piolib.md
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
# piolib
|
||||||
|
|
||||||
|
PIOlib/libPIO is a user-space API to the rp1-pio driver, which gives access to the PIO hardware of RP1. It takes the form of a clone of the PICO SDK PIO API, where most of the methods are implemented as RPC calls to RP1. This allows existing PIO code to be run without (much) alteration, but runs into problems when it relies on the PIO state machine and the support code being closely coupled.
|
||||||
|
|
||||||
|
To build piolib:
|
||||||
|
1. cmake . (or create a build subdirectory and cmake ..)
|
||||||
|
2. make
|
||||||
|
|
||||||
|
If `ls -l /dev/pio0` reports that the file is not found, you may need to update your Pi 5 firmware to one with PIO support and make sure that you are running a suitably recent kernel.
|
||||||
|
If `ls -l /dev/pio0` reports that the file is owned by `root` and group `root`, you should add the following to /etc/udev/rules/99-com.rules:
|
||||||
|
```
|
||||||
|
SUBSYSTEM=="*-pio", GROUP="gpio", MODE="0660"
|
||||||
|
```
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
* piotest:
|
||||||
|
This is the normal WS2812 example LED PIO code, but using DMA to send the data. The optional parameter is the GPIO number to drive; the defailt is 2.
|
||||||
|
* piopwm:
|
||||||
|
The PWM example, unmodified except for dynamic SM allocation and a command line parameter to choose the GPIO. The optional parameter is the GPIO number to drive; the default is 4.
|
||||||
|
* piows2812:
|
||||||
|
The ws2812 example, unmodified except for dynamic SM allocation and a command line parameter to choose the GPIO. The optional parameter is the GPIO number to drive; the defailt is 2.
|
||||||
|
* rp1sm:
|
||||||
|
Show the state of the hardware for a particular SM. The parameter is the number of the state machine to inspect.
|
||||||
|
* dpi_interlace:
|
||||||
|
Nick's interlaced sync fixer. More of an example than something actually usable right now - it may eventually be built into a kernel driver. Run with "-n" or "--ntsc" to enable NTSC timing (it's PAL by default=)
|
||||||
|
|
||||||
|
Known issues:
|
||||||
|
* Blocking operations block the whole RP1 firmware interface until they complete.
|
||||||
24
src/include/hardware/clocks.h
Normal file
24
src/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
src/include/hardware/gpio.h
Normal file
65
src/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
src/include/hardware/pio.h
Normal file
11
src/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
src/include/hardware/pio_instructions.h
Normal file
511
src/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
src/include/hardware/regs/proc_pio.h
Normal file
3222
src/include/hardware/regs/proc_pio.h
Normal file
File diff suppressed because it is too large
Load diff
16
src/include/pico/stdlib.h
Normal file
16
src/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
src/include/pio_platform.h
Normal file
53
src/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
src/include/piolib.h
Normal file
829
src/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
src/include/piolib_priv.h
Normal file
16
src/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
src/include/rp1_pio_if.h
Normal file
249
src/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
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
#include <pybind11/pybind11.h>
|
#include <pybind11/pybind11.h>
|
||||||
|
|
||||||
#include "piolib.h"
|
#include "piolib.h"
|
||||||
#include "utils/piolib/examples/ws2812.pio.h"
|
#include "ws2812.pio.h"
|
||||||
|
|
||||||
#define STRINGIFY(x) #x
|
#define STRINGIFY(x) #x
|
||||||
#define MACRO_STRINGIFY(x) STRINGIFY(x)
|
#define MACRO_STRINGIFY(x) STRINGIFY(x)
|
||||||
|
|
|
||||||
946
src/pio_rp1.c
Normal file
946
src/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, 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 = 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
src/piolib.c
Normal file
164
src/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);
|
||||||
|
}
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit 63929145cc639d6cb4715073df4efaf50d38d939
|
|
||||||
119
src/ws2812.pio.h
Normal file
119
src/ws2812.pio.h
Normal file
|
|
@ -0,0 +1,119 @@
|
||||||
|
// -------------------------------------------------- //
|
||||||
|
// This file is autogenerated by pioasm; do not edit! //
|
||||||
|
// -------------------------------------------------- //
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if !PICO_NO_HARDWARE
|
||||||
|
#include "hardware/pio.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ------ //
|
||||||
|
// ws2812 //
|
||||||
|
// ------ //
|
||||||
|
|
||||||
|
#define ws2812_wrap_target 0
|
||||||
|
#define ws2812_wrap 3
|
||||||
|
|
||||||
|
#define ws2812_T1 3
|
||||||
|
#define ws2812_T2 4
|
||||||
|
#define ws2812_T3 3
|
||||||
|
|
||||||
|
static const uint16_t ws2812_program_instructions[] = {
|
||||||
|
// .wrap_target
|
||||||
|
0x6221, // 0: out x, 1 side 0 [2]
|
||||||
|
0x1223, // 1: jmp !x, 3 side 1 [2]
|
||||||
|
0x1300, // 2: jmp 0 side 1 [3]
|
||||||
|
0xa342, // 3: nop side 0 [3]
|
||||||
|
// .wrap
|
||||||
|
};
|
||||||
|
|
||||||
|
#if !PICO_NO_HARDWARE
|
||||||
|
static const struct pio_program ws2812_program = {
|
||||||
|
.instructions = ws2812_program_instructions,
|
||||||
|
.length = 4,
|
||||||
|
.origin = -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline pio_sm_config ws2812_program_get_default_config(uint offset) {
|
||||||
|
pio_sm_config c = pio_get_default_sm_config();
|
||||||
|
sm_config_set_wrap(&c, offset + ws2812_wrap_target, offset + ws2812_wrap);
|
||||||
|
sm_config_set_sideset(&c, 1, false, false);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "hardware/clocks.h"
|
||||||
|
static inline void ws2812_program_init(PIO pio, uint sm, uint offset, uint pin,
|
||||||
|
float freq, bool rgbw) {
|
||||||
|
pio_gpio_init(pio, pin);
|
||||||
|
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true);
|
||||||
|
pio_sm_config c = ws2812_program_get_default_config(offset);
|
||||||
|
sm_config_set_sideset_pins(&c, pin);
|
||||||
|
sm_config_set_out_shift(&c, false, true, rgbw ? 32 : 24);
|
||||||
|
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
|
||||||
|
int cycles_per_bit = ws2812_T1 + ws2812_T2 + ws2812_T3;
|
||||||
|
float div = clock_get_hz(clk_sys) / (freq * cycles_per_bit);
|
||||||
|
sm_config_set_clkdiv(&c, div);
|
||||||
|
pio_sm_init(pio, sm, offset, &c);
|
||||||
|
pio_sm_set_enabled(pio, sm, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// --------------- //
|
||||||
|
// ws2812_parallel //
|
||||||
|
// --------------- //
|
||||||
|
|
||||||
|
#define ws2812_parallel_wrap_target 0
|
||||||
|
#define ws2812_parallel_wrap 3
|
||||||
|
|
||||||
|
#define ws2812_parallel_T1 3
|
||||||
|
#define ws2812_parallel_T2 4
|
||||||
|
#define ws2812_parallel_T3 3
|
||||||
|
|
||||||
|
static const uint16_t ws2812_parallel_program_instructions[] = {
|
||||||
|
// .wrap_target
|
||||||
|
0x6020, // 0: out x, 32
|
||||||
|
0xa10b, // 1: mov pins, !null [1]
|
||||||
|
0xa401, // 2: mov pins, x [4]
|
||||||
|
0xa103, // 3: mov pins, null [1]
|
||||||
|
// .wrap
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct pio_program ws2812_parallel_program = {
|
||||||
|
.instructions = ws2812_parallel_program_instructions,
|
||||||
|
.length = 4,
|
||||||
|
.origin = -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
#if !PICO_NO_HARDWARE
|
||||||
|
static inline pio_sm_config
|
||||||
|
ws2812_parallel_program_get_default_config(uint offset) {
|
||||||
|
pio_sm_config c = pio_get_default_sm_config();
|
||||||
|
sm_config_set_wrap(&c, offset + ws2812_parallel_wrap_target,
|
||||||
|
offset + ws2812_parallel_wrap);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "hardware/clocks.h"
|
||||||
|
static inline void ws2812_parallel_program_init(PIO pio, uint sm, uint offset,
|
||||||
|
uint pin_base, uint pin_count,
|
||||||
|
float freq) {
|
||||||
|
for (uint i = pin_base; i < pin_base + pin_count; i++) {
|
||||||
|
pio_gpio_init(pio, i);
|
||||||
|
}
|
||||||
|
pio_sm_set_consecutive_pindirs(pio, sm, pin_base, pin_count, true);
|
||||||
|
pio_sm_config c = ws2812_parallel_program_get_default_config(offset);
|
||||||
|
sm_config_set_out_shift(&c, true, true, 32);
|
||||||
|
sm_config_set_out_pins(&c, pin_base, pin_count);
|
||||||
|
sm_config_set_set_pins(&c, pin_base, pin_count);
|
||||||
|
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
|
||||||
|
int cycles_per_bit =
|
||||||
|
ws2812_parallel_T1 + ws2812_parallel_T2 + ws2812_parallel_T3;
|
||||||
|
float div = clock_get_hz(clk_sys) / (freq * cycles_per_bit);
|
||||||
|
sm_config_set_clkdiv(&c, div);
|
||||||
|
pio_sm_init(pio, sm, offset, &c);
|
||||||
|
pio_sm_set_enabled(pio, sm, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
Loading…
Reference in a new issue