From 549674a68be65b8dfd1caa41d6090f83eb42a831 Mon Sep 17 00:00:00 2001 From: Andrew Scheller Date: Thu, 5 Mar 2026 21:43:11 +0000 Subject: [PATCH] Check for parameter underflow when PIO_USE_GPIO_BASE is in use (#2618) * Fix PIO comment and assertion typos * Add (and use) 32-bit version of check_pio_pin_mask64 * minor comment tidyup * small code size improvement * oops * hmm * fix typos --------- Co-authored-by: Graham Sanderson --- .../hardware_pio/include/hardware/pio.h | 151 +++++++++--------- src/rp2_common/hardware_pio/pio.c | 36 +++-- 2 files changed, 102 insertions(+), 85 deletions(-) diff --git a/src/rp2_common/hardware_pio/include/hardware/pio.h b/src/rp2_common/hardware_pio/include/hardware/pio.h index ee0f0faa..dd111e13 100644 --- a/src/rp2_common/hardware_pio/include/hardware/pio.h +++ b/src/rp2_common/hardware_pio/include/hardware/pio.h @@ -774,7 +774,7 @@ static inline pio_sm_config pio_get_default_sm_config(void) { * This method always return 0 in RP2040 * \endif * - * \param pio The PIO instance; e.g. \ref pio0 or \ref pio1 + * \param pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \return the current GPIO base for the PIO instance */ static inline uint pio_get_gpio_base(PIO pio) { @@ -786,6 +786,13 @@ static inline uint pio_get_gpio_base(PIO pio) { #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 & ~(0xffffffffu << pio_get_gpio_base(pio))) == 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 @@ -801,7 +808,7 @@ static inline void check_pio_pin_mask64(__unused PIO pio, __unused uint sm, __un * \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 pio Handle to PIO instance; e.g. \ref pio0, \ref pio1 etc. * \param sm State machine index (0..3) * \param config the configuration to apply * \return PICO_OK (0) on success, negative error code otherwise @@ -836,7 +843,7 @@ static inline int pio_sm_set_config(PIO pio, uint sm, const pio_sm_config *confi /*! \brief Return the instance number of a PIO instance * \ingroup hardware_pio * - * \param pio The PIO instance; e.g. \ref pio0 or \ref pio1 + * \param pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \return the PIO instance number (0, 1, ...) */ static inline uint pio_get_index(PIO pio) { @@ -847,7 +854,7 @@ static inline uint pio_get_index(PIO 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 + * \param pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \return the PIO instance number (0, 1, ...) * \see gpio_function_t */ @@ -892,7 +899,7 @@ static inline PIO pio_get_instance(uint instance) { * 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \param pin the GPIO pin whose function select to set */ static inline void pio_gpio_init(PIO pio, uint pin) { @@ -904,7 +911,7 @@ static inline void pio_gpio_init(PIO pio, uint 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \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 */ @@ -933,8 +940,8 @@ typedef struct pio_program { * * 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \param gpio_base the GPIO base (either 0 or 16) * \return PICO_OK (0) on success, error code otherwise */ @@ -943,7 +950,7 @@ 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \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 @@ -953,7 +960,7 @@ 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \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; @@ -966,7 +973,7 @@ bool pio_can_add_program_at_offset(PIO pio, const pio_program_t *program, uint o * * 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \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) @@ -978,7 +985,7 @@ int pio_add_program(PIO pio, const pio_program_t *program); * * 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \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 @@ -989,7 +996,7 @@ 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \param program the program definition * \param loaded_offset the loaded offset returned when the program was added */ @@ -998,7 +1005,7 @@ void pio_remove_program(PIO pio, const pio_program_t *program, uint loaded_offse /*! \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 + * \param pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. */ void pio_clear_instruction_memory(PIO pio); @@ -1017,8 +1024,8 @@ void pio_clear_instruction_memory(PIO 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 The PIO instance; e.g. \ref pio0 or \ref pio1 + * + * \param pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \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) @@ -1029,7 +1036,7 @@ 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \param sm State machine index (0..3) * \param enabled true to enable the state machine; false to disable */ @@ -1048,7 +1055,7 @@ static inline void pio_sm_set_enabled(PIO pio, uint sm, bool enabled) { * 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \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 */ @@ -1068,7 +1075,7 @@ static inline void pio_set_sm_mask_enabled(PIO pio, uint32_t mask, bool enabled) * 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \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 @@ -1092,7 +1099,7 @@ static inline void pio_set_sm_multi_mask_enabled(PIO pio, uint32_t mask_prev, ui * 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \param sm State machine index (0..3) */ static inline void pio_sm_restart(PIO pio, uint sm) { @@ -1107,7 +1114,7 @@ static inline void pio_sm_restart(PIO pio, uint sm) { * 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \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) { @@ -1134,7 +1141,7 @@ static inline void pio_restart_sm_mask(PIO pio, uint32_t mask) { * 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \param sm State machine index (0..3) */ static inline void pio_sm_clkdiv_restart(PIO pio, uint sm) { @@ -1169,7 +1176,7 @@ static inline void pio_sm_clkdiv_restart(PIO pio, uint sm) { * 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \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) { @@ -1205,7 +1212,7 @@ static inline void pio_clkdiv_restart_sm_mask(PIO pio, uint32_t mask) { * 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \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 @@ -1228,7 +1235,7 @@ static inline void pio_clkdiv_restart_sm_multi_mask(PIO pio, uint32_t mask_prev, * 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \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) { @@ -1248,7 +1255,7 @@ static inline void pio_enable_sm_mask_in_sync(PIO pio, uint32_t mask) { * 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \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 @@ -1293,7 +1300,7 @@ typedef enum pio_interrupt_source { /*! \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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \param source the source number (see \ref pio_interrupt_source) * \param enabled true to enable IRQ 0 for the source, false to disable. */ @@ -1309,7 +1316,7 @@ static inline void pio_set_irq0_source_enabled(PIO pio, pio_interrupt_source_t s /*! \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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \param source the source number (see \ref pio_interrupt_source) * \param enabled true to enable IRQ 0 for the source, false to disable. */ @@ -1325,7 +1332,7 @@ static inline void pio_set_irq1_source_enabled(PIO pio, pio_interrupt_source_t s /*! \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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \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 */ @@ -1342,7 +1349,7 @@ static inline void pio_set_irq0_source_mask_enabled(PIO pio, uint32_t source_mas /*! \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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \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 */ @@ -1359,7 +1366,7 @@ static inline void pio_set_irq1_source_mask_enabled(PIO pio, uint32_t source_mas /*! \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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \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. @@ -1376,7 +1383,7 @@ static inline void pio_set_irqn_source_enabled(PIO pio, uint irq_index, pio_inte /*! \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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \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 @@ -1395,7 +1402,7 @@ static inline void pio_set_irqn_source_mask_enabled(PIO pio, uint irq_index, uin /*! \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 The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \param pio_interrupt_num the PIO interrupt number 0-7 * \return true if corresponding PIO interrupt is currently set */ @@ -1408,7 +1415,7 @@ static inline bool pio_interrupt_get(PIO pio, uint 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 The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \param pio_interrupt_num the PIO interrupt number 0-7 */ static inline void pio_interrupt_clear(PIO pio, uint pio_interrupt_num) { @@ -1420,7 +1427,7 @@ static inline void pio_interrupt_clear(PIO pio, uint 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \param sm State machine index (0..3) * \return the program counter */ @@ -1438,7 +1445,7 @@ static inline uint8_t pio_sm_get_pc(PIO pio, uint sm) { * 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \param sm State machine index (0..3) * \param instr the encoded PIO instruction */ @@ -1451,7 +1458,7 @@ inline static void pio_sm_exec(PIO pio, uint sm, uint 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \param sm State machine index (0..3) * \return true if the executed instruction is still running (stalled) */ @@ -1469,7 +1476,7 @@ static inline bool pio_sm_is_exec_stalled(PIO pio, uint sm) { * 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \param sm State machine index (0..3) * \param instr the encoded PIO instruction */ @@ -1483,7 +1490,7 @@ static inline void pio_sm_exec_wait_blocking(PIO pio, uint sm, uint instr) { /*! \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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \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 @@ -1505,7 +1512,7 @@ static inline void pio_sm_set_wrap(PIO pio, uint sm, uint wrap_target, uint wrap * * 'out' pins can overlap with the 'in', 'set' and 'sideset' pins * - * \param pio The PIO instance; e.g. \ref pio0 or \ref pio1 + * \param pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \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. @@ -1529,7 +1536,7 @@ static inline void pio_sm_set_out_pins(PIO pio, uint sm, uint out_base, uint out * * 'set' pins can overlap with the 'in', 'out' and 'sideset' pins * - * \param pio The PIO instance; e.g. \ref pio0 or \ref pio1 + * \param pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \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. @@ -1552,7 +1559,7 @@ static inline void pio_sm_set_set_pins(PIO pio, uint sm, uint set_base, uint set * * 'in' pins can overlap with the 'out', 'set' and 'sideset' pins * - * \param pio The PIO instance; e.g. \ref pio0 or \ref pio1 + * \param pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \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 */ @@ -1572,7 +1579,7 @@ static inline void pio_sm_set_in_pins(PIO pio, uint sm, uint in_base) { * * 'sideset' pins can overlap with the 'in', 'out' and 'set' pins * - * \param pio The PIO instance; e.g. \ref pio0 or \ref pio1 + * \param pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \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 */ @@ -1590,7 +1597,7 @@ static inline void pio_sm_set_sideset_pins(PIO pio, uint sm, uint sideset_base) /*! \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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \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 */ @@ -1615,7 +1622,7 @@ static inline void pio_sm_set_jmp_pin(PIO pio, uint sm, uint pin) { * 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \param sm State machine index (0..3) * \param data the 32 bit data value * @@ -1637,7 +1644,7 @@ static inline void pio_sm_put(PIO pio, uint sm, uint32_t data) { * 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \param sm State machine index (0..3) * * \sa pio_sm_get_blocking() @@ -1651,7 +1658,7 @@ static inline uint32_t pio_sm_get(PIO pio, uint 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \param sm State machine index (0..3) * \return true if the RX FIFO is full */ @@ -1664,7 +1671,7 @@ static inline bool pio_sm_is_rx_fifo_full(PIO pio, uint sm) { /*! \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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \param sm State machine index (0..3) * \return true if the RX FIFO is empty */ @@ -1677,7 +1684,7 @@ static inline bool pio_sm_is_rx_fifo_empty(PIO pio, uint sm) { /*! \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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \param sm State machine index (0..3) * \return the number of elements in the RX FIFO */ @@ -1692,7 +1699,7 @@ static inline uint pio_sm_get_rx_fifo_level(PIO pio, uint sm) { /*! \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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \param sm State machine index (0..3) * \return true if the TX FIFO is full */ @@ -1705,7 +1712,7 @@ static inline bool pio_sm_is_tx_fifo_full(PIO pio, uint sm) { /*! \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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \param sm State machine index (0..3) * \return true if the TX FIFO is empty */ @@ -1718,7 +1725,7 @@ static inline bool pio_sm_is_tx_fifo_empty(PIO pio, uint sm) { /*! \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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \param sm State machine index (0..3) * \return the number of elements in the TX FIFO */ @@ -1733,7 +1740,7 @@ static inline uint pio_sm_get_tx_fifo_level(PIO pio, uint sm) { /*! \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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \param sm State machine index (0..3) * \param data the 32 bit data value */ @@ -1747,7 +1754,7 @@ static inline void pio_sm_put_blocking(PIO pio, uint sm, uint32_t 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \param sm State machine index (0..3) */ static inline uint32_t pio_sm_get_blocking(PIO pio, uint sm) { @@ -1765,7 +1772,7 @@ static inline uint32_t pio_sm_get_blocking(PIO pio, uint sm) { * 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \param sm State machine index (0..3) * * \sa pio_sm_clear_fifos() @@ -1775,7 +1782,7 @@ 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \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 @@ -1800,7 +1807,7 @@ static inline void pio_sm_set_clkdiv_int_frac(PIO pio, uint sm, uint16_t div_int /*! \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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \param sm State machine index (0..3) * \param div the floating point clock divider */ @@ -1816,7 +1823,7 @@ static inline void pio_sm_set_clkdiv(PIO pio, uint sm, float div) { /*! \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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \param sm State machine index (0..3) */ static inline void pio_sm_clear_fifos(PIO pio, uint sm) { @@ -1836,7 +1843,7 @@ static inline void pio_sm_clear_fifos(PIO pio, uint sm) { * 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \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 */ @@ -1850,7 +1857,7 @@ void pio_sm_set_pins(PIO pio, uint sm, uint32_t pin_values); * * 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \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 */ @@ -1865,7 +1872,7 @@ void pio_sm_set_pins64(PIO pio, uint sm, uint64_t pin_values); * 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \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 @@ -1875,12 +1882,12 @@ void pio_sm_set_pins_with_mask(PIO pio, uint sm, uint32_t pin_values, uint32_t p /*! \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, + * This method repeatedly reconfigures the target state machine's pin configuration and executes 'set' instructions to set values on all 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \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 @@ -1896,7 +1903,7 @@ void pio_sm_set_pins_with_mask64(PIO pio, uint sm, uint64_t pin_values, uint64_t * 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \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_dir for that pin should be applied. @@ -1906,12 +1913,12 @@ void pio_sm_set_pindirs_with_mask(PIO pio, uint sm, uint32_t pin_dirs, uint32_t /*! \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, + * This method repeatedly reconfigures the target state machine's pin configuration and executes 'set' instructions to set pin directions on all 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \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_dir for that pin should be applied. @@ -1926,7 +1933,7 @@ void pio_sm_set_pindirs_with_mask64(PIO pio, uint sm, uint64_t pin_dirs, uint64_ * * 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \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 @@ -1942,7 +1949,7 @@ int pio_sm_set_consecutive_pindirs(PIO pio, uint sm, uint pins_base, uint pin_co * 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \param sm State machine index (0..3) */ void pio_sm_claim(PIO pio, uint sm); @@ -1954,7 +1961,7 @@ void pio_sm_claim(PIO pio, uint sm); * 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \param sm_mask Mask of state machine indexes */ void pio_claim_sm_mask(PIO pio, uint sm_mask); @@ -1964,7 +1971,7 @@ void pio_claim_sm_mask(PIO pio, uint sm_mask); * * Method for cooperative claiming of hardware. * - * \param pio The PIO instance; e.g. \ref pio0 or \ref pio1 + * \param pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \param sm State machine index (0..3) */ void pio_sm_unclaim(PIO pio, uint sm); @@ -1972,7 +1979,7 @@ 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \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) @@ -1982,7 +1989,7 @@ 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 pio The PIO instance; e.g. \ref pio0, \ref pio1 etc. * \param sm State machine index (0..3) * \return true if claimed, false otherwise * \see pio_sm_claim diff --git a/src/rp2_common/hardware_pio/pio.c b/src/rp2_common/hardware_pio/pio.c index edff012d..0ef49ec4 100644 --- a/src/rp2_common/hardware_pio/pio.c +++ b/src/rp2_common/hardware_pio/pio.c @@ -82,10 +82,10 @@ static int find_offset_for_program(PIO pio, const pio_program_t *program) { } static int pio_set_gpio_base_unsafe(PIO pio, uint gpio_base) { - invalid_params_if_and_return(PIO, gpio_base != 0 && (!PICO_PIO_VERSION || gpio_base != 16), PICO_ERROR_BAD_ALIGNMENT); + invalid_params_if_and_return(HARDWARE_PIO, gpio_base != 0 && (!PICO_PIO_VERSION || gpio_base != 16), PICO_ERROR_BAD_ALIGNMENT); #if PICO_PIO_VERSION > 0 uint32_t used_mask = _used_instruction_space[pio_get_index(pio)]; - invalid_params_if_and_return(PIO, used_mask, PICO_ERROR_INVALID_STATE); + invalid_params_if_and_return(HARDWARE_PIO, used_mask, PICO_ERROR_INVALID_STATE); pio->gpiobase = gpio_base; #else ((void)pio); @@ -251,6 +251,7 @@ void pio_sm_set_pins_internal(PIO pio, uint sm, uint32_t pins) { #ifndef pio_sm_set_pins_internal void pio_sm_set_pins(PIO pio, uint sm, uint32_t pins) { + check_pio_pin_mask(pio, sm, pins); #if PICO_PIO_USE_GPIO_BASE pins >>= pio_get_gpio_base(pio); #endif @@ -287,9 +288,11 @@ void pio_sm_set_pins_with_mask_internal(PIO pio, uint sm, uint32_t pin_values, u #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) { + check_pio_pin_mask(pio, sm, pin_mask); #if PICO_PIO_USE_GPIO_BASE - pin_values >>= pio_get_gpio_base(pio); - pin_mask >>= pio_get_gpio_base(pio); + uint gpio_base = pio_get_gpio_base(pio); + pin_values >>= gpio_base; + pin_mask >>= gpio_base; #endif pio_sm_set_pins_with_mask_internal(pio, sm, pin_values, pin_mask); } @@ -298,8 +301,9 @@ void pio_sm_set_pins_with_mask(PIO pio, uint sm, uint32_t pin_values, uint32_t p 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 - pin_values >>= pio_get_gpio_base(pio); - pin_mask >>= pio_get_gpio_base(pio); + uint gpio_base = pio_get_gpio_base(pio); + pin_values >>= gpio_base; + pin_mask >>= gpio_base; #endif pio_sm_set_pins_with_mask_internal(pio, sm, (uint32_t)pin_values, (uint32_t)pin_mask); } @@ -324,18 +328,22 @@ void pio_sm_set_pindirs_with_mask_internal(PIO pio, uint sm, uint32_t pindirs, u #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) { + check_pio_pin_mask(pio, sm, pin_mask); #if PICO_PIO_USE_GPIO_BASE - pindirs >>= pio_get_gpio_base(pio); - pin_mask >>= pio_get_gpio_base(pio); + uint gpio_base = pio_get_gpio_base(pio); + pindirs >>= gpio_base; + pin_mask >>= gpio_base; #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) { + check_pio_pin_mask64(pio, sm, pin_mask); #if PICO_PIO_USE_GPIO_BASE - pindirs >>= pio_get_gpio_base(pio); - pin_mask >>= pio_get_gpio_base(pio); + uint gpio_base = pio_get_gpio_base(pio); + pindirs >>= gpio_base; + pin_mask >>= gpio_base; #endif pio_sm_set_pindirs_with_mask_internal(pio, sm, (uint32_t)pindirs, (uint32_t)pin_mask); } @@ -343,8 +351,10 @@ void pio_sm_set_pindirs_with_mask64(PIO pio, uint sm, uint64_t pindirs, uint64_t 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); +#if PICO_PIO_USE_GPIO_BASE pin -= pio_get_gpio_base(pio); - invalid_params_if_and_return(PIO, pin >= 32u, PICO_ERROR_INVALID_ARG); +#endif + invalid_params_if_and_return(HARDWARE_PIO, pin >= 32u, PICO_ERROR_INVALID_ARG); 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); @@ -409,12 +419,12 @@ bool pio_claim_free_sm_and_add_program_for_gpio_range(const pio_program_t *progr invalid_params_if(HARDWARE_PIO, (gpio_start + gpio_count) > NUM_BANK0_GPIOS); #if !PICO_PIO_USE_GPIO_BASE - // short-circuit some logic when not using GIO_BASE + // short-circuit some logic when not using GPIO_BASE set_gpio_base = 0; gpio_count = 0; #endif - // note if we gpio_count == 0, we don't care about GPIOs so use a zero mask for what we require + // note if gpio_count == 0, we don't care about GPIOs so use a zero mask for what we require // if gpio_count > 0, then we just set used mask for the ends, since that is all that is checked at the moment uint32_t required_gpio_ranges; if (gpio_count) required_gpio_ranges = (1u << (gpio_start >> 4)) | (1u << ((gpio_start + gpio_count - 1) >> 4));