diff --git a/src/rp2_common/hardware_pio/include/hardware/pio.h b/src/rp2_common/hardware_pio/include/hardware/pio.h index 264adeff7..1a3bcc053 100644 --- a/src/rp2_common/hardware_pio/include/hardware/pio.h +++ b/src/rp2_common/hardware_pio/include/hardware/pio.h @@ -708,6 +708,15 @@ static inline uint pio_get_gpio_base(PIO pio) { #endif } +static inline void check_pio_pin_mask64(__unused PIO pio, __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 * @@ -1717,6 +1726,7 @@ static inline void pio_sm_clear_fifos(PIO pio, uint sm) { * 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 @@ -1724,6 +1734,20 @@ static inline void pio_sm_clear_fifos(PIO pio, uint sm) { */ 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 + */ +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 * @@ -1731,6 +1755,7 @@ void pio_sm_set_pins(PIO pio, uint sm, uint32_t pin_values); * 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 @@ -1739,6 +1764,21 @@ void pio_sm_set_pins(PIO pio, uint sm, uint32_t pin_values); */ void pio_sm_set_pins_with_mask(PIO pio, uint sm, uint32_t pin_values, uint32_t pin_mask); +/*! \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. + */ +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 * @@ -1746,6 +1786,7 @@ void pio_sm_set_pins_with_mask(PIO pio, uint sm, uint32_t pin_values, uint32_t p * 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 @@ -1754,6 +1795,21 @@ void pio_sm_set_pins_with_mask(PIO pio, uint sm, uint32_t pin_values, uint32_t p */ 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 * diff --git a/src/rp2_common/hardware_pio/pio.c b/src/rp2_common/hardware_pio/pio.c index 120dbf3f1..8a1a892e7 100644 --- a/src/rp2_common/hardware_pio/pio.c +++ b/src/rp2_common/hardware_pio/pio.c @@ -205,13 +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); +} + // 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_pins(PIO pio, uint sm, uint32_t pins) { +void pio_sm_set_pins64(PIO pio, uint sm, uint64_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); @@ -232,8 +241,17 @@ void pio_sm_set_pins(PIO pio, uint sm, uint32_t pins) { } 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); +} + +void pio_sm_set_pins_with_mask64(PIO pio, uint sm, uint64_t pinvals, uint64_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); @@ -250,8 +268,17 @@ void pio_sm_set_pins_with_mask(PIO pio, uint sm, uint32_t pinvals, uint32_t pin_ } 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); +} + +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); +#if PICO_PIO_USE_GPIO_BASE + pindirs >>= 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); diff --git a/src/rp2_common/pico_cyw43_driver/cyw43_bus_pio_spi.c b/src/rp2_common/pico_cyw43_driver/cyw43_bus_pio_spi.c index 5c5111b00..bcc7284f1 100644 --- a/src/rp2_common/pico_cyw43_driver/cyw43_bus_pio_spi.c +++ b/src/rp2_common/pico_cyw43_driver/cyw43_bus_pio_spi.c @@ -250,9 +250,7 @@ int cyw43_spi_transfer(cyw43_int_t *self, const uint8_t *tx, size_t tx_length, u pio_sm_set_enabled(bus_data->pio, bus_data->pio_sm, false); pio_sm_set_wrap(bus_data->pio, bus_data->pio_sm, bus_data->pio_offset, bus_data->pio_offset + SPI_OFFSET_END - 1); pio_sm_clear_fifos(bus_data->pio, bus_data->pio_sm); - pio_sm_set_pindirs_with_mask(bus_data->pio, bus_data->pio_sm, - 1u << (CYW43_PIN_WL_DATA_OUT - pio_get_gpio_base(bus_data->pio)), - 1u << (CYW43_PIN_WL_DATA_OUT - pio_get_gpio_base(bus_data->pio))); + pio_sm_set_pindirs_with_mask64(bus_data->pio, bus_data->pio_sm, 1ull << CYW43_PIN_WL_DATA_OUT, 1ull << CYW43_PIN_WL_DATA_OUT); pio_sm_restart(bus_data->pio, bus_data->pio_sm); pio_sm_clkdiv_restart(bus_data->pio, bus_data->pio_sm); pio_sm_put(bus_data->pio, bus_data->pio_sm, tx_length * 8 - 1); @@ -294,9 +292,7 @@ int cyw43_spi_transfer(cyw43_int_t *self, const uint8_t *tx, size_t tx_length, u pio_sm_set_enabled(bus_data->pio, bus_data->pio_sm, false); pio_sm_set_wrap(bus_data->pio, bus_data->pio_sm, bus_data->pio_offset, bus_data->pio_offset + SPI_OFFSET_LP1_END - 1); pio_sm_clear_fifos(bus_data->pio, bus_data->pio_sm); - pio_sm_set_pindirs_with_mask(bus_data->pio, bus_data->pio_sm, - 1u << (CYW43_PIN_WL_DATA_OUT - pio_get_gpio_base(bus_data->pio)), - 1u << (CYW43_PIN_WL_DATA_OUT - pio_get_gpio_base(bus_data->pio))); + pio_sm_set_pindirs_with_mask64(bus_data->pio, bus_data->pio_sm, 1ull << CYW43_PIN_WL_DATA_OUT, 1ull << CYW43_PIN_WL_DATA_OUT); pio_sm_restart(bus_data->pio, bus_data->pio_sm); pio_sm_clkdiv_restart(bus_data->pio, bus_data->pio_sm); pio_sm_put(bus_data->pio, bus_data->pio_sm, tx_length * 8 - 1);