pico-sdk/src/rp2_common/hardware_pio/include/hardware/pio.h
2025-08-07 18:29:46 +01:00

2093 lines
89 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _HARDWARE_PIO_H
#define _HARDWARE_PIO_H
#include "pico.h"
#include "hardware/address_mapped.h"
#include "hardware/structs/pio.h"
#include "hardware/gpio.h"
#include "hardware/regs/dreq.h"
#include "hardware/pio_instructions.h"
// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_HARDWARE_PIO, Enable/disable assertions in the hardware_pio module, type=bool, default=0, group=hardware_pio
#ifndef PARAM_ASSERTIONS_ENABLED_HARDWARE_PIO
#ifdef PARAM_ASSERTIONS_ENABLED_PIO // backwards compatibility with SDK < 2.0.0
#define PARAM_ASSERTIONS_ENABLED_HARDWARE_PIO PARAM_ASSERTIONS_ENABLED_PIO
#else
#define PARAM_ASSERTIONS_ENABLED_HARDWARE_PIO 0
#endif
#endif
// PICO_CONFIG: PICO_PIO_VERSION, PIO hardware version, type=int, default=0 on RP2040 and 1 on RP2350, group=hardware_pio
#ifndef PICO_PIO_VERSION
#if PIO_GPIOBASE_BITS
#define PICO_PIO_VERSION 1
#else
#define PICO_PIO_VERSION 0
#endif
#endif
// PICO_CONFIG: PICO_PIO_CLKDIV_ROUND_NEAREST, True if floating point PIO clock divisors should be rounded to the nearest possible clock divisor rather than rounding down, type=bool, default=PICO_CLKDIV_ROUND_NEAREST, group=hardware_pio
#ifndef PICO_PIO_CLKDIV_ROUND_NEAREST
#define PICO_PIO_CLKDIV_ROUND_NEAREST PICO_CLKDIV_ROUND_NEAREST
#endif
/** \file hardware/pio.h
* \defgroup hardware_pio hardware_pio
*
* \brief Programmable I/O (PIO) API
*
* A programmable input/output block (PIO) is a versatile hardware interface which
* can support a number of different IO standards.
*
* \if rp2040_specific
* There are two PIO blocks in the RP2040.
* \endif
*
* \if rp2350_specific
* There are three PIO blocks in the RP2350
* \endif
*
* Each PIO is programmable in the same sense as a processor: the four state machines independently
* execute short, sequential programs, to manipulate GPIOs and transfer data. Unlike a general
* purpose processor, PIO state machines are highly specialised for IO, with a focus on determinism,
* precise timing, and close integration with fixed-function hardware. Each state machine is equipped
* with:
* * Two 32-bit shift registers either direction, any shift count
* * Two 32-bit scratch registers
* * 4×32 bit bus FIFO in each direction (TX/RX), reconfigurable as 8×32 in a single direction
* * Fractional clock divider (16 integer, 8 fractional bits)
* * Flexible GPIO mapping
* * DMA interface, sustained throughput up to 1 word per clock from system DMA
* * IRQ flag set/clear/status
*
* Full details of the PIO can be found in the appropriate RP-series datasheet. Note that there are
* additional features in the RP2350 PIO implementation that mean care should be taken when writing PIO
* code that needs to run on both the RP2040 and the RP2350.
*
* \anchor pio_sm_pins
* \if rp2040_specific
* On RP2040, pin numbers may always be specified from 0-31
* \endif
*
* \if rp2350_specific
* On RP2350A, pin numbers may always be specified from 0-31.
*
* On RP2350B, there are 48 pins but each PIO instance can only address 32 pins (the PIO
* instance either addresses pins 0-31 or 16-47 based on \ref pio_set_gpio_base). The
* `pio_sm_` methods that directly affect the hardware always take _real_ pin numbers in the full range, however:
*
* * If `PICO_PIO_USE_GPIO_BASE != 1` then the 5th bit of the pin number is ignored. This is done so
* that programs compiled for boards with RP2350A do not incur the extra overhead of dealing with higher pins that don't exist.
* Effectively these functions behave exactly like RP2040 in this case.
* Note that `PICO_PIO_USE_GPIO_BASE` is defaulted to 0 if `PICO_RP2350A` is 1
* * If `PICO_PIO_USE_GPIO_BASE == 1` then the passed pin numbers are adjusted internally by subtracting
* the GPIO base to give a pin number in the range 0-31 from the PIO's perspective
*
* You can set `PARAM_ASSERTIONS_ENABLED_HARDWARE_PIO = 1` to enable parameter checking to debug pin (or other) issues with
* hardware_pio methods.
*
* Note that pin masks follow the same rules as individual pins; bit N of a 32-bit or 64-bit mask always refers to pin N.
* \endif
*/
#ifdef __cplusplus
extern "C" {
#endif
static_assert(PIO_SM0_SHIFTCTRL_FJOIN_RX_LSB == PIO_SM0_SHIFTCTRL_FJOIN_TX_LSB + 1, "");
/** \brief FIFO join states
* \ingroup hardware_pio
*/
enum pio_fifo_join {
PIO_FIFO_JOIN_NONE = 0, ///< TX FIFO length=4 is used for transmit, RX FIFO length=4 is used for receive
PIO_FIFO_JOIN_TX = 1, ///< TX FIFO length=8 is used for transmit, RX FIFO is disabled
PIO_FIFO_JOIN_RX = 2, ///< RX FIFO length=8 is used for receive, TX FIFO is disabled
#if PICO_PIO_VERSION > 0
PIO_FIFO_JOIN_TXGET = 4, ///< TX FIFO length=4 is used for transmit, RX FIFO is disabled; space is used for "get" instructions or processor writes
PIO_FIFO_JOIN_TXPUT = 8, ///< TX FIFO length=4 is used for transmit, RX FIFO is disabled; space is used for "put" instructions or processor reads
PIO_FIFO_JOIN_PUTGET = 12, ///< TX FIFO length=4 is used for transmit, RX FIFO is disabled; space is used for "put"/"get" instructions with no processor access
#endif
};
/** \brief MOV status types
* \ingroup hardware_pio
*/
enum pio_mov_status_type {
STATUS_TX_LESSTHAN = 0,
STATUS_RX_LESSTHAN = 1,
#if PICO_PIO_VERSION > 0
STATUS_IRQ_SET = 2
#endif
};
typedef pio_hw_t *PIO;
/** Identifier for the first (PIO 0) hardware PIO instance (for use in PIO functions).
*
* e.g. pio_gpio_init(pio0, 5)
*
* \ingroup hardware_pio
*/
#define pio0 pio0_hw
/** Identifier for the second (PIO 1) hardware PIO instance (for use in PIO functions).
*
* e.g. pio_gpio_init(pio1, 5)
*
* \ingroup hardware_pio
*/
#define pio1 pio1_hw
#if NUM_PIOS > 2
/** Identifier for the third (PIO 2) hardware PIO instance (for use in PIO functions).
*
* e.g. pio_gpio_init(pio2, 5)
*
* \ingroup hardware_pio
*/
#define pio2 pio2_hw
#endif
#if PICO_PIO_VERSION > 0
#ifndef PICO_PIO_USE_GPIO_BASE
// PICO_CONFIG: PICO_PIO_USE_GPIO_BASE, Enable code for handling more than 32 PIO pins, type=bool, default=true when supported and when the device has more than 32 pins, group=hardware_pio
#define PICO_PIO_USE_GPIO_BASE ((NUM_BANK0_GPIOS) > 32)
#endif
#endif
/**
* \def PIO_NUM(pio)
* \ingroup hardware_pio
* \hideinitializer
* \brief Returns the PIO number for a PIO instance
*
* Note this macro is intended to resolve at compile time, and does no parameter checking
*/
#ifndef PIO_NUM
static_assert(PIO1_BASE - PIO0_BASE == (1u << 20), "hardware layout mismatch");
#if NUM_PIOS > 2
static_assert(PIO2_BASE - PIO0_BASE == (2u << 20), "hardware layout mismatch");
#endif
#define PIO_NUM(pio) (((uintptr_t)(pio) - PIO0_BASE) >> 20)
#endif
/**
* \def PIO_INSTANCE(pio_num)
* \ingroup hardware_pio
* \hideinitializer
* \brief Returns the PIO instance with the given PIO number
*
* Note this macro is intended to resolve at compile time, and does no parameter checking
*/
#ifndef PIO_INSTANCE
static_assert(PIO1_BASE - PIO0_BASE == (1u << 20), "hardware layout mismatch");
#if NUM_PIOS > 2
static_assert(PIO2_BASE - PIO0_BASE == (2u << 20), "hardware layout mismatch");
#endif
#define PIO_INSTANCE(instance) ((pio_hw_t *)(PIO0_BASE + (instance) * (1u << 20)))
#endif
/**
* \def PIO_FUNCSEL_NUM(pio, gpio)
* \ingroup hardware_pio
* \hideinitializer
* \brief Returns \ref gpio_function_t needed to select the PIO function for the given PIO instance on the given GPIO
*
* Note this macro is intended to resolve at compile time, and does no parameter checking
*/
#ifndef PIO_FUNCSEL_NUM
#define PIO_FUNCSEL_NUM(pio, gpio) ((gpio_function_t) (GPIO_FUNC_PIO0 + PIO_NUM(pio)))
#endif
/**
* \def PIO_DREQ_NUM(pio, sm, is_tx)
* \ingroup hardware_pio
* \hideinitializer
* \brief Returns the \ref dreq_num_t used for pacing DMA transfers to or from a given state machine's FIFOs on this PIO instance.
* If is_tx is true, then it is for transfers to the PIO state machine TX FIFO else for transfers from the PIO state machine RX FIFO.
*
* Note this macro is intended to resolve at compile time, and does no parameter checking
*/
#ifndef PIO_DREQ_NUM
static_assert(DREQ_PIO0_TX1 == DREQ_PIO0_TX0 + 1, "");
static_assert(DREQ_PIO0_TX2 == DREQ_PIO0_TX0 + 2, "");
static_assert(DREQ_PIO0_TX3 == DREQ_PIO0_TX0 + 3, "");
static_assert(DREQ_PIO0_RX0 == DREQ_PIO0_TX0 + NUM_PIO_STATE_MACHINES, "");
static_assert(DREQ_PIO1_TX0 == DREQ_PIO0_RX0 + NUM_PIO_STATE_MACHINES, "");
static_assert(DREQ_PIO1_RX0 == DREQ_PIO1_TX0 + NUM_PIO_STATE_MACHINES, "");
#if NUM_PIOS > 2
static_assert(DREQ_PIO2_TX0 == DREQ_PIO1_RX0 + NUM_PIO_STATE_MACHINES, "");
static_assert(DREQ_PIO2_RX0 == DREQ_PIO2_TX0 + NUM_PIO_STATE_MACHINES, "");
#endif
#define PIO_DREQ_NUM(pio, sm, is_tx) (DREQ_PIO0_TX0 + (sm) + (((is_tx) ? 0 : NUM_PIO_STATE_MACHINES) + PIO_NUM(pio) * (DREQ_PIO1_TX0 - DREQ_PIO0_TX0)))
#endif
/**
* \def PIO_IRQ_NUM(pio)
* \ingroup hardware_pio
* \hideinitializer
* \brief Returns the \ref irq_num_t for processor interrupts from the given PIO instance
*
* Note this macro is intended to resolve at compile time, and does no parameter checking
*/
#ifndef PIO_IRQ_NUM
#define PIO_IRQ_NUM(pio, irqn) (PIO0_IRQ_0 + NUM_PIO_IRQS * PIO_NUM(pio) + (irqn))
#endif
/** \brief PIO state machine configuration
* \defgroup sm_config sm_config
* \ingroup hardware_pio
*
* A PIO block needs to be configured, these functions provide helpers to set up configuration
* structures. See \ref pio_sm_set_config
*
* \anchor sm_config_pins
* \if rp2040_specific
* On RP2040, pin numbers may always be specified from 0-31
* \endif
*
* \if rp2350_specific
* On RP2350A, pin numbers may always be specified from 0-31.
*
* On RP2350B, there are 48 pins but each PIO instance can only address 32 pins (the PIO
* instance either addresses pins 0-31 or 16-47 based on \ref pio_set_gpio_base). The
* `sm_config_` state machine configuration always take _real_ pin numbers in the full range, however:
*
* * If `PICO_PIO_USE_GPIO_BASE != 1` then the 5th bit of the pin number is ignored. This is done so
* that programs compiled for boards with RP2350A do not incur the extra overhead of dealing with higher pins that don't exist.
* Effectively these functions behave exactly like RP2040 in this case.
* Note that `PICO_PIO_USE_GPIO_BASE` is defaulted to 0 if `PICO_RP2350A` is 1
* * If `PICO_PIO_USE_GPIO_BASE == 1` then the state machine configuration stores the actual pin numbers in the range 0-47.
* Of course in this scenario, it is possible to make an invalid configuration (one which uses pins in both the ranges
* 0-15 and 32-47).
*
* \ref pio_sm_set_config (or \ref pio_sm_init which calls it) attempts to apply the configuration to a particular PIO's state machine,
* and will return PICO_ERROR_BAD_ALIGNMENT if the configuration cannot be applied due to the above problem,
* or if the PIO's GPIO base (see \ref pio_set_gpio_base) does not allow access to the required pins.
*
* To be clear, \ref pio_sm_set_config does not change the PIO's GPIO base for you; you must configre the PIO's
* GPIO base before calling the method, however you can use \ref pio_claim_free_sm_and_add_program_for_gpio_range
* to find/configure a PIO instance suitable for a partiular GPIO range.
*
* You can set `PARAM_ASSERTIONS_ENABLED_HARDWARE_PIO = 1` to enable parameter checking to debug pin (or other) issues with
* hardware_pio methods.
* \endif
*/
/** \brief PIO Configuration structure
* \ingroup sm_config
*
* This structure is an in-memory representation of the configuration that can be applied to a PIO
* state machine later using pio_sm_set_config() or pio_sm_init().
*/
typedef struct {
uint32_t clkdiv;
uint32_t execctrl;
uint32_t shiftctrl;
uint32_t pinctrl;
#if PICO_PIO_USE_GPIO_BASE
#define PINHI_ALL_PINCTRL_LSBS ((1u << PIO_SM0_PINCTRL_IN_BASE_LSB) | (1u << PIO_SM0_PINCTRL_OUT_BASE_LSB) | \
(1u << PIO_SM0_PINCTRL_SET_BASE_LSB) | (1u << PIO_SM0_PINCTRL_SIDESET_BASE_LSB))
// note we put the out_special pin starting at bit 20
#define PINHI_EXECCTRL_LSB 20
static_assert( (1u << PINHI_EXECCTRL_LSB) > (PINHI_ALL_PINCTRL_LSBS * 0x1f), "");
#define PINHI_ALL_PIN_LSBS ((1u << PINHI_EXECCTRL_LSB) |(1u << PIO_SM0_PINCTRL_IN_BASE_LSB) | (1u << PIO_SM0_PINCTRL_OUT_BASE_LSB) | \
(1u << PIO_SM0_PINCTRL_SET_BASE_LSB) | (1u << PIO_SM0_PINCTRL_SIDESET_BASE_LSB))
// each 5-bit field which would usually be used for the pin_base in pin_ctrl, is used for:
// 0b11111 - corresponding field not specified
// 0b00000 - pin is in range 0-15
// 0b00001 - pin is in range 16-31
// 0b00010 - pin is in range 32-47
uint32_t pinhi;
#endif
} pio_sm_config;
static inline void check_sm_param(__unused uint sm) {
valid_params_if(HARDWARE_PIO, sm < NUM_PIO_STATE_MACHINES);
}
static inline void check_sm_mask(__unused uint mask) {
valid_params_if(HARDWARE_PIO, mask < (1u << NUM_PIO_STATE_MACHINES));
}
static inline void check_pio_param(__unused PIO pio) {
#if NUM_PIOS == 2
valid_params_if(HARDWARE_PIO, pio == pio0 || pio == pio1);
#elif NUM_PIOS == 3
valid_params_if(HARDWARE_PIO, pio == pio0 || pio == pio1 || pio == pio2);
#endif
}
static inline void check_pio_pin_param(__unused uint pin) {
#if !PICO_PIO_USE_GPIO_BASE
invalid_params_if(HARDWARE_PIO, pin >= 32);
#else
// pin base allows us to move up 16 pins at a time
invalid_params_if(HARDWARE_PIO, pin >= ((NUM_BANK0_GPIOS + 15u)&~15u));
#endif
}
/*! \brief Set the base of the 'out' pins in a state machine configuration
* \ingroup sm_config
*
* 'out' pins can overlap with the 'in', 'set' and 'sideset' pins
*
* \param c Pointer to the configuration structure to modify
* \param out_base First pin to set as output. See \ref sm_config_pins "sm_config_ pins" for more detail on pin arguments
*/
static inline void sm_config_set_out_pin_base(pio_sm_config *c, uint out_base) {
check_pio_pin_param(out_base);
c->pinctrl = (c->pinctrl & ~PIO_SM0_PINCTRL_OUT_BASE_BITS) |
((out_base & 31) << PIO_SM0_PINCTRL_OUT_BASE_LSB);
#if PICO_PIO_USE_GPIO_BASE
c->pinhi = (c->pinhi & ~(31u << PIO_SM0_PINCTRL_OUT_BASE_LSB)) |
((out_base >> 4) << PIO_SM0_PINCTRL_OUT_BASE_LSB);
#endif
}
/*! \brief Set the number of 'out' pins in a state machine configuration
* \ingroup sm_config
*
* 'out' pins can overlap with the 'in', 'set' and 'sideset' pins
*
* \param c Pointer to the configuration structure to modify
* \param out_count 0-32 Number of pins to set.
*/
static inline void sm_config_set_out_pin_count(pio_sm_config *c, uint out_count) {
valid_params_if(HARDWARE_PIO, out_count <= 32);
c->pinctrl = (c->pinctrl & ~PIO_SM0_PINCTRL_OUT_COUNT_BITS) |
(out_count << PIO_SM0_PINCTRL_OUT_COUNT_LSB);
}
/*! \brief Set the 'out' pins in a state machine configuration
* \ingroup sm_config
*
* 'out' pins can overlap with the 'in', 'set' and 'sideset' pins
*
* \param c Pointer to the configuration structure to modify
* \param out_base First pin to set as output. See \ref sm_config_pins "sm_config_ pins" for more detail on pin arguments
* \param out_count 0-32 Number of pins to set.
*/
static inline void sm_config_set_out_pins(pio_sm_config *c, uint out_base, uint out_count) {
sm_config_set_out_pin_base(c, out_base);
sm_config_set_out_pin_count(c, out_count);
}
/*! \brief Set the base of the 'set' pins in a state machine configuration
* \ingroup sm_config
*
* 'set' pins can overlap with the 'in', 'out' and 'sideset' pins
*
* \param c Pointer to the configuration structure to modify
* \param set_base First pin to use as 'set'. See \ref sm_config_pins "sm_config_ pins" for more detail on pin arguments
*/
static inline void sm_config_set_set_pin_base(pio_sm_config *c, uint set_base) {
check_pio_pin_param(set_base);
c->pinctrl = (c->pinctrl & ~PIO_SM0_PINCTRL_SET_BASE_BITS) |
((set_base & 31) << PIO_SM0_PINCTRL_SET_BASE_LSB);
#if PICO_PIO_USE_GPIO_BASE
c->pinhi = (c->pinhi & ~(31u << PIO_SM0_PINCTRL_SET_BASE_LSB)) |
((set_base >> 4) << PIO_SM0_PINCTRL_SET_BASE_LSB);
#endif
}
/*! \brief Set the count of 'set' pins in a state machine configuration
* \ingroup sm_config
*
* 'set' pins can overlap with the 'in', 'out' and 'sideset' pins
*
* \param c Pointer to the configuration structure to modify
* \param set_count 0-5 Number of pins to set.
*/
static inline void sm_config_set_set_pin_count(pio_sm_config *c, uint set_count) {
valid_params_if(HARDWARE_PIO, set_count <= 5);
c->pinctrl = (c->pinctrl & ~PIO_SM0_PINCTRL_SET_COUNT_BITS) |
(set_count << PIO_SM0_PINCTRL_SET_COUNT_LSB);
}
/*! \brief Set the 'set' pins in a state machine configuration
* \ingroup sm_config
*
* 'set' pins can overlap with the 'in', 'out' and 'sideset' pins
*
* \param c Pointer to the configuration structure to modify
* \param set_base First pin to use as 'set'. See \ref sm_config_pins "sm_config_ pins" for more detail on pin arguments
* \param set_count 0-5 Number of pins to set.
*/
static inline void sm_config_set_set_pins(pio_sm_config *c, uint set_base, uint set_count) {
sm_config_set_set_pin_base(c, set_base);
sm_config_set_set_pin_count(c, set_count);
}
/*! \brief Set the base of the 'in' pins in a state machine configuration
* \ingroup sm_config
*
* 'in' pins can overlap with the 'out', 'set' and 'sideset' pins
*
* \param c Pointer to the configuration structure to modify
* \param in_base First pin to use as input. See \ref sm_config_pins "sm_config_ pins" for more detail on pin arguments
*/
static inline void sm_config_set_in_pin_base(pio_sm_config *c, uint in_base) {
check_pio_pin_param(in_base);
c->pinctrl = (c->pinctrl & ~PIO_SM0_PINCTRL_IN_BASE_BITS) |
((in_base & 31) << PIO_SM0_PINCTRL_IN_BASE_LSB);
#if PICO_PIO_USE_GPIO_BASE
c->pinhi = (c->pinhi & ~(31u << PIO_SM0_PINCTRL_IN_BASE_LSB)) |
((in_base >> 4) << PIO_SM0_PINCTRL_IN_BASE_LSB);
#endif
}
/*! \brief Set the base for the 'in' pins in a state machine configuration
* \ingroup sm_config
*
* 'in' pins can overlap with the 'out', 'set' and 'sideset' pins
*
* \param c Pointer to the configuration structure to modify
* \param in_base First pin to use as input. See \ref sm_config_pins "sm_config_ pins" for more detail on pin arguments
*/
static inline void sm_config_set_in_pins(pio_sm_config *c, uint in_base) {
sm_config_set_in_pin_base(c, in_base);
}
/*! \brief Set the count of 'in' pins in a state machine configuration
* \ingroup sm_config
*
* When reading pins using the IN pin mapping, this many (low) bits will be read, with the rest taking
* the value zero.
*
* \if rp2040_specific
* RP2040 does not have the ability to mask unused input pins, so the in_count must be 32
* \endif
*
* \param c Pointer to the configuration structure to modify
* \param in_count 1-32 The number of pins to include when reading via the IN pin mapping
*/
static inline void sm_config_set_in_pin_count(pio_sm_config *c, uint in_count) {
#if PICO_PIO_VERSION == 0
// can't be changed from 32 on PIO v0
((void)c);
valid_params_if(HARDWARE_PIO, in_count == 32);
#else
valid_params_if(HARDWARE_PIO, in_count && in_count <= 32);
c->shiftctrl = (c->shiftctrl & ~PIO_SM0_SHIFTCTRL_IN_COUNT_BITS) |
((in_count & 0x1fu) << PIO_SM0_SHIFTCTRL_IN_COUNT_LSB);
#endif
}
/*! \brief Set the base of the 'sideset' pins in a state machine configuration
* \ingroup sm_config
*
* 'sideset' pins can overlap with the 'in', 'out' and 'set' pins
*
* \param c Pointer to the configuration structure to modify
* \param sideset_base First pin to use for 'side set'. See \ref sm_config_pins "sm_config_ pins" for more detail on pin arguments
*/
static inline void sm_config_set_sideset_pin_base(pio_sm_config *c, uint sideset_base) {
check_pio_pin_param(sideset_base);
c->pinctrl = (c->pinctrl & ~PIO_SM0_PINCTRL_SIDESET_BASE_BITS) |
((sideset_base & 31) << PIO_SM0_PINCTRL_SIDESET_BASE_LSB);
#if PICO_PIO_USE_GPIO_BASE
c->pinhi = (c->pinhi & ~(31u << PIO_SM0_PINCTRL_SIDESET_BASE_LSB)) |
((sideset_base >> 4) << PIO_SM0_PINCTRL_SIDESET_BASE_LSB);
#endif
}
/*! \brief Set the 'sideset' pins in a state machine configuration
* \ingroup sm_config
*
* This method is identical to \ref sm_config_set_sideset_pin_base, and is provided
* for backwards compatibility
*
* 'sideset' pins can overlap with the 'in', 'out' and 'set' pins
*
* \param c Pointer to the configuration structure to modify
* \param sideset_base First pin to use for 'side set'. See \ref sm_config_pins "sm_config_ pins" for more detail on pin arguments
*/
static inline void sm_config_set_sideset_pins(pio_sm_config *c, uint sideset_base) {
sm_config_set_sideset_pin_base(c, sideset_base);
}
/*! \brief Set the 'sideset' options in a state machine configuration
* \ingroup sm_config
*
* \param c Pointer to the configuration structure to modify
* \param bit_count Number of bits to steal from delay field in the instruction for use of side set (max 5)
* \param optional True if the topmost side set bit is used as a flag for whether to apply side set on that instruction
* \param pindirs True if the side set affects pin directions rather than values
*/
static inline void sm_config_set_sideset(pio_sm_config *c, uint bit_count, bool optional, bool pindirs) {
valid_params_if(HARDWARE_PIO, bit_count <= 5);
valid_params_if(HARDWARE_PIO, !optional || bit_count >= 1);
c->pinctrl = (c->pinctrl & ~PIO_SM0_PINCTRL_SIDESET_COUNT_BITS) |
(bit_count << PIO_SM0_PINCTRL_SIDESET_COUNT_LSB);
c->execctrl = (c->execctrl & ~(PIO_SM0_EXECCTRL_SIDE_EN_BITS | PIO_SM0_EXECCTRL_SIDE_PINDIR_BITS)) |
(bool_to_bit(optional) << PIO_SM0_EXECCTRL_SIDE_EN_LSB) |
(bool_to_bit(pindirs) << PIO_SM0_EXECCTRL_SIDE_PINDIR_LSB);
}
/*! \brief Set the state machine clock divider (from integer and fractional parts - 16:8) in a state machine configuration
* \ingroup sm_config
*
* The clock divider can slow the state machine's execution to some rate below
* the system clock frequency, by enabling the state machine on some cycles
* but not on others, in a regular pattern. This can be used to generate e.g.
* a given UART baud rate. See the datasheet for further detail.
*
* \param c Pointer to the configuration structure to modify
* \param div_int Integer part of the divisor
* \param div_frac8 Fractional part in 1/256ths
* \sa sm_config_set_clkdiv()
*/
static inline void sm_config_set_clkdiv_int_frac8(pio_sm_config *c, uint32_t div_int, uint8_t div_frac8) {
static_assert(REG_FIELD_WIDTH(PIO_SM0_CLKDIV_INT) == 16, "");
invalid_params_if(HARDWARE_PIO, div_int >> 16);
invalid_params_if(HARDWARE_PIO, div_int == 0 && div_frac8 != 0);
static_assert(REG_FIELD_WIDTH(PIO_SM0_CLKDIV_FRAC) == 8, "");
c->clkdiv =
(((uint)div_frac8) << PIO_SM0_CLKDIV_FRAC_LSB) |
(((uint)div_int) << PIO_SM0_CLKDIV_INT_LSB);
}
// backwards compatibility
static inline void sm_config_set_clkdiv_int_frac(pio_sm_config *c, uint16_t div_int, uint8_t div_frac8) {
sm_config_set_clkdiv_int_frac8(c, div_int, div_frac8);
}
static inline void pio_calculate_clkdiv8_from_float(float div, uint32_t *div_int, uint8_t *div_frac8) {
valid_params_if(HARDWARE_PIO, div >= 1 && div <= 65536);
const int frac_bit_count = REG_FIELD_WIDTH(PIO_SM0_CLKDIV_FRAC);
#if PICO_PIO_CLKDIV_ROUND_NEAREST
div += 0.5f / (1 << frac_bit_count); // round to the nearest 1/256
#endif
*div_int = (uint16_t)div;
// not a strictly necessary check, but if this changes, then this method should
// probably no longer be used in favor of one with a larger fraction
static_assert(REG_FIELD_WIDTH(PIO_SM0_CLKDIV_FRAC) == 8, "");
if (*div_int == 0) {
*div_frac8 = 0;
} else {
*div_frac8 = (uint8_t)((div - (float)*div_int) * (1u << frac_bit_count));
}
}
// backwards compatibility
static inline void pio_calculate_clkdiv_from_float(float div, uint16_t *div_int16, uint8_t *div_frac8) {
uint32_t div_int;
pio_calculate_clkdiv8_from_float(div, &div_int, div_frac8);
*div_int16 = (uint16_t) div_int;
}
/*! \brief Set the state machine clock divider (from a floating point value) in a state machine configuration
* \ingroup sm_config
*
* The clock divider slows the state machine's execution by masking the
* system clock on some cycles, in a repeating pattern, so that the state
* machine does not advance. Effectively this produces a slower clock for the
* state machine to run from, which can be used to generate e.g. a particular
* UART baud rate. See the datasheet for further detail.
*
* \param c Pointer to the configuration structure to modify
* \param div The fractional divisor to be set. 1 for full speed. An integer clock divisor of n
* will cause the state machine to run 1 cycle in every n.
* Note that for small n, the jitter introduced by a fractional divider (e.g. 2.5) may be unacceptable
* although it will depend on the use case.
*/
static inline void sm_config_set_clkdiv(pio_sm_config *c, float div) {
uint32_t div_int;
uint8_t div_frac8;
pio_calculate_clkdiv8_from_float(div, &div_int, &div_frac8);
sm_config_set_clkdiv_int_frac8(c, div_int, div_frac8);
}
/*! \brief Set the wrap addresses in a state machine configuration
* \ingroup sm_config
*
* \param c Pointer to the configuration structure to modify
* \param wrap_target the instruction memory address to wrap to
* \param wrap the instruction memory address after which to set the program counter to wrap_target
* if the instruction does not itself update the program_counter
*/
static inline void sm_config_set_wrap(pio_sm_config *c, uint wrap_target, uint wrap) {
valid_params_if(HARDWARE_PIO, wrap < PIO_INSTRUCTION_COUNT);
valid_params_if(HARDWARE_PIO, wrap_target < PIO_INSTRUCTION_COUNT);
c->execctrl = (c->execctrl & ~(PIO_SM0_EXECCTRL_WRAP_TOP_BITS | PIO_SM0_EXECCTRL_WRAP_BOTTOM_BITS)) |
(wrap_target << PIO_SM0_EXECCTRL_WRAP_BOTTOM_LSB) |
(wrap << PIO_SM0_EXECCTRL_WRAP_TOP_LSB);
}
/*! \brief Set the 'jmp' pin in a state machine configuration
* \ingroup sm_config
*
* \param c Pointer to the configuration structure to modify
* \param pin The raw GPIO pin number to use as the source for a `jmp pin` instruction. See \ref sm_config_pins "sm_config_ pins" for more detail on pin arguments
*/
static inline void sm_config_set_jmp_pin(pio_sm_config *c, uint pin) {
check_pio_pin_param(pin);
c->execctrl = (c->execctrl & ~PIO_SM0_EXECCTRL_JMP_PIN_BITS) |
((pin & 31) << PIO_SM0_EXECCTRL_JMP_PIN_LSB);
#if PICO_PIO_USE_GPIO_BASE
c->pinhi = (c->pinhi & ~(31u << 20)) |
((pin >> 4) << 20);
#endif
}
/*! \brief Setup 'in' shifting parameters in a state machine configuration
* \ingroup sm_config
*
* \param c Pointer to the configuration structure to modify
* \param shift_right true to shift ISR to right, false to shift ISR to left
* \param autopush whether autopush is enabled
* \param push_threshold threshold in bits to shift in before auto/conditional re-pushing of the ISR
*/
static inline void sm_config_set_in_shift(pio_sm_config *c, bool shift_right, bool autopush, uint push_threshold) {
valid_params_if(HARDWARE_PIO, push_threshold <= 32);
c->shiftctrl = (c->shiftctrl &
~(PIO_SM0_SHIFTCTRL_IN_SHIFTDIR_BITS |
PIO_SM0_SHIFTCTRL_AUTOPUSH_BITS |
PIO_SM0_SHIFTCTRL_PUSH_THRESH_BITS)) |
(bool_to_bit(shift_right) << PIO_SM0_SHIFTCTRL_IN_SHIFTDIR_LSB) |
(bool_to_bit(autopush) << PIO_SM0_SHIFTCTRL_AUTOPUSH_LSB) |
((push_threshold & 0x1fu) << PIO_SM0_SHIFTCTRL_PUSH_THRESH_LSB);
}
/*! \brief Setup 'out' shifting parameters in a state machine configuration
* \ingroup sm_config
*
* \param c Pointer to the configuration structure to modify
* \param shift_right true to shift OSR to right, false to shift OSR to left
* \param autopull whether autopull is enabled
* \param pull_threshold threshold in bits to shift out before auto/conditional re-pulling of the OSR
*/
static inline void sm_config_set_out_shift(pio_sm_config *c, bool shift_right, bool autopull, uint pull_threshold) {
valid_params_if(HARDWARE_PIO, pull_threshold <= 32);
c->shiftctrl = (c->shiftctrl &
~(PIO_SM0_SHIFTCTRL_OUT_SHIFTDIR_BITS |
PIO_SM0_SHIFTCTRL_AUTOPULL_BITS |
PIO_SM0_SHIFTCTRL_PULL_THRESH_BITS)) |
(bool_to_bit(shift_right) << PIO_SM0_SHIFTCTRL_OUT_SHIFTDIR_LSB) |
(bool_to_bit(autopull) << PIO_SM0_SHIFTCTRL_AUTOPULL_LSB) |
((pull_threshold & 0x1fu) << PIO_SM0_SHIFTCTRL_PULL_THRESH_LSB);
}
/*! \brief Setup the FIFO joining in a state machine configuration
* \ingroup sm_config
*
* \param c Pointer to the configuration structure to modify
* \param join Specifies the join type. See \ref pio_fifo_join
*/
static inline void sm_config_set_fifo_join(pio_sm_config *c, enum pio_fifo_join join) {
valid_params_if(HARDWARE_PIO, join == PIO_FIFO_JOIN_NONE || join == PIO_FIFO_JOIN_TX || join == PIO_FIFO_JOIN_RX
#if PICO_PIO_VERSION > 0
|| join == PIO_FIFO_JOIN_TXPUT || join == PIO_FIFO_JOIN_TXGET || join == PIO_FIFO_JOIN_PUTGET
#endif
);
#if PICO_PIO_VERSION == 0
c->shiftctrl = (c->shiftctrl & (uint)~(PIO_SM0_SHIFTCTRL_FJOIN_TX_BITS | PIO_SM0_SHIFTCTRL_FJOIN_RX_BITS)) |
(((uint)join) << PIO_SM0_SHIFTCTRL_FJOIN_TX_LSB);
#else
c->shiftctrl = (c->shiftctrl & (uint)~(PIO_SM0_SHIFTCTRL_FJOIN_TX_BITS | PIO_SM0_SHIFTCTRL_FJOIN_RX_BITS |
PIO_SM0_SHIFTCTRL_FJOIN_RX_PUT_BITS | PIO_SM0_SHIFTCTRL_FJOIN_RX_GET_BITS)) |
(((uint)(join & 3)) << PIO_SM0_SHIFTCTRL_FJOIN_TX_LSB) |
(((uint)(join >> 2)) << PIO_SM0_SHIFTCTRL_FJOIN_RX_GET_LSB);
#endif
}
/*! \brief Set special 'out' operations in a state machine configuration
* \ingroup sm_config
*
* \param c Pointer to the configuration structure to modify
* \param sticky to enable 'sticky' output (i.e. re-asserting most recent OUT/SET pin values on subsequent cycles)
* \param has_enable_pin true to enable auxiliary OUT enable pin
* \param enable_bit_index Data bit index for auxiliary OUT enable.
*/
static inline void sm_config_set_out_special(pio_sm_config *c, bool sticky, bool has_enable_pin, uint enable_bit_index) {
c->execctrl = (c->execctrl &
(uint)~(PIO_SM0_EXECCTRL_OUT_STICKY_BITS | PIO_SM0_EXECCTRL_INLINE_OUT_EN_BITS |
PIO_SM0_EXECCTRL_OUT_EN_SEL_BITS)) |
(bool_to_bit(sticky) << PIO_SM0_EXECCTRL_OUT_STICKY_LSB) |
(bool_to_bit(has_enable_pin) << PIO_SM0_EXECCTRL_INLINE_OUT_EN_LSB) |
((enable_bit_index << PIO_SM0_EXECCTRL_OUT_EN_SEL_LSB) & PIO_SM0_EXECCTRL_OUT_EN_SEL_BITS);
}
/*! \brief Set source for 'mov status' in a state machine configuration
* \ingroup sm_config
*
* \param c Pointer to the configuration structure to modify
* \param status_sel the status operation selector. See \ref pio_mov_status_type
* \param status_n parameter for the mov status operation (currently a bit count)
*/
static inline void sm_config_set_mov_status(pio_sm_config *c, enum pio_mov_status_type status_sel, uint status_n) {
valid_params_if(HARDWARE_PIO,
status_sel == STATUS_TX_LESSTHAN || status_sel == STATUS_RX_LESSTHAN
#if PICO_PIO_VERSION > 0
|| status_sel == STATUS_IRQ_SET
#endif
);
c->execctrl = (c->execctrl
& ~(PIO_SM0_EXECCTRL_STATUS_SEL_BITS | PIO_SM0_EXECCTRL_STATUS_N_BITS))
| ((((uint)status_sel) << PIO_SM0_EXECCTRL_STATUS_SEL_LSB) & PIO_SM0_EXECCTRL_STATUS_SEL_BITS)
| ((status_n << PIO_SM0_EXECCTRL_STATUS_N_LSB) & PIO_SM0_EXECCTRL_STATUS_N_BITS);
}
/*! \brief Get the default state machine configuration
* \ingroup sm_config
*
* Setting | Default
* --------|--------
* Out Pins | 32 starting at 0
* Set Pins | 0 starting at 0
* In Pins | 32 starting at 0
* Side Set Pins (base) | 0
* Side Set | disabled
* Wrap | wrap=31, wrap_to=0
* In Shift | shift_direction=right, autopush=false, push_threshold=32
* Out Shift | shift_direction=right, autopull=false, pull_threshold=32
* Jmp Pin | 0
* Out Special | sticky=false, has_enable_pin=false, enable_pin_index=0
* Mov Status | status_sel=STATUS_TX_LESSTHAN, n=0
*
* \return the default state machine configuration which can then be modified.
*/
static inline pio_sm_config pio_get_default_sm_config(void) {
pio_sm_config c = {};
#if PICO_PIO_USE_GPIO_BASE
c.pinhi = -1;
#endif
sm_config_set_clkdiv_int_frac8(&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;
}
/*! \brief Return the base GPIO base for the PIO instance
* \ingroup hardware_pio
*
* \if rp2040_specific
* This method always return 0 in RP2040
* \endif
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \return the current GPIO base for the PIO instance
*/
static inline uint pio_get_gpio_base(PIO pio) {
#if PICO_PIO_VERSION > 0
return pio->gpiobase;
#else
((void)pio);
return 0;
#endif
}
static inline void check_pio_pin_mask(__unused PIO pio, __unused uint sm, __unused uint32_t pinmask) {
// check no pins are set in the mask which are incompatible with the pio
#if PICO_PIO_USE_GPIO_BASE
valid_params_if(HARDWARE_PIO, (pinmask & ~(0xfffffffful << pio_get_gpio_base(pio))) == 0);
#else
valid_params_if(HARDWARE_PIO, (pinmask & ~0xfffffffful) == 0);
#endif
}
static inline void check_pio_pin_mask64(__unused PIO pio, __unused uint sm, __unused uint64_t pinmask) {
// check no pins are set in the mask which are incompatible with the pio
#if PICO_PIO_USE_GPIO_BASE
valid_params_if(HARDWARE_PIO, (pinmask & ~(0xffffffffull << pio_get_gpio_base(pio))) == 0);
#else
valid_params_if(HARDWARE_PIO, (pinmask & ~0xffffffffull) == 0);
#endif
}
/*! \brief Apply a state machine configuration to a state machine
* \ingroup hardware_pio
*
* \if rp2350_specific
* See \ref sm_config_pins "sm_config_ pins" for more detail on why this method might fail on RP2350B
* \endif
* \param pio Handle to PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
* \param config the configuration to apply
* \return PICO_OK (0) on success, negative error code otherwise
*/
static inline int pio_sm_set_config(PIO pio, uint sm, const pio_sm_config *config) {
check_pio_param(pio);
check_sm_param(sm);
pio->sm[sm].clkdiv = config->clkdiv;
pio->sm[sm].shiftctrl = config->shiftctrl;
#if PICO_PIO_USE_GPIO_BASE
uint used = (~config->pinhi >> 4) & PINHI_ALL_PIN_LSBS;
// configs that use pins 0-15
uint gpio_under_16 = (~config->pinhi) & (~config->pinhi >> 1) & used;
// configs that use pins 32-47
uint gpio_over_32 = (config->pinhi >> 1) & used;
uint gpio_base = pio_get_gpio_base(pio);
invalid_params_if_and_return(PIO, gpio_under_16 && gpio_base, PICO_ERROR_BAD_ALIGNMENT);
invalid_params_if_and_return(PIO, gpio_over_32 && !gpio_base, PICO_ERROR_BAD_ALIGNMENT);
// flip the top bit of any used (execctrl/pinctrl) values to turn:
// bit6(32) + 0-15 -> base(16) + 16-31
// bit6(0) + 16-31 -> base(16) + 0-15
static_assert(PINHI_EXECCTRL_LSB == 20, ""); // we use shifts to mask off bits below
pio->sm[sm].execctrl = config->execctrl ^ (gpio_base ? ((used >> 20) << (PIO_SM0_EXECCTRL_JMP_PIN_LSB + 4)) : 0);
pio->sm[sm].pinctrl = config->pinctrl ^ (gpio_base ? ((used << 12) >> 8) : 0);
#else
pio->sm[sm].execctrl = config->execctrl;
pio->sm[sm].pinctrl = config->pinctrl;
#endif
return PICO_OK;
}
/*! \brief Return the instance number of a PIO instance
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \return the PIO instance number (0, 1, ...)
*/
static inline uint pio_get_index(PIO pio) {
check_pio_param(pio);
return PIO_NUM(pio);
}
/*! \brief Return the funcsel number of a PIO instance
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \return the PIO instance number (0, 1, ...)
* \see gpio_function_t
*/
static inline uint pio_get_funcsel(PIO pio) {
check_pio_param(pio);
return PIO_FUNCSEL_NUM(pio, 0); // note GPIO currently unused, so won't bother updating API
}
/*! \brief Convert PIO instance to hardware instance
* \ingroup hardware_pio
*
* \param instance Instance of PIO, 0 or 1
* \return the PIO hardware instance
*/
static inline PIO pio_get_instance(uint instance) {
invalid_params_if(HARDWARE_PIO, instance >= NUM_PIOS);
return PIO_INSTANCE(instance);
}
/*! \brief Setup the function select for a GPIO to use output from the given PIO instance
* \ingroup hardware_pio
*
* PIO appears as an alternate function in the GPIO muxing, just like an SPI
* or UART. This function configures that multiplexing to connect a given PIO
* instance to a GPIO. It also configures the GPIO pad to pass signals in and
* out, by:
*
* * Clearing the pad output disable (OD) bit
* * Setting the pad input enable (IE) bit
* * (Non-RP2040) removing pad isolation
*
* This function achieves this low-level pad setup by calling gpio_set_function()
* internally.
*
* Note that, if your PIO program only needs the *input* from a given GPIO,
* it's not necessary to select the PIO GPIO function, because PIO input
* paths ignore the GPIO muxing. However, you must still configure the GPIO
* pad itself for input.
*
* Conversely, if using PIO for both input and output on a given pin, you must
* select the PIO GPIO function for the given PIO instance, as well as
* configuring the pad for input and output. Calling this function is
* sufficient for both the input-only and input/output case.
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param pin the GPIO pin whose function select to set
*/
static inline void pio_gpio_init(PIO pio, uint pin) {
check_pio_param(pio);
valid_params_if(HARDWARE_PIO, pin < NUM_BANK0_GPIOS);
gpio_set_function(pin, PIO_FUNCSEL_NUM(pio, pin));
}
/*! \brief Return the DREQ to use for pacing transfers to/from a particular state machine FIFO
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
* \param is_tx true for sending data to the state machine, false for receiving data from the state machine
*/
static inline uint pio_get_dreq(PIO pio, uint sm, bool is_tx) {
check_pio_param(pio);
check_sm_param(sm);
return PIO_DREQ_NUM(pio, sm, is_tx);
}
typedef struct pio_program {
const uint16_t *instructions;
uint8_t length;
int8_t origin; // required instruction memory origin or -1
uint8_t pio_version;
#if PICO_PIO_VERSION > 0
uint8_t used_gpio_ranges; // bitmap with one bit per 16 pins
#endif
} pio_program_t;
/*! \brief Set the base GPIO base for the PIO instance
* \ingroup hardware_pio
*
* Since an individual PIO accesses only 32 pins, to be able to access more pins, the PIO
* instance must specify a base GPIO where the instance's "pin 0" maps. For RP2350 the valid
* values are 0 and 16, indicating the PIO instance has access to pins 0-31, or 16-47 respectively.
*
* NOTE: This method simply changes the underlying PIO register, it does not detect or attempt
* to prevent any side effects this change will have on in use state machines on this PIO.
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param gpio_base the GPIO base (either 0 or 16)
* \return PICO_OK (0) on success, error code otherwise
*/
int pio_set_gpio_base(PIO pio, uint gpio_base);
/*! \brief Determine whether the given program can (at the time of the call) be loaded onto the PIO instance
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param program the program definition
* \return true if the program can be loaded;
* false if not, e.g. if there is not suitable space in the instruction memory
*/
bool pio_can_add_program(PIO pio, const pio_program_t *program);
/*! \brief Determine whether the given program can (at the time of the call) be loaded onto the PIO instance starting at a particular location
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param program the program definition
* \param offset the instruction memory offset wanted for the start of the program
* \return true if the program can be loaded at that location;
* false if not, e.g. if there is not space in the instruction memory
*/
bool pio_can_add_program_at_offset(PIO pio, const pio_program_t *program, uint offset);
/*! \brief Attempt to load the program
* \ingroup hardware_pio
*
* See pio_can_add_program() if you need to check whether the program can be loaded
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param program the program definition
* \return the instruction memory offset the program is loaded at, or negative for error (for
* backwards compatibility with prior SDK the error value is -1 i.e. PICO_ERROR_GENERIC)
*/
int pio_add_program(PIO pio, const pio_program_t *program);
/*! \brief Attempt to load the program at the specified instruction memory offset
* \ingroup hardware_pio
*
* See pio_can_add_program_at_offset() if you need to check whether the program can be loaded
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param program the program definition
* \param offset the instruction memory offset wanted for the start of the program
* \return the instruction memory offset the program is loaded at, or negative for error (for
* backwards compatibility with prior SDK the error value is -1 i.e. PICO_ERROR_GENERIC)
*/
int pio_add_program_at_offset(PIO pio, const pio_program_t *program, uint offset);
/*! \brief Remove a program from a PIO instance's instruction memory
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param program the program definition
* \param loaded_offset the loaded offset returned when the program was added
*/
void pio_remove_program(PIO pio, const pio_program_t *program, uint loaded_offset);
/*! \brief Clears all of a PIO instance's instruction memory
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
*/
void pio_clear_instruction_memory(PIO pio);
/*! \brief Resets the state machine to a consistent state, and configures it
* \ingroup hardware_pio
*
* This method:
* - Disables the state machine (if running)
* - Clears the FIFOs
* - Applies the configuration specified by 'config'
* - Resets any internal state e.g. shift counters
* - Jumps to the initial program location given by 'initial_pc'
*
* The state machine is left disabled on return from this call.
*
* \if rp2350_specific
* See \ref sm_config_pins "sm_config_ pins" for more detail on why this method might fail on RP2350B
* \endif
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
* \param initial_pc the initial program memory offset to run from
* \param config the configuration to apply (or NULL to apply defaults)
* \return PICO_OK, or < 0 for an error (see \ref pico_error_codes)
*/
int pio_sm_init(PIO pio, uint sm, uint initial_pc, const pio_sm_config *config);
/*! \brief Enable or disable a PIO state machine
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
* \param enabled true to enable the state machine; false to disable
*/
static inline void pio_sm_set_enabled(PIO pio, uint sm, bool enabled) {
check_pio_param(pio);
check_sm_param(sm);
pio->ctrl = (pio->ctrl & ~(1u << sm)) | (bool_to_bit(enabled) << sm);
}
/*! \brief Enable or disable multiple PIO state machines
* \ingroup hardware_pio
*
* Note that this method just sets the enabled state of the state machine;
* if now enabled they continue exactly from where they left off.
*
* See pio_enable_sm_mask_in_sync() if you wish to enable multiple state machines
* and ensure their clock dividers are in sync.
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param mask bit mask of state machine indexes to modify the enabled state of
* \param enabled true to enable the state machines; false to disable
*/
static inline void pio_set_sm_mask_enabled(PIO pio, uint32_t mask, bool enabled) {
check_pio_param(pio);
check_sm_mask(mask);
pio->ctrl = (pio->ctrl & ~mask) | (enabled ? mask : 0u);
}
#if PICO_PIO_VERSION > 0
/*! \brief Enable or disable multiple PIO state machines
* \ingroup hardware_pio
*
* Note that this method just sets the enabled state of the state machine;
* if now enabled they continue exactly from where they left off.
*
* See pio_enable_sm_mask_in_sync() if you wish to enable multiple state machines
* and ensure their clock dividers are in sync.
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param mask_prev bit mask of state machine indexes to modify the enabled state of, in the next-lower numbered PIO instance
* \param mask bit mask of state machine indexes to modify the enabled state of, in this PIO instance
* \param mask bit mask of state machine indexes to modify the enabled state of, in the next-higher numbered PIO instance
* \param enabled true to enable the state machines; false to disable
*/
static inline void pio_set_sm_multi_mask_enabled(PIO pio, uint32_t mask_prev, uint32_t mask, uint32_t mask_next, bool enabled) {
check_pio_param(pio);
check_sm_mask(mask);
pio->ctrl = (pio->ctrl & ~(mask << PIO_CTRL_SM_ENABLE_LSB)) |
(enabled ? ((mask << PIO_CTRL_SM_ENABLE_LSB) & PIO_CTRL_SM_ENABLE_BITS) : 0) |
(enabled ? PIO_CTRL_NEXTPREV_SM_ENABLE_BITS : PIO_CTRL_NEXTPREV_SM_DISABLE_BITS) |
((mask_prev << PIO_CTRL_PREV_PIO_MASK_LSB) & PIO_CTRL_PREV_PIO_MASK_BITS) |
((mask_next << PIO_CTRL_NEXT_PIO_MASK_LSB) & PIO_CTRL_NEXT_PIO_MASK_BITS);
}
#endif
/*! \brief Restart a state machine with a known state
* \ingroup hardware_pio
*
* This method clears the ISR, shift counters, clock divider counter
* pin write flags, delay counter, latched EXEC instruction, and IRQ wait condition.
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
*/
static inline void pio_sm_restart(PIO pio, uint sm) {
check_pio_param(pio);
check_sm_param(sm);
hw_set_bits(&pio->ctrl, 1u << (PIO_CTRL_SM_RESTART_LSB + sm));
}
/*! \brief Restart multiple state machine with a known state
* \ingroup hardware_pio
*
* This method clears the ISR, shift counters, clock divider counter
* pin write flags, delay counter, latched EXEC instruction, and IRQ wait condition.
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param mask bit mask of state machine indexes to modify the enabled state of
*/
static inline void pio_restart_sm_mask(PIO pio, uint32_t mask) {
check_pio_param(pio);
check_sm_mask(mask);
hw_set_bits(&pio->ctrl, (mask << PIO_CTRL_SM_RESTART_LSB) & PIO_CTRL_SM_RESTART_BITS);
}
/*! \brief Restart a state machine's clock divider from a phase of 0
* \ingroup hardware_pio
*
* Each state machine's clock divider is a free-running piece of hardware,
* that generates a pattern of clock enable pulses for the state machine,
* based *only* on the configured integer/fractional divisor. The pattern of
* running/halted cycles slows the state machine's execution to some
* controlled rate.
*
* This function clears the divider's integer and fractional phase
* accumulators so that it restarts this pattern from the beginning. It is
* called automatically by pio_sm_init() but can also be called at a later
* time, when you enable the state machine, to ensure precisely consistent
* timing each time you load and run a given PIO program.
*
* More commonly this hardware mechanism is used to synchronise the execution
* clocks of multiple state machines -- see pio_clkdiv_restart_sm_mask().
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
*/
static inline void pio_sm_clkdiv_restart(PIO pio, uint sm) {
check_pio_param(pio);
check_sm_param(sm);
hw_set_bits(&pio->ctrl, 1u << (PIO_CTRL_CLKDIV_RESTART_LSB + sm));
}
/*! \brief Restart multiple state machines' clock dividers from a phase of 0.
* \ingroup hardware_pio
*
* Each state machine's clock divider is a free-running piece of hardware,
* that generates a pattern of clock enable pulses for the state machine,
* based *only* on the configured integer/fractional divisor. The pattern of
* running/halted cycles slows the state machine's execution to some
* controlled rate.
*
* This function simultaneously clears the integer and fractional phase
* accumulators of multiple state machines' clock dividers. If these state
* machines all have the same integer and fractional divisors configured,
* their clock dividers will run in precise deterministic lockstep from this
* point.
*
* With their execution clocks synchronised in this way, it is then safe to
* e.g. have multiple state machines performing a 'wait irq' on the same flag,
* and all clear it on the same cycle.
*
* Also note that this function can be called whilst state machines are
* running (e.g. if you have just changed the clock divisors of some state
* machines and wish to resynchronise them), and that disabling a state
* machine does not halt its clock divider: that is, if multiple state
* machines have their clocks synchronised, you can safely disable and
* re-enable one of the state machines without losing synchronisation.
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param mask bit mask of state machine indexes to modify the enabled state of
*/
static inline void pio_clkdiv_restart_sm_mask(PIO pio, uint32_t mask) {
check_pio_param(pio);
check_sm_mask(mask);
hw_set_bits(&pio->ctrl, (mask << PIO_CTRL_CLKDIV_RESTART_LSB) & PIO_CTRL_CLKDIV_RESTART_BITS);
}
#if PICO_PIO_VERSION > 0
/*! \brief Restart multiple state machines' clock dividers on multiple PIOs from a phase of 0.
* \ingroup hardware_pio
*
* Each state machine's clock divider is a free-running piece of hardware,
* that generates a pattern of clock enable pulses for the state machine,
* based *only* on the configured integer/fractional divisor. The pattern of
* running/halted cycles slows the state machine's execution to some
* controlled rate.
*
* This function simultaneously clears the integer and fractional phase
* accumulators of multiple state machines' clock dividers. If these state
* machines all have the same integer and fractional divisors configured,
* their clock dividers will run in precise deterministic lockstep from this
* point.
*
* With their execution clocks synchronised in this way, it is then safe to
* e.g. have multiple state machines performing a 'wait irq' on the same flag,
* and all clear it on the same cycle.
*
* Also note that this function can be called whilst state machines are
* running (e.g. if you have just changed the clock divisors of some state
* machines and wish to resynchronise them), and that disabling a state
* machine does not halt its clock divider: that is, if multiple state
* machines have their clocks synchronised, you can safely disable and
* re-enable one of the state machines without losing synchronisation.
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param mask_prev bit mask of state machine indexes to modify the enabled state of, in the next-lower numbered PIO instance
* \param mask bit mask of state machine indexes to modify the enabled state of, in this PIO instance
* \param mask_next bit mask of state machine indexes to modify the enabled state of, in the next-higher numbered PIO instance
*/
static inline void pio_clkdiv_restart_sm_multi_mask(PIO pio, uint32_t mask_prev, uint32_t mask, uint32_t mask_next) {
check_pio_param(pio);
check_sm_mask(mask);
hw_set_bits(&pio->ctrl, ((mask << PIO_CTRL_CLKDIV_RESTART_LSB) & PIO_CTRL_CLKDIV_RESTART_BITS) |
PIO_CTRL_NEXTPREV_CLKDIV_RESTART_BITS |
((mask_prev << PIO_CTRL_PREV_PIO_MASK_LSB) & PIO_CTRL_PREV_PIO_MASK_BITS) |
((mask_next << PIO_CTRL_NEXT_PIO_MASK_LSB) & PIO_CTRL_NEXT_PIO_MASK_BITS));
}
#endif
/*! \brief Enable multiple PIO state machines synchronizing their clock dividers
* \ingroup hardware_pio
*
* This is equivalent to calling both pio_set_sm_mask_enabled() and
* pio_clkdiv_restart_sm_mask() on the *same* clock cycle. All state machines
* specified by 'mask' are started simultaneously and, assuming they have the
* same clock divisors, their divided clocks will stay precisely synchronised.
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param mask bit mask of state machine indexes to modify the enabled state of
*/
static inline void pio_enable_sm_mask_in_sync(PIO pio, uint32_t mask) {
check_pio_param(pio);
check_sm_mask(mask);
hw_set_bits(&pio->ctrl,
((mask << PIO_CTRL_CLKDIV_RESTART_LSB) & PIO_CTRL_CLKDIV_RESTART_BITS) |
((mask << PIO_CTRL_SM_ENABLE_LSB) & PIO_CTRL_SM_ENABLE_BITS));
}
#if PICO_PIO_VERSION > 0
/*! \brief Enable multiple PIO state machines on multiple PIOs synchronizing their clock dividers
* \ingroup hardware_pio
*
* This is equivalent to calling both pio_set_sm_multi_mask_enabled() and
* pio_clkdiv_restart_sm_multi_mask() on the *same* clock cycle. All state machines
* specified by 'mask' are started simultaneously and, assuming they have the
* same clock divisors, their divided clocks will stay precisely synchronised.
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param mask_prev bit mask of state machine indexes to modify the enabled state of, in the next-lower numbered PIO instance
* \param mask bit mask of state machine indexes to modify the enabled state of, in this PIO instance
* \param mask_next bit mask of state machine indexes to modify the enabled state of, in the next-higher numbered PIO instance
*/
static inline void pio_enable_sm_multi_mask_in_sync(PIO pio, uint32_t mask_prev, uint32_t mask, uint32_t mask_next) {
check_pio_param(pio);
check_sm_mask(mask);
check_pio_param(pio);
check_sm_mask(mask);
hw_set_bits(&pio->ctrl, ((mask << PIO_CTRL_CLKDIV_RESTART_LSB) & PIO_CTRL_CLKDIV_RESTART_BITS) |
((mask << PIO_CTRL_SM_ENABLE_LSB) & PIO_CTRL_SM_ENABLE_BITS) |
PIO_CTRL_NEXTPREV_CLKDIV_RESTART_BITS | PIO_CTRL_NEXTPREV_SM_ENABLE_BITS |
((mask_prev << PIO_CTRL_PREV_PIO_MASK_LSB) & PIO_CTRL_PREV_PIO_MASK_BITS) |
((mask_next << PIO_CTRL_NEXT_PIO_MASK_LSB) & PIO_CTRL_NEXT_PIO_MASK_BITS));
}
#endif
/*! \brief PIO interrupt source numbers for pio related IRQs
* \ingroup hardware_pio
*/
typedef enum pio_interrupt_source {
pis_interrupt0 = PIO_INTR_SM0_LSB, ///< PIO interrupt 0 is raised
pis_interrupt1 = PIO_INTR_SM1_LSB, ///< PIO interrupt 1 is raised
pis_interrupt2 = PIO_INTR_SM2_LSB, ///< PIO interrupt 2 is raised
pis_interrupt3 = PIO_INTR_SM3_LSB, ///< PIO interrupt 3 is raised
#if PICO_PIO_VERSION > 0
pis_interrupt4 = PIO_INTR_SM4_LSB, ///< PIO interrupt 4 is raised
pis_interrupt5 = PIO_INTR_SM5_LSB, ///< PIO interrupt 5 is raised
pis_interrupt6 = PIO_INTR_SM6_LSB, ///< PIO interrupt 6 is raised
pis_interrupt7 = PIO_INTR_SM7_LSB, ///< PIO interrupt 7 is raised
#endif
pis_sm0_tx_fifo_not_full = PIO_INTR_SM0_TXNFULL_LSB, ///< State machine 0 TX FIFO is not full
pis_sm1_tx_fifo_not_full = PIO_INTR_SM1_TXNFULL_LSB, ///< State machine 1 TX FIFO is not full
pis_sm2_tx_fifo_not_full = PIO_INTR_SM2_TXNFULL_LSB, ///< State machine 2 TX FIFO is not full
pis_sm3_tx_fifo_not_full = PIO_INTR_SM3_TXNFULL_LSB, ///< State machine 3 TX FIFO is not full
pis_sm0_rx_fifo_not_empty = PIO_INTR_SM0_RXNEMPTY_LSB, ///< State machine 0 RX FIFO is not empty
pis_sm1_rx_fifo_not_empty = PIO_INTR_SM1_RXNEMPTY_LSB, ///< State machine 1 RX FIFO is not empty
pis_sm2_rx_fifo_not_empty = PIO_INTR_SM2_RXNEMPTY_LSB, ///< State machine 2 RX FIFO is not empty
pis_sm3_rx_fifo_not_empty = PIO_INTR_SM3_RXNEMPTY_LSB, ///< State machine 3 RX FIFO is not empty
} pio_interrupt_source_t;
/*! \brief Enable/Disable a single source on a PIO's IRQ 0
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param source the source number (see \ref pio_interrupt_source)
* \param enabled true to enable IRQ 0 for the source, false to disable.
*/
static inline void pio_set_irq0_source_enabled(PIO pio, pio_interrupt_source_t source, bool enabled) {
check_pio_param(pio);
invalid_params_if(HARDWARE_PIO, source >= 32u || (1u << source) > PIO_INTR_BITS);
if (enabled)
hw_set_bits(&pio->inte0, 1u << source);
else
hw_clear_bits(&pio->inte0, 1u << source);
}
/*! \brief Enable/Disable a single source on a PIO's IRQ 1
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param source the source number (see \ref pio_interrupt_source)
* \param enabled true to enable IRQ 0 for the source, false to disable.
*/
static inline void pio_set_irq1_source_enabled(PIO pio, pio_interrupt_source_t source, bool enabled) {
check_pio_param(pio);
invalid_params_if(HARDWARE_PIO, source >= 32 || (1u << source) > PIO_INTR_BITS);
if (enabled)
hw_set_bits(&pio->inte1, 1u << source);
else
hw_clear_bits(&pio->inte1, 1u << source);
}
/*! \brief Enable/Disable multiple sources on a PIO's IRQ 0
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param source_mask Mask of bits, one for each source number (see \ref pio_interrupt_source) to affect
* \param enabled true to enable all the sources specified in the mask on IRQ 0, false to disable all the sources specified in the mask on IRQ 0
*/
static inline void pio_set_irq0_source_mask_enabled(PIO pio, uint32_t source_mask, bool enabled) {
check_pio_param(pio);
invalid_params_if(HARDWARE_PIO, source_mask > PIO_INTR_BITS);
if (enabled) {
hw_set_bits(&pio->inte0, source_mask);
} else {
hw_clear_bits(&pio->inte0, source_mask);
}
}
/*! \brief Enable/Disable multiple sources on a PIO's IRQ 1
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param source_mask Mask of bits, one for each source number (see \ref pio_interrupt_source) to affect
* \param enabled true to enable all the sources specified in the mask on IRQ 1, false to disable all the source specified in the mask on IRQ 1
*/
static inline void pio_set_irq1_source_mask_enabled(PIO pio, uint32_t source_mask, bool enabled) {
check_pio_param(pio);
invalid_params_if(HARDWARE_PIO, source_mask > PIO_INTR_BITS);
if (enabled) {
hw_set_bits(&pio->inte1, source_mask);
} else {
hw_clear_bits(&pio->inte1, source_mask);
}
}
/*! \brief Enable/Disable a single source on a PIO's specified (0/1) IRQ index
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param irq_index the IRQ index; either 0 or 1
* \param source the source number (see \ref pio_interrupt_source)
* \param enabled true to enable the source on the specified IRQ, false to disable.
*/
static inline void pio_set_irqn_source_enabled(PIO pio, uint irq_index, pio_interrupt_source_t source, bool enabled) {
invalid_params_if(HARDWARE_PIO, irq_index > NUM_PIO_IRQS);
invalid_params_if(HARDWARE_PIO, source >= 32 || (1u << source) > PIO_INTR_BITS);
if (enabled)
hw_set_bits(&pio->irq_ctrl[irq_index].inte, 1u << source);
else
hw_clear_bits(&pio->irq_ctrl[irq_index].inte, 1u << source);
}
/*! \brief Enable/Disable multiple sources on a PIO's specified (0/1) IRQ index
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param irq_index the IRQ index; either 0 or 1
* \param source_mask Mask of bits, one for each source number (see \ref pio_interrupt_source) to affect
* \param enabled true to enable all the sources specified in the mask on the specified IRQ, false to disable all the sources specified in the mask on the specified IRQ
*/
static inline void pio_set_irqn_source_mask_enabled(PIO pio, uint irq_index, uint32_t source_mask, bool enabled) {
invalid_params_if(HARDWARE_PIO, irq_index > NUM_PIO_IRQS);
static_assert(NUM_PIO_IRQS == 2, "");
invalid_params_if(HARDWARE_PIO, source_mask > PIO_INTR_BITS);
if (enabled) {
hw_set_bits(&pio->irq_ctrl[irq_index].inte, source_mask);
} else {
hw_clear_bits(&pio->irq_ctrl[irq_index].inte, source_mask);
}
}
/*! \brief Determine if a particular PIO interrupt is set
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param pio_interrupt_num the PIO interrupt number 0-7
* \return true if corresponding PIO interrupt is currently set
*/
static inline bool pio_interrupt_get(PIO pio, uint pio_interrupt_num) {
check_pio_param(pio);
invalid_params_if(HARDWARE_PIO, pio_interrupt_num >= 8);
return pio->irq & (1u << pio_interrupt_num);
}
/*! \brief Clear a particular PIO interrupt
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param pio_interrupt_num the PIO interrupt number 0-7
*/
static inline void pio_interrupt_clear(PIO pio, uint pio_interrupt_num) {
check_pio_param(pio);
invalid_params_if(HARDWARE_PIO, pio_interrupt_num >= 8);
pio->irq = (1u << pio_interrupt_num);
}
/*! \brief Return the current program counter for a state machine
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
* \return the program counter
*/
static inline uint8_t pio_sm_get_pc(PIO pio, uint sm) {
check_pio_param(pio);
check_sm_param(sm);
return (uint8_t) pio->sm[sm].addr;
}
/*! \brief Immediately execute an instruction on a state machine
* \ingroup hardware_pio
*
* This instruction is executed instead of the next instruction in the normal control flow on the state machine.
* Subsequent calls to this method replace the previous executed
* instruction if it is still running. See pio_sm_is_exec_stalled() to see if an executed instruction
* is still running (i.e. it is stalled on some condition)
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
* \param instr the encoded PIO instruction
*/
inline static void pio_sm_exec(PIO pio, uint sm, uint instr) {
check_pio_param(pio);
check_sm_param(sm);
pio->sm[sm].instr = instr;
}
/*! \brief Determine if an instruction set by pio_sm_exec() is stalled executing
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
* \return true if the executed instruction is still running (stalled)
*/
static inline bool pio_sm_is_exec_stalled(PIO pio, uint sm) {
check_pio_param(pio);
check_sm_param(sm);
return pio->sm[sm].execctrl & PIO_SM0_EXECCTRL_EXEC_STALLED_BITS;
}
/*! \brief Immediately execute an instruction on a state machine and wait for it to complete
* \ingroup hardware_pio
*
* This instruction is executed instead of the next instruction in the normal control flow on the state machine.
* Subsequent calls to this method replace the previous executed
* instruction if it is still running. See pio_sm_is_exec_stalled() to see if an executed instruction
* is still running (i.e. it is stalled on some condition)
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
* \param instr the encoded PIO instruction
*/
static inline void pio_sm_exec_wait_blocking(PIO pio, uint sm, uint instr) {
check_pio_param(pio);
check_sm_param(sm);
pio_sm_exec(pio, sm, instr);
while (pio_sm_is_exec_stalled(pio, sm)) tight_loop_contents();
}
/*! \brief Set the current wrap configuration for a state machine
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
* \param wrap_target the instruction memory address to wrap to
* \param wrap the instruction memory address after which to set the program counter to wrap_target
* if the instruction does not itself update the program_counter
*/
static inline void pio_sm_set_wrap(PIO pio, uint sm, uint wrap_target, uint wrap) {
check_pio_param(pio);
check_sm_param(sm);
valid_params_if(HARDWARE_PIO, wrap < PIO_INSTRUCTION_COUNT);
valid_params_if(HARDWARE_PIO, wrap_target < PIO_INSTRUCTION_COUNT);
pio->sm[sm].execctrl =
(pio->sm[sm].execctrl & ~(PIO_SM0_EXECCTRL_WRAP_TOP_BITS | PIO_SM0_EXECCTRL_WRAP_BOTTOM_BITS)) |
(wrap_target << PIO_SM0_EXECCTRL_WRAP_BOTTOM_LSB) |
(wrap << PIO_SM0_EXECCTRL_WRAP_TOP_LSB);
}
/*! \brief Set the current 'out' pins for a state machine
* \ingroup hardware_pio
*
* 'out' pins can overlap with the 'in', 'set' and 'sideset' pins
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
* \param out_base First pin to set as output. See \ref pio_sm_pins "pio_sm_ pins" for more detail on pin arguments
* \param out_count 0-32 Number of pins to set.
*/
static inline void pio_sm_set_out_pins(PIO pio, uint sm, uint out_base, uint out_count) {
check_pio_param(pio);
check_sm_param(sm);
#if PICO_PIO_USE_GPIO_BASE
invalid_params_if(HARDWARE_PIO, out_base < pio_get_gpio_base(pio));
out_base -= pio_get_gpio_base(pio);
#endif
valid_params_if(HARDWARE_PIO, out_base < 32);
valid_params_if(HARDWARE_PIO, out_count <= 32);
pio->sm[sm].pinctrl = (pio->sm[sm].pinctrl & ~(PIO_SM0_PINCTRL_OUT_BASE_BITS | PIO_SM0_PINCTRL_OUT_COUNT_BITS)) |
(out_base << PIO_SM0_PINCTRL_OUT_BASE_LSB) |
(out_count << PIO_SM0_PINCTRL_OUT_COUNT_LSB);
}
/*! \brief Set the current 'set' pins for a state machine
* \ingroup hardware_pio
*
* 'set' pins can overlap with the 'in', 'out' and 'sideset' pins
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
* \param set_base First pin to set as 'set'. See \ref pio_sm_pins "pio_sm_ pins" for more detail on pin arguments
* \param set_count 0-5 Number of pins to set.
*/
static inline void pio_sm_set_set_pins(PIO pio, uint sm, uint set_base, uint set_count) {
check_pio_param(pio);
check_sm_param(sm);
#if PICO_PIO_USE_GPIO_BASE
invalid_params_if(HARDWARE_PIO, set_base < pio_get_gpio_base(pio));
set_base -= pio_get_gpio_base(pio);
#endif
valid_params_if(HARDWARE_PIO, set_base < 32);
valid_params_if(HARDWARE_PIO, set_count <= 5);
pio->sm[sm].pinctrl = (pio->sm[sm].pinctrl & ~(PIO_SM0_PINCTRL_SET_BASE_BITS | PIO_SM0_PINCTRL_SET_COUNT_BITS)) |
(set_base << PIO_SM0_PINCTRL_SET_BASE_LSB) |
(set_count << PIO_SM0_PINCTRL_SET_COUNT_LSB);
}
/*! \brief Set the current 'in' pins for a state machine
* \ingroup hardware_pio
*
* 'in' pins can overlap with the 'out', 'set' and 'sideset' pins
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
* \param in_base First pin to use as input. See \ref pio_sm_pins "pio_sm_ pins" for more detail on pin arguments
*/
static inline void pio_sm_set_in_pins(PIO pio, uint sm, uint in_base) {
check_pio_param(pio);
check_sm_param(sm);
#if PICO_PIO_USE_GPIO_BASE
invalid_params_if(HARDWARE_PIO, in_base < pio_get_gpio_base(pio));
in_base -= pio_get_gpio_base(pio);
#endif
valid_params_if(HARDWARE_PIO, in_base < 32);
pio->sm[sm].pinctrl = (pio->sm[sm].pinctrl & ~PIO_SM0_PINCTRL_IN_BASE_BITS) |
(in_base << PIO_SM0_PINCTRL_IN_BASE_LSB);
}
/*! \brief Set the current 'sideset' pins for a state machine
* \ingroup hardware_pio
*
* 'sideset' pins can overlap with the 'in', 'out' and 'set' pins
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
* \param sideset_base Base pin for 'side set'. See \ref pio_sm_pins "pio_sm_ pins" for more detail on pin arguments
*/
static inline void pio_sm_set_sideset_pins(PIO pio, uint sm, uint sideset_base) {
check_pio_param(pio);
check_sm_param(sm);
#if PICO_PIO_USE_GPIO_BASE
invalid_params_if(HARDWARE_PIO, sideset_base < pio_get_gpio_base(pio));
sideset_base -= pio_get_gpio_base(pio);
#endif
valid_params_if(HARDWARE_PIO, sideset_base < 32);
pio->sm[sm].pinctrl = (pio->sm[sm].pinctrl & ~PIO_SM0_PINCTRL_SIDESET_BASE_BITS) |
(sideset_base << PIO_SM0_PINCTRL_SIDESET_BASE_LSB);
}
/*! \brief Set the 'jmp' pin for a state machine
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
* \param pin The pin number to use as the source for a `jmp pin` instruction. See \ref pio_sm_pins "pio_sm_ pins" for more detail on pin arguments
*/
static inline void pio_sm_set_jmp_pin(PIO pio, uint sm, uint pin) {
check_pio_param(pio);
check_sm_param(sm);
#if PICO_PIO_USE_GPIO_BASE
invalid_params_if(HARDWARE_PIO, pin < pio_get_gpio_base(pio));
pin -= pio_get_gpio_base(pio);
#endif
valid_params_if(HARDWARE_PIO, pin < 32);
pio->sm[sm].execctrl =
(pio->sm[sm].execctrl & ~PIO_SM0_EXECCTRL_JMP_PIN_BITS)
| (pin << PIO_SM0_EXECCTRL_JMP_PIN_LSB);
}
/*! \brief Write a word of data to a state machine's TX FIFO
* \ingroup hardware_pio
*
* This is a raw FIFO access that does not check for fullness. If the FIFO is
* full, the FIFO contents and state are not affected by the write attempt.
* Hardware sets the TXOVER sticky flag for this FIFO in FDEBUG, to indicate
* that the system attempted to write to a full FIFO.
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
* \param data the 32 bit data value
*
* \sa pio_sm_put_blocking()
*/
static inline void pio_sm_put(PIO pio, uint sm, uint32_t data) {
check_pio_param(pio);
check_sm_param(sm);
pio->txf[sm] = data;
}
/*! \brief Read a word of data from a state machine's RX FIFO
* \ingroup hardware_pio
*
* This is a raw FIFO access that does not check for emptiness. If the FIFO is
* empty, the hardware ignores the attempt to read from the FIFO (the FIFO
* remains in an empty state following the read) and the sticky RXUNDER flag
* for this FIFO is set in FDEBUG to indicate that the system tried to read
* from this FIFO when empty. The data returned by this function is undefined
* when the FIFO is empty.
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
*
* \sa pio_sm_get_blocking()
*/
static inline uint32_t pio_sm_get(PIO pio, uint sm) {
check_pio_param(pio);
check_sm_param(sm);
return pio->rxf[sm];
}
/*! \brief Determine if a state machine's RX FIFO is full
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
* \return true if the RX FIFO is full
*/
static inline bool pio_sm_is_rx_fifo_full(PIO pio, uint sm) {
check_pio_param(pio);
check_sm_param(sm);
return (pio->fstat & (1u << (PIO_FSTAT_RXFULL_LSB + sm))) != 0;
}
/*! \brief Determine if a state machine's RX FIFO is empty
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
* \return true if the RX FIFO is empty
*/
static inline bool pio_sm_is_rx_fifo_empty(PIO pio, uint sm) {
check_pio_param(pio);
check_sm_param(sm);
return (pio->fstat & (1u << (PIO_FSTAT_RXEMPTY_LSB + sm))) != 0;
}
/*! \brief Return the number of elements currently in a state machine's RX FIFO
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
* \return the number of elements in the RX FIFO
*/
static inline uint pio_sm_get_rx_fifo_level(PIO pio, uint sm) {
check_pio_param(pio);
check_sm_param(sm);
uint bitoffs = PIO_FLEVEL_RX0_LSB + sm * (PIO_FLEVEL_RX1_LSB - PIO_FLEVEL_RX0_LSB);
const uint32_t mask = PIO_FLEVEL_RX0_BITS >> PIO_FLEVEL_RX0_LSB;
return (pio->flevel >> bitoffs) & mask;
}
/*! \brief Determine if a state machine's TX FIFO is full
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
* \return true if the TX FIFO is full
*/
static inline bool pio_sm_is_tx_fifo_full(PIO pio, uint sm) {
check_pio_param(pio);
check_sm_param(sm);
return (pio->fstat & (1u << (PIO_FSTAT_TXFULL_LSB + sm))) != 0;
}
/*! \brief Determine if a state machine's TX FIFO is empty
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
* \return true if the TX FIFO is empty
*/
static inline bool pio_sm_is_tx_fifo_empty(PIO pio, uint sm) {
check_pio_param(pio);
check_sm_param(sm);
return (pio->fstat & (1u << (PIO_FSTAT_TXEMPTY_LSB + sm))) != 0;
}
/*! \brief Return the number of elements currently in a state machine's TX FIFO
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
* \return the number of elements in the TX FIFO
*/
static inline uint pio_sm_get_tx_fifo_level(PIO pio, uint sm) {
check_pio_param(pio);
check_sm_param(sm);
unsigned int bitoffs = PIO_FLEVEL_TX0_LSB + sm * (PIO_FLEVEL_TX1_LSB - PIO_FLEVEL_TX0_LSB);
const uint32_t mask = PIO_FLEVEL_TX0_BITS >> PIO_FLEVEL_TX0_LSB;
return (pio->flevel >> bitoffs) & mask;
}
/*! \brief Write a word of data to a state machine's TX FIFO, blocking if the FIFO is full
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
* \param data the 32 bit data value
*/
static inline void pio_sm_put_blocking(PIO pio, uint sm, uint32_t data) {
check_pio_param(pio);
check_sm_param(sm);
while (pio_sm_is_tx_fifo_full(pio, sm)) tight_loop_contents();
pio_sm_put(pio, sm, data);
}
/*! \brief Read a word of data from a state machine's RX FIFO, blocking if the FIFO is empty
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
*/
static inline uint32_t pio_sm_get_blocking(PIO pio, uint sm) {
check_pio_param(pio);
check_sm_param(sm);
while (pio_sm_is_rx_fifo_empty(pio, sm)) tight_loop_contents();
return pio_sm_get(pio, sm);
}
/*! \brief Empty out a state machine's TX FIFO
* \ingroup hardware_pio
*
* This method executes `pull` instructions on the state machine until the TX
* FIFO is empty. This disturbs the contents of the OSR, so see also
* pio_sm_clear_fifos() which clears both FIFOs but leaves the state machine's
* internal state undisturbed.
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
*
* \sa pio_sm_clear_fifos()
*/
void pio_sm_drain_tx_fifo(PIO pio, uint sm);
/*! \brief set the current clock divider for a state machine using a 16:8 fraction
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
* \param div_int the integer part of the clock divider
* \param div_frac8 the fractional part of the clock divider in 1/256s
*/
static inline void pio_sm_set_clkdiv_int_frac8(PIO pio, uint sm, uint32_t div_int, uint8_t div_frac8) {
check_pio_param(pio);
check_sm_param(sm);
static_assert(REG_FIELD_WIDTH(PIO_SM0_CLKDIV_INT) == 16, "");
invalid_params_if(HARDWARE_PIO, div_int >> 16);
invalid_params_if(HARDWARE_PIO, div_int == 0 && div_frac8 != 0);
static_assert(REG_FIELD_WIDTH(PIO_SM0_CLKDIV_FRAC) == 8, "");
pio->sm[sm].clkdiv =
(((uint)div_frac8) << PIO_SM0_CLKDIV_FRAC_LSB) |
(((uint)div_int) << PIO_SM0_CLKDIV_INT_LSB);
}
// backwards compatibility
static inline void pio_sm_set_clkdiv_int_frac(PIO pio, uint sm, uint16_t div_int, uint8_t div_frac8) {
pio_sm_set_clkdiv_int_frac8(pio, sm, div_int, div_frac8);
}
/*! \brief set the current clock divider for a state machine
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
* \param div the floating point clock divider
*/
static inline void pio_sm_set_clkdiv(PIO pio, uint sm, float div) {
check_pio_param(pio);
check_sm_param(sm);
uint32_t div_int;
uint8_t div_frac8;
pio_calculate_clkdiv8_from_float(div, &div_int, &div_frac8);
pio_sm_set_clkdiv_int_frac8(pio, sm, div_int, div_frac8);
}
/*! \brief Clear a state machine's TX and RX FIFOs
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
*/
static inline void pio_sm_clear_fifos(PIO pio, uint sm) {
// changing the FIFO join state clears the fifo
check_pio_param(pio);
check_sm_param(sm);
hw_xor_bits(&pio->sm[sm].shiftctrl, PIO_SM0_SHIFTCTRL_FJOIN_RX_BITS);
hw_xor_bits(&pio->sm[sm].shiftctrl, PIO_SM0_SHIFTCTRL_FJOIN_RX_BITS);
}
/*! \brief Use a state machine to set a value on all pins for the PIO instance
* \ingroup hardware_pio
*
* This method repeatedly reconfigures the target state machine's pin configuration and executes 'set' instructions to set values on all 32 pins,
* before restoring the state machine's pin configuration to what it was.
*
* This method is provided as a convenience to set initial pin states, and should not be used against a state machine that is enabled.
* Note: This method only works for pins < 32. To use with pins >= 32 call pio_sm_set_pins64
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3) to use
* \param pin_values the pin values to set. See \ref pio_sm_pins "pio_sm_ pins" for more detail on pin arguments
*/
void pio_sm_set_pins(PIO pio, uint sm, uint32_t pin_values);
/*! \brief Use a state machine to set a value on all pins for the PIO instance
* \ingroup hardware_pio
*
* This method repeatedly reconfigures the target state machine's pin configuration and executes 'set' instructions to set values on all 32 pins,
* before restoring the state machine's pin configuration to what it was.
*
* This method is provided as a convenience to set initial pin states, and should not be used against a state machine that is enabled.
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3) to use
* \param pin_values the pin values to set. See \ref pio_sm_pins "pio_sm_ pins" for more detail on pin arguments
*/
void pio_sm_set_pins64(PIO pio, uint sm, uint64_t pin_values);
/*! \brief Use a state machine to set a value on multiple pins for the PIO instance
* \ingroup hardware_pio
*
* This method repeatedly reconfigures the target state machine's pin configuration and executes 'set' instructions to set values on up to 32 pins,
* before restoring the state machine's pin configuration to what it was.
*
* This method is provided as a convenience to set initial pin states, and should not be used against a state machine that is enabled.
* Note: This method only works for pins < 32. To use with pins >= 32 call pio_sm_set_pins_with_mask64
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3) to use
* \param pin_values the pin values to set (if the corresponding bit in pin_mask is set)
* \param pin_mask a bit for each pin to indicate whether the corresponding pin_value for that pin should be applied. See \ref pio_sm_pins "pio_sm_ pins" for more detail on pin arguments
*/
void pio_sm_set_pins_with_mask(PIO pio, uint sm, uint32_t pin_values, uint32_t pin_mask);
/*! \brief Use a state machine to set a value on multiple pins for the PIO instance
* \ingroup hardware_pio
*
* This method repeatedly reconfigures the target state machine's pin configuration and executes 'set' instructions to set values on up to 32 pins,
* before restoring the state machine's pin configuration to what it was.
*
* This method is provided as a convenience to set initial pin states, and should not be used against a state machine that is enabled.
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3) to use
* \param pin_values the pin values to set (if the corresponding bit in pin_mask is set)
* \param pin_mask a bit for each pin to indicate whether the corresponding pin_value for that pin should be applied. See \ref pio_sm_pins "pio_sm_ pins" for more detail on pin arguments
*/
void pio_sm_set_pins_with_mask64(PIO pio, uint sm, uint64_t pin_values, uint64_t pin_mask);
/*! \brief Use a state machine to set the pin directions for multiple pins for the PIO instance
* \ingroup hardware_pio
*
* This method repeatedly reconfigures the target state machine's pin configuration and executes 'set' instructions to set pin directions on up to 32 pins,
* before restoring the state machine's pin configuration to what it was.
*
* This method is provided as a convenience to set initial pin directions, and should not be used against a state machine that is enabled.
* Note: This method only works for pins < 32. To use with pins >= 32 call pio_sm_set_pindirs_with_mask64
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3) to use
* \param pin_dirs the pin directions to set - 1 = out, 0 = in (if the corresponding bit in pin_mask is set)
* \param pin_mask a bit for each pin to indicate whether the corresponding pin_value for that pin should be applied.
*/
void pio_sm_set_pindirs_with_mask(PIO pio, uint sm, uint32_t pin_dirs, uint32_t pin_mask);
/*! \brief Use a state machine to set the pin directions for multiple pins for the PIO instance
* \ingroup hardware_pio
*
* This method repeatedly reconfigures the target state machine's pin configuration and executes 'set' instructions to set pin directions on up to 32 pins,
* before restoring the state machine's pin configuration to what it was.
*
* This method is provided as a convenience to set initial pin directions, and should not be used against a state machine that is enabled.
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3) to use
* \param pin_dirs the pin directions to set - 1 = out, 0 = in (if the corresponding bit in pin_mask is set)
* \param pin_mask a bit for each pin to indicate whether the corresponding pin_value for that pin should be applied.
*/
void pio_sm_set_pindirs_with_mask64(PIO pio, uint sm, uint64_t pin_dirs, uint64_t pin_mask);
/*! \brief Use a state machine to set the same pin direction for multiple consecutive pins for the PIO instance
* \ingroup hardware_pio
*
* This method repeatedly reconfigures the target state machine's pin configuration and executes 'set' instructions to set the pin direction on consecutive pins,
* before restoring the state machine's pin configuration to what it was.
*
* This method is provided as a convenience to set initial pin directions, and should not be used against a state machine that is enabled.
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3) to use
* \param pins_base the first pin to set a direction for. See \ref pio_sm_pins "pio_sm_ pins" for more detail on pin arguments
* \param pin_count the count of consecutive pins to set the direction for
* \param is_out the direction to set; true = out, false = in
* \return PICO_OK (0) on success, error code otherwise
*/
int pio_sm_set_consecutive_pindirs(PIO pio, uint sm, uint pins_base, uint pin_count, bool is_out);
/*! \brief Mark a state machine as used
* \ingroup hardware_pio
*
* Method for cooperative claiming of hardware. Will cause a panic if the state machine
* is already claimed. Use of this method by libraries detects accidental
* configurations that would fail in unpredictable ways.
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
*/
void pio_sm_claim(PIO pio, uint sm);
/*! \brief Mark multiple state machines as used
* \ingroup hardware_pio
*
* Method for cooperative claiming of hardware. Will cause a panic if any of the state machines
* are already claimed. Use of this method by libraries detects accidental
* configurations that would fail in unpredictable ways.
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm_mask Mask of state machine indexes
*/
void pio_claim_sm_mask(PIO pio, uint sm_mask);
/*! \brief Mark a state machine as no longer used
* \ingroup hardware_pio
*
* Method for cooperative claiming of hardware.
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
*/
void pio_sm_unclaim(PIO pio, uint sm);
/*! \brief Claim a free state machine on a PIO instance
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param required if true the function will panic if none are available
* \return the state machine index or negative if required was false, and none were free (for
* backwards compatibility with prior SDK the error value is -1 i.e. PICO_ERROR_GENERIC)
*/
int pio_claim_unused_sm(PIO pio, bool required);
/*! \brief Determine if a PIO state machine is claimed
* \ingroup hardware_pio
*
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1
* \param sm State machine index (0..3)
* \return true if claimed, false otherwise
* \see pio_sm_claim
* \see pio_claim_sm_mask
*/
bool pio_sm_is_claimed(PIO pio, uint sm);
/*! \brief Finds a PIO and statemachine and adds a program into PIO memory
* \ingroup hardware_pio
*
* \param program PIO program to add
* \param pio Returns the PIO hardware instance or NULL if no PIO is available
* \param sm Returns the index of the PIO state machine that was claimed
* \param offset Returns the instruction memory offset of the start of the program
* \return true on success, false otherwise
* \see pio_remove_program_and_unclaim_sm
*/
bool pio_claim_free_sm_and_add_program(const pio_program_t *program, PIO *pio, uint *sm, uint *offset);
/*! \brief Finds a PIO and statemachine and adds a program into PIO memory
* \ingroup hardware_pio
*
* This variation of \ref pio_claim_free_sm_and_add_program is useful on RP2350 QFN80 where the "GPIO Base"
* must be set per PIO instance to either address the 32 GPIOs (0->31) or the 32 GPIOS (16-47). No single
* PIO instance can interact with both pins 0->15 or 32->47 at the same time.
*
* This method takes additional information about the GPIO pins needed (via gpio_base and gpio_count),
* and optionally will set the GPIO base (see \ref pio_set_gpio_base) of an unused PIO instance if necessary
*
* \param program PIO program to add
* \param pio Returns the PIO hardware instance or NULL if no PIO is available
* \param sm Returns the index of the PIO state machine that was claimed
* \param offset Returns the instruction memory offset of the start of the program
* \param gpio_base the lowest GPIO number required (0-47 on RP2350B, 0-31 otherwise)
* \param gpio_count the count of GPIOs required
* \param set_gpio_base if there is no free SM on a PIO instance with the right GPIO base, and there IS an unused PIO
* instance, then that PIO will be reconfigured so that this method can succeed
*
* \return true on success, false otherwise
* \see pio_remove_program_and_unclaim_sm
*/
bool pio_claim_free_sm_and_add_program_for_gpio_range(const pio_program_t *program, PIO *pio, uint *sm, uint *offset, uint gpio_base, uint gpio_count, bool set_gpio_base);
/*! \brief Removes a program from PIO memory and unclaims the state machine
* \ingroup hardware_pio
*
* \param program PIO program to remove from memory
* \param pio PIO hardware instance being used
* \param sm PIO state machine that was claimed
* \param offset offset of the program in PIO memory
* \see pio_claim_free_sm_and_add_program
*/
void pio_remove_program_and_unclaim_sm(const pio_program_t *program, PIO pio, uint sm, uint offset);
/*! \brief Return an IRQ for a PIO hardware instance
* \ingroup hardware_pio
*
* \param pio PIO hardware instance
* \param irqn 0 for PIOx_IRQ_0 or 1 for PIOx_IRQ_1 etc where x is the PIO number
* \return The IRQ number to use for the PIO
*/
static inline int pio_get_irq_num(PIO pio, uint irqn) {
check_pio_param(pio);
valid_params_if(HARDWARE_PIO, irqn < NUM_PIO_IRQS);
return PIO_IRQ_NUM(pio, irqn);
}
/*! \brief Return the interrupt source for a state machines TX FIFO not full interrupt
* \ingroup hardware_pio
*
* \param sm State machine index (0..3)
* \return The interrupt source number for use in \ref pio_set_irqn_source_enabled or similar functions
*/
static inline pio_interrupt_source_t pio_get_tx_fifo_not_full_interrupt_source(uint sm) {
check_sm_param(sm);
return ((pio_interrupt_source_t)(pis_sm0_tx_fifo_not_full + sm));
}
/*! \brief Return the interrupt source for a state machines RX FIFO not empty interrupt
* \ingroup hardware_pio
*
* \param sm State machine index (0..3)
* \return The interrupt source number for use in \ref pio_set_irqn_source_enabled or similar functions
*/
static inline pio_interrupt_source_t pio_get_rx_fifo_not_empty_interrupt_source(uint sm) {
check_sm_param(sm);
return ((pio_interrupt_source_t)(pis_sm0_rx_fifo_not_empty + sm));
}
#ifdef __cplusplus
}
#endif
#endif // _PIO_H_