From 39a7f97116d90535e3eeba1aa6d0c68a10717564 Mon Sep 17 00:00:00 2001 From: Graham Sanderson Date: Fri, 22 Nov 2024 13:13:15 -0600 Subject: [PATCH] Cleanup/clarification of PIO behavior with >32 pins (#2085) --- .../hardware_pio/include/hardware/pio.h | 139 +++++++++++++----- src/rp2_common/hardware_pio/pio.c | 87 +++++++---- 2 files changed, 167 insertions(+), 59 deletions(-) diff --git a/src/rp2_common/hardware_pio/include/hardware/pio.h b/src/rp2_common/hardware_pio/include/hardware/pio.h index 124318426..7ca20d64c 100644 --- a/src/rp2_common/hardware_pio/include/hardware/pio.h +++ b/src/rp2_common/hardware_pio/include/hardware/pio.h @@ -69,6 +69,31 @@ * 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 @@ -212,6 +237,37 @@ static_assert(DREQ_PIO1_RX0 == DREQ_PIO1_TX0 + NUM_PIO_STATE_MACHINES, ""); * 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 @@ -228,9 +284,10 @@ typedef struct { #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)) -static_assert( 0 == (0xff000000u & (PINHI_ALL_PINCTRL_LSBS * 0x1f)), ""); -// note we put the jmp_ctrl pin starting at bit 24 -#define PINHI_ALL_PIN_LSBS ((1u << 24) | (1u << PIO_SM0_PINCTRL_IN_BASE_LSB) | (1u << PIO_SM0_PINCTRL_OUT_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 @@ -272,7 +329,7 @@ static inline void check_pio_pin_param(__unused uint pin) { * 'out' pins can overlap with the 'in', 'set' and 'sideset' pins * * \param c Pointer to the configuration structure to modify - * \param out_base 0-31 First pin to set as output + * \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); @@ -304,7 +361,7 @@ static inline void sm_config_set_out_pin_count(pio_sm_config *c, uint out_count) * 'out' pins can overlap with the 'in', 'set' and 'sideset' pins * * \param c Pointer to the configuration structure to modify - * \param out_base 0-31 First pin to set as output + * \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) { @@ -318,7 +375,7 @@ static inline void sm_config_set_out_pins(pio_sm_config *c, uint out_base, uint * 'set' pins can overlap with the 'in', 'out' and 'sideset' pins * * \param c Pointer to the configuration structure to modify - * \param set_base 0-31 First pin to set as + * \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); @@ -350,7 +407,7 @@ static inline void sm_config_set_set_pin_count(pio_sm_config *c, uint set_count) * 'set' pins can overlap with the 'in', 'out' and 'sideset' pins * * \param c Pointer to the configuration structure to modify - * \param set_base 0-31 First pin to set as + * \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) { @@ -364,7 +421,7 @@ static inline void sm_config_set_set_pins(pio_sm_config *c, uint set_base, uint * 'in' pins can overlap with the 'out', 'set' and 'sideset' pins * * \param c Pointer to the configuration structure to modify - * \param in_base 0-31 First pin to use as input + * \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); @@ -382,7 +439,7 @@ static inline void sm_config_set_in_pin_base(pio_sm_config *c, uint in_base) { * 'in' pins can overlap with the 'out', 'set' and 'sideset' pins * * \param c Pointer to the configuration structure to modify - * \param in_base 0-31 First pin to use as input + * \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); @@ -419,7 +476,7 @@ static inline void sm_config_set_in_pin_count(pio_sm_config *c, uint in_count) { * 'sideset' pins can overlap with the 'in', 'out' and 'set' pins * * \param c Pointer to the configuration structure to modify - * \param sideset_base 0-31 base pin for 'side set' + * \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); @@ -440,7 +497,7 @@ static inline void sm_config_set_sideset_pin_base(pio_sm_config *c, uint sideset * 'sideset' pins can overlap with the 'in', 'out' and 'set' pins * * \param c Pointer to the configuration structure to modify - * \param sideset_base 0-31 base pin for 'side set' + * \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); @@ -558,15 +615,15 @@ static inline void sm_config_set_wrap(pio_sm_config *c, uint wrap_target, uint w * \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 + * \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 << 24)) | - ((pin >> 4) << 24); + c->pinhi = (c->pinhi & ~(31u << 20)) | + ((pin >> 4) << 20); #endif } @@ -637,15 +694,15 @@ static inline void sm_config_set_fifo_join(pio_sm_config *c, enum pio_fifo_join * \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_pin_index pin 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_pin_index) { + * \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_pin_index << PIO_SM0_EXECCTRL_OUT_EN_SEL_LSB) & PIO_SM0_EXECCTRL_OUT_EN_SEL_BITS); + ((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 @@ -718,7 +775,7 @@ static inline uint pio_get_gpio_base(PIO pio) { #endif } -static inline void check_pio_pin_mask64(__unused PIO pio, __unused uint64_t pinmask) { +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); @@ -730,6 +787,9 @@ static inline void check_pio_pin_mask64(__unused PIO pio, __unused uint64_t pinm /*! \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 @@ -739,7 +799,6 @@ static inline int pio_sm_set_config(PIO pio, uint sm, const pio_sm_config *confi check_pio_param(pio); check_sm_param(sm); pio->sm[sm].clkdiv = config->clkdiv; - pio->sm[sm].execctrl = config->execctrl; pio->sm[sm].shiftctrl = config->shiftctrl; #if PICO_PIO_USE_GPIO_BASE uint used = (~config->pinhi >> 4) & PINHI_ALL_PIN_LSBS; @@ -750,11 +809,14 @@ static inline int pio_sm_set_config(PIO pio, uint sm, const pio_sm_config *confi 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 (pinctrl) values to turn: + // 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; @@ -842,6 +904,9 @@ typedef struct pio_program { * 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 @@ -853,7 +918,8 @@ int pio_set_gpio_base(PIO pio, uint gpio_base); * * \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 there is not suitable space in the instruction memory + * \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); @@ -863,7 +929,8 @@ bool pio_can_add_program(PIO pio, const pio_program_t *program); * \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 there is not space in the instruction memory + * \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); @@ -920,6 +987,10 @@ void pio_clear_instruction_memory(PIO pio); * * 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 @@ -1409,7 +1480,7 @@ static inline void pio_sm_set_wrap(PIO pio, uint sm, uint wrap_target, uint wrap * * \param pio The PIO instance; e.g. \ref pio0 or \ref pio1 * \param sm State machine index (0..3) - * \param out_base 0-31 First pin to set as output + * \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) { @@ -1433,7 +1504,7 @@ static inline void pio_sm_set_out_pins(PIO pio, uint sm, uint out_base, uint out * * \param pio The PIO instance; e.g. \ref pio0 or \ref pio1 * \param sm State machine index (0..3) - * \param set_base 0-31 First pin to set as + * \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) { @@ -1456,7 +1527,7 @@ static inline void pio_sm_set_set_pins(PIO pio, uint sm, uint set_base, uint set * * \param pio The PIO instance; e.g. \ref pio0 or \ref pio1 * \param sm State machine index (0..3) - * \param in_base 0-31 First pin to use as input + * \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); @@ -1476,7 +1547,7 @@ static inline void pio_sm_set_in_pins(PIO pio, uint sm, uint in_base) { * * \param pio The PIO instance; e.g. \ref pio0 or \ref pio1 * \param sm State machine index (0..3) - * \param sideset_base 0-31 base pin for 'side set' + * \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); @@ -1494,7 +1565,7 @@ static inline void pio_sm_set_sideset_pins(PIO pio, uint sm, uint sideset_base) * * \param pio The PIO instance; e.g. \ref pio0 or \ref pio1 * \param sm State machine index (0..3) - * \param pin The raw GPIO pin number to use as the source for a `jmp pin` instruction + * \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) { @@ -1740,7 +1811,7 @@ static inline void pio_sm_clear_fifos(PIO pio, uint sm) { * * \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 + * \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); @@ -1754,7 +1825,7 @@ void pio_sm_set_pins(PIO pio, uint sm, uint32_t pin_values); * * \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 + * \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); @@ -1770,7 +1841,7 @@ void pio_sm_set_pins64(PIO pio, uint sm, uint64_t pin_values); * \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. + * \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); @@ -1785,7 +1856,7 @@ void pio_sm_set_pins_with_mask(PIO pio, uint sm, uint32_t pin_values, uint32_t p * \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. + * \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); @@ -1830,7 +1901,7 @@ void pio_sm_set_pindirs_with_mask64(PIO pio, uint sm, uint64_t pin_dirs, uint64_ * * \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 + * \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 @@ -1918,7 +1989,7 @@ bool pio_claim_free_sm_and_add_program(const pio_program_t *program, PIO *pio, u * \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 + * \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 diff --git a/src/rp2_common/hardware_pio/pio.c b/src/rp2_common/hardware_pio/pio.c index 8a1a892e7..e0fe2e76b 100644 --- a/src/rp2_common/hardware_pio/pio.c +++ b/src/rp2_common/hardware_pio/pio.c @@ -205,22 +205,22 @@ void pio_clear_instruction_memory(PIO pio) { hw_claim_unlock(save); } -void pio_sm_set_pins(PIO pio, uint sm, uint32_t pins) { - pio_sm_set_pins64(pio, sm, pins); -} +#if !PICO_PIO_USE_GPIO_BASE +// the 32 pin APIs are the same as the internal method, so collapse them +#define pio_sm_set_pins_internal pio_sm_set_pins +#define pio_sm_set_pins_with_mask_internal pio_sm_set_pins_with_mask +#define pio_sm_set_pindirs_with_mask_internal pio_sm_set_pindirs_with_mask +#endif // Set the value of all PIO pins. This is done by forcibly executing // instructions on a "victim" state machine, sm. Ideally you should choose one // which is not currently running a program. This is intended for one-time // setup of initial pin states. -void pio_sm_set_pins64(PIO pio, uint sm, uint64_t pins) { +// +// note pin mask bit 0 is relative to current GPIO_BASE +void pio_sm_set_pins_internal(PIO pio, uint sm, uint32_t pins) { check_pio_param(pio); check_sm_param(sm); - check_pio_pin_mask64(pio, pins); - -#if PICO_PIO_USE_GPIO_BASE - pins >>= pio_get_gpio_base(pio); -#endif uint32_t pinctrl_saved = pio->sm[sm].pinctrl; uint32_t execctrl_saved = pio->sm[sm].execctrl; hw_clear_bits(&pio->sm[sm].execctrl, 1u << PIO_SM0_EXECCTRL_OUT_STICKY_LSB); @@ -240,18 +240,27 @@ void pio_sm_set_pins64(PIO pio, uint sm, uint64_t pins) { pio->sm[sm].execctrl = execctrl_saved; } -void pio_sm_set_pins_with_mask(PIO pio, uint sm, uint32_t pinvals, uint32_t pin_mask) { - pio_sm_set_pins_with_mask64(pio, sm, pinvals, pin_mask); +#ifndef pio_sm_set_pins_internal +void pio_sm_set_pins(PIO pio, uint sm, uint32_t pins) { +#if PICO_PIO_USE_GPIO_BASE + pins >>= pio_get_gpio_base(pio); +#endif + pio_sm_set_pins_internal(pio, sm, pins); +} +#endif + +void pio_sm_set_pins64(PIO pio, uint sm, uint64_t pins) { + check_pio_pin_mask64(pio, sm, pins); +#if PICO_PIO_USE_GPIO_BASE + pins >>= pio_get_gpio_base(pio); +#endif + pio_sm_set_pins_internal(pio, sm, (uint32_t)pins); } -void pio_sm_set_pins_with_mask64(PIO pio, uint sm, uint64_t pinvals, uint64_t pin_mask) { +// note pin values/mask bit 0 is relative to current GPIO_BASE +void pio_sm_set_pins_with_mask_internal(PIO pio, uint sm, uint32_t pin_values, uint32_t pin_mask) { check_pio_param(pio); check_sm_param(sm); - check_pio_pin_mask64(pio, pin_mask); -#if PICO_PIO_USE_GPIO_BASE - pinvals >>= pio_get_gpio_base(pio); - pin_mask >>= pio_get_gpio_base(pio); -#endif uint32_t pinctrl_saved = pio->sm[sm].pinctrl; uint32_t execctrl_saved = pio->sm[sm].execctrl; hw_clear_bits(&pio->sm[sm].execctrl, 1u << PIO_SM0_EXECCTRL_OUT_STICKY_LSB); @@ -260,25 +269,35 @@ void pio_sm_set_pins_with_mask64(PIO pio, uint sm, uint64_t pinvals, uint64_t pi pio->sm[sm].pinctrl = (1u << PIO_SM0_PINCTRL_SET_COUNT_LSB) | (base << PIO_SM0_PINCTRL_SET_BASE_LSB); - pio_sm_exec(pio, sm, pio_encode_set(pio_pins, (pinvals >> base) & 0x1u)); + pio_sm_exec(pio, sm, pio_encode_set(pio_pins, (pin_values >> base) & 0x1u)); pin_mask &= pin_mask - 1; } pio->sm[sm].pinctrl = pinctrl_saved; pio->sm[sm].execctrl = execctrl_saved; } -void pio_sm_set_pindirs_with_mask(PIO pio, uint sm, uint32_t pindirs, uint32_t pin_mask) { - pio_sm_set_pindirs_with_mask64(pio, sm, pindirs, pin_mask); +#ifndef pio_sm_set_pins_with_mask_internal +void pio_sm_set_pins_with_mask(PIO pio, uint sm, uint32_t pin_values, uint32_t pin_mask) { +#if PICO_PIO_USE_GPIO_BASE + pin_values >>= pio_get_gpio_base(pio); + pin_mask >>= pio_get_gpio_base(pio); +#endif + pio_sm_set_pins_with_mask_internal(pio, sm, pin_values, pin_mask); } +#endif -void pio_sm_set_pindirs_with_mask64(PIO pio, uint sm, uint64_t pindirs, uint64_t pin_mask) { - check_pio_param(pio); - check_sm_param(sm); - check_pio_pin_mask64(pio, pin_mask); +void pio_sm_set_pins_with_mask64(PIO pio, uint sm, uint64_t pin_values, uint64_t pin_mask) { + check_pio_pin_mask64(pio, sm, pin_mask); #if PICO_PIO_USE_GPIO_BASE - pindirs >>= pio_get_gpio_base(pio); + pin_values >>= pio_get_gpio_base(pio); pin_mask >>= pio_get_gpio_base(pio); #endif + pio_sm_set_pins_with_mask_internal(pio, sm, pin_values, pin_mask); +} + +void pio_sm_set_pindirs_with_mask_internal(PIO pio, uint sm, uint32_t pindirs, uint32_t pin_mask) { + check_pio_param(pio); + check_sm_param(sm); uint32_t pinctrl_saved = pio->sm[sm].pinctrl; uint32_t execctrl_saved = pio->sm[sm].execctrl; hw_clear_bits(&pio->sm[sm].execctrl, 1u << PIO_SM0_EXECCTRL_OUT_STICKY_LSB); @@ -294,6 +313,24 @@ void pio_sm_set_pindirs_with_mask64(PIO pio, uint sm, uint64_t pindirs, uint64_t pio->sm[sm].execctrl = execctrl_saved; } +#ifndef pio_sm_set_pindirs_with_mask_internal +void pio_sm_set_pindirs_with_mask(PIO pio, uint sm, uint32_t pindirs, uint32_t pin_mask) { +#if PICO_PIO_USE_GPIO_BASE + pindirs >>= pio_get_gpio_base(pio); + pin_mask >>= pio_get_gpio_base(pio); +#endif + pio_sm_set_pindirs_with_mask_internal(pio, sm, pindirs, pin_mask); +} +#endif + +void pio_sm_set_pindirs_with_mask64(PIO pio, uint sm, uint64_t pindirs, uint64_t pin_mask) { +#if PICO_PIO_USE_GPIO_BASE + pindirs >>= pio_get_gpio_base(pio); + pin_mask >>= pio_get_gpio_base(pio); +#endif + pio_sm_set_pindirs_with_mask_internal(pio, sm, (uint32_t)pindirs, (uint32_t)pin_mask); +} + int pio_sm_set_consecutive_pindirs(PIO pio, uint sm, uint pin, uint count, bool is_out) { check_pio_param(pio); check_sm_param(sm);