From 5afa3636d6706764bc54a6dffb4e7f71b9aa8125 Mon Sep 17 00:00:00 2001 From: Graham Sanderson Date: Wed, 2 Jun 2021 13:12:27 -0500 Subject: [PATCH] Small API additions and minor fixes (#406) * Add missing DREQ_s * store actual clock frequency in clock_configure (fixes #368) * use dma DREQ values defined in dreqs/dma.h * Fix hw_is_claimed, and add xxx_is_claimed APIs * Add some PIO irq helper methods * Add DMA channel IRQ status getter and clear methods * Implement the correct PIO IRQ status/clear methods (good to have methods here as the h/w interrupt registers are super confusing) * fix pico_multicore dependencies * add missing wrapper func __aeabi_f2d * Further DMA/PIO IRQ API cleanup (and review fixes) * add PICO_INT64_OPS_IN_RAM flag --- cmake/preload/toolchains/pico_arm_gcc.cmake | 2 +- src/common/pico_time/time.c | 2 +- src/rp2_common/cmsis/CMakeLists.txt | 2 +- .../cmsis/include/cmsis/rename_exceptions.h | 2 + src/rp2_common/hardware_claim/claim.c | 19 +- .../hardware_claim/include/hardware/claim.h | 4 +- src/rp2_common/hardware_clocks/clocks.c | 2 +- src/rp2_common/hardware_dma/dma.c | 5 + .../hardware_dma/include/hardware/dma.h | 125 +++++++++++++- .../hardware_interp/include/hardware/interp.h | 17 +- src/rp2_common/hardware_interp/interp.c | 17 +- .../hardware_pio/include/hardware/pio.h | 163 ++++++++++++++++++ src/rp2_common/hardware_pio/pio.c | 7 + .../hardware_sync/include/hardware/sync.h | 10 ++ src/rp2_common/hardware_sync/sync.c | 5 + .../hardware_timer/include/hardware/timer.h | 9 + src/rp2_common/hardware_timer/timer.c | 5 + src/rp2_common/pico_float/float_none.S | 1 + .../pico_int64_ops/pico_int64_ops_aeabi.S | 4 + src/rp2_common/pico_multicore/CMakeLists.txt | 2 +- src/rp2_common/pico_multicore/multicore.c | 1 - 21 files changed, 368 insertions(+), 36 deletions(-) diff --git a/cmake/preload/toolchains/pico_arm_gcc.cmake b/cmake/preload/toolchains/pico_arm_gcc.cmake index 77b94e1..d8c56fc 100644 --- a/cmake/preload/toolchains/pico_arm_gcc.cmake +++ b/cmake/preload/toolchains/pico_arm_gcc.cmake @@ -12,7 +12,7 @@ if (NOT PICO_GCC_TRIPLE) message("PICO_GCC_TRIPLE set from environment: $ENV{PICO_GCC_TRIPLE}") else() set(PICO_GCC_TRIPLE arm-none-eabi) - pico_message_debug("PICO_GCC_TRIPLE defaulted to arm-none-eabi") + #pico_message_debug("PICO_GCC_TRIPLE defaulted to arm-none-eabi") endif() endif() diff --git a/src/common/pico_time/time.c b/src/common/pico_time/time.c index 7c06041..f965ab8 100644 --- a/src/common/pico_time/time.c +++ b/src/common/pico_time/time.c @@ -283,7 +283,7 @@ static void alarm_pool_dump_key(pheap_node_id_t id, void *user_data) { #endif } -static int64_t repeating_timer_callback(__unused alarm_id_t id, __unused void *user_data) { +static int64_t repeating_timer_callback(__unused alarm_id_t id, void *user_data) { repeating_timer_t *rt = (repeating_timer_t *)user_data; assert(rt->alarm_id == id); if (rt->callback(rt)) { diff --git a/src/rp2_common/cmsis/CMakeLists.txt b/src/rp2_common/cmsis/CMakeLists.txt index fc099ae..0d663e1 100644 --- a/src/rp2_common/cmsis/CMakeLists.txt +++ b/src/rp2_common/cmsis/CMakeLists.txt @@ -50,7 +50,7 @@ set(PICO_CMSIS_VENDOR RaspberryPi) set(PICO_CMSIS_DEVICE RP2040) if (PICO_CMSIS_CORE_PATH) - add_library(cmsis_core INTERFACE) + pico_add_impl_library(cmsis_core) target_sources(cmsis_core INTERFACE ${PICO_CMSIS_CORE_PATH}/CMSIS/Device/${PICO_CMSIS_VENDOR}/${PICO_CMSIS_DEVICE}/Source/system_${PICO_CMSIS_DEVICE}.c ) diff --git a/src/rp2_common/cmsis/include/cmsis/rename_exceptions.h b/src/rp2_common/cmsis/include/cmsis/rename_exceptions.h index ba28526..a523d27 100644 --- a/src/rp2_common/cmsis/include/cmsis/rename_exceptions.h +++ b/src/rp2_common/cmsis/include/cmsis/rename_exceptions.h @@ -7,6 +7,7 @@ #ifndef _CMSIS_RENAME_EXCEPTIONS_H #define _CMSIS_RENAME_EXCEPTIONS_H +#if LIB_CMSIS_CORE // PICO_CONFIG: PICO_CMSIS_RENAME_EXCEPTIONS, Whether to rename SDK exceptions such as isr_nmi to their CMSIS equivalent i.e. NMI_Handler, type=bool, default=1, group=cmsis_core // Note that since this header is included at the config stage, if you wish to override this you should do so via build compiler define @@ -48,4 +49,5 @@ #define isr_irq25 RTC_IRQ_Handler #endif +#endif #endif /* _CMSIS_RENAME_EXCEPTIONS_H */ diff --git a/src/rp2_common/hardware_claim/claim.c b/src/rp2_common/hardware_claim/claim.c index 96f341e..c96764f 100644 --- a/src/rp2_common/hardware_claim/claim.c +++ b/src/rp2_common/hardware_claim/claim.c @@ -14,22 +14,13 @@ void hw_claim_unlock(uint32_t save) { spin_unlock(spin_lock_instance(PICO_SPINLOCK_ID_HARDWARE_CLAIM), save); } -bool hw_is_claimed(uint8_t *bits, uint bit_index) { - bool rc; - uint32_t save = hw_claim_lock(); - if (bits[bit_index >> 3u] & (1u << (bit_index & 7u))) { - rc = false; - } else { - bits[bit_index >> 3u] |= (uint8_t)(1u << (bit_index & 7u)); - rc = true; - } - hw_claim_unlock(save); - return rc; +inline bool hw_is_claimed(const uint8_t *bits, uint bit_index) { + return (bits[bit_index >> 3u] & (1u << (bit_index & 7u))); } void hw_claim_or_assert(uint8_t *bits, uint bit_index, const char *message) { uint32_t save = hw_claim_lock(); - if (bits[bit_index >> 3u] & (1u << (bit_index & 7u))) { + if (hw_is_claimed(bits, bit_index)) { panic(message, bit_index); } else { bits[bit_index >> 3u] |= (uint8_t)(1u << (bit_index & 7u)); @@ -42,7 +33,7 @@ int hw_claim_unused_from_range(uint8_t *bits, bool required, uint bit_lsb, uint uint32_t save = hw_claim_lock(); int found_bit = -1; for(uint bit=bit_lsb; bit <= bit_msb; bit++) { - if (!(bits[bit >> 3u] & (1u << (bit & 7u)))) { + if (!hw_is_claimed(bits, bit)) { bits[bit >> 3u] |= (uint8_t)(1u << (bit & 7u)); found_bit = (int)bit; break; @@ -57,7 +48,7 @@ int hw_claim_unused_from_range(uint8_t *bits, bool required, uint bit_lsb, uint void hw_claim_clear(uint8_t *bits, uint bit_index) { uint32_t save = hw_claim_lock(); - assert(bits[bit_index >> 3u] & (1u << (bit_index & 7u))); + assert(hw_is_claimed(bits, bit_index)); bits[bit_index >> 3u] &= (uint8_t) ~(1u << (bit_index & 7u)); hw_claim_unlock(save); } diff --git a/src/rp2_common/hardware_claim/include/hardware/claim.h b/src/rp2_common/hardware_claim/include/hardware/claim.h index 681962a..5c93453 100644 --- a/src/rp2_common/hardware_claim/include/hardware/claim.h +++ b/src/rp2_common/hardware_claim/include/hardware/claim.h @@ -65,10 +65,10 @@ int hw_claim_unused_from_range(uint8_t *bits, bool required, uint bit_lsb, uint * The resource ownership is indicated by the bit_index bit in an array of bits. * * \param bits pointer to an array of bits (8 bits per byte) - * \param bit_index resource to unclaim (bit index into array of bits) + * \param bit_index resource to check (bit index into array of bits) * \return true if the resource is claimed */ -bool hw_is_claimed(uint8_t *bits, uint bit_index); +bool hw_is_claimed(const uint8_t *bits, uint bit_index); /*! \brief Atomically unclaim a resource * \ingroup hardware_claim diff --git a/src/rp2_common/hardware_clocks/clocks.c b/src/rp2_common/hardware_clocks/clocks.c index ec26d2d..f51331a 100644 --- a/src/rp2_common/hardware_clocks/clocks.c +++ b/src/rp2_common/hardware_clocks/clocks.c @@ -112,7 +112,7 @@ bool clock_configure(enum clock_index clk_index, uint32_t src, uint32_t auxsrc, clock->div = div; // Store the configured frequency - configured_freq[clk_index] = freq; + configured_freq[clk_index] = (uint32_t)(((uint64_t) src_freq << 8) / div); return true; } diff --git a/src/rp2_common/hardware_dma/dma.c b/src/rp2_common/hardware_dma/dma.c index d648bfb..230fa16 100644 --- a/src/rp2_common/hardware_dma/dma.c +++ b/src/rp2_common/hardware_dma/dma.c @@ -39,6 +39,11 @@ int dma_claim_unused_channel(bool required) { return hw_claim_unused_from_range((uint8_t*)&_claimed, required, 0, NUM_DMA_CHANNELS-1, "No DMA channels are available"); } +bool dma_channel_is_claimed(uint channel) { + check_dma_channel_param(channel); + return hw_is_claimed((uint8_t *) &_claimed, channel); +} + #ifndef NDEBUG void print_dma_ctrl(dma_channel_hw_t *channel) { diff --git a/src/rp2_common/hardware_dma/include/hardware/dma.h b/src/rp2_common/hardware_dma/include/hardware/dma.h index be67303..526d632 100644 --- a/src/rp2_common/hardware_dma/include/hardware/dma.h +++ b/src/rp2_common/hardware_dma/include/hardware/dma.h @@ -34,8 +34,12 @@ extern "C" { * * Memory to memory */ -// this is not defined in generated dreq.h -#define DREQ_FORCE 63 +// these are not defined in generated dreq.h +#define DREQ_DMA_TIMER0 DMA_CH0_CTRL_TRIG_TREQ_SEL_VALUE_TIMER0 +#define DREQ_DMA_TIMER1 DMA_CH0_CTRL_TRIG_TREQ_SEL_VALUE_TIMER1 +#define DREQ_DMA_TIMER2 DMA_CH0_CTRL_TRIG_TREQ_SEL_VALUE_TIMER2 +#define DREQ_DMA_TIMER3 DMA_CH0_CTRL_TRIG_TREQ_SEL_VALUE_TIMER3 +#define DREQ_FORCE DMA_CH0_CTRL_TRIG_TREQ_SEL_VALUE_PERMANENT // PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_DMA, Enable/disable DMA assertions, type=bool, default=0, group=hardware_dma #ifndef PARAM_ASSERTIONS_ENABLED_DMA @@ -94,6 +98,16 @@ void dma_channel_unclaim(uint channel); */ int dma_claim_unused_channel(bool required); +/*! \brief Determine if a dma channel is claimed + * \ingroup hardware_dma + * + * \param channel the dma channel + * \return true if the channel is claimed, false otherwise + * \see dma_channel_claim + * \see dma_channel_claim_mask + */ +bool dma_channel_is_claimed(uint channel); + /** \brief DMA channel configuration * \defgroup channel_config channel_config * \ingroup hardware_dma @@ -465,7 +479,7 @@ static inline void dma_channel_abort(uint channel) { while (dma_hw->abort & (1ul << channel)) tight_loop_contents(); } -/*! \brief Enable single DMA channel interrupt 0 +/*! \brief Enable single DMA channel's interrupt via DMA_IRQ_0 * \ingroup hardware_dma * * \param channel DMA channel @@ -480,7 +494,7 @@ static inline void dma_channel_set_irq0_enabled(uint channel, bool enabled) { hw_clear_bits(&dma_hw->inte0, 1u << channel); } -/*! \brief Enable multiple DMA channels interrupt 0 +/*! \brief Enable multiple DMA channels' interrupts via DMA_IRQ_0 * \ingroup hardware_dma * * \param channel_mask Bitmask of all the channels to enable/disable. Channel 0 = bit 0, channel 1 = bit 1 etc. @@ -494,7 +508,7 @@ static inline void dma_set_irq0_channel_mask_enabled(uint32_t channel_mask, bool } } -/*! \brief Enable single DMA channel interrupt 1 +/*! \brief Enable single DMA channel's interrupt via DMA_IRQ_1 * \ingroup hardware_dma * * \param channel DMA channel @@ -509,7 +523,7 @@ static inline void dma_channel_set_irq1_enabled(uint channel, bool enabled) { hw_clear_bits(&dma_hw->inte1, 1u << channel); } -/*! \brief Enable multiple DMA channels interrupt 0 +/*! \brief Enable multiple DMA channels' interrupts via DMA_IRQ_1 * \ingroup hardware_dma * * \param channel_mask Bitmask of all the channels to enable/disable. Channel 0 = bit 0, channel 1 = bit 1 etc. @@ -523,6 +537,105 @@ static inline void dma_set_irq1_channel_mask_enabled(uint32_t channel_mask, bool } } +/*! \brief Enable single DMA channel interrupt on either DMA_IRQ_0 or DMA_IRQ_1 + * \ingroup hardware_dma + * + * \param irq_index the IRQ index; either 0 or 1 for DMA_IRQ_0 or DMA_IRQ_1 + * \param channel DMA channel + * \param enabled true to enable interrupt via irq_index for specified channel, false to disable. + */ +static inline void dma_irqn_set_channel_enabled(uint irq_index, uint channel, bool enabled) { + invalid_params_if(DMA, irq_index > 1); + if (irq_index) { + dma_channel_set_irq1_enabled(channel, enabled); + } else { + dma_channel_set_irq0_enabled(channel, enabled); + } +} + +/*! \brief Enable multiple DMA channels' interrupt via either DMA_IRQ_0 or DMA_IRQ_1 + * \ingroup hardware_dma + * + * \param irq_index the IRQ index; either 0 or 1 for DMA_IRQ_0 or DMA_IRQ_1 + * \param channel_mask Bitmask of all the channels to enable/disable. Channel 0 = bit 0, channel 1 = bit 1 etc. + * \param enabled true to enable all the interrupts specified in the mask, false to disable all the interrupts specified in the mask. + */ +static inline void dma_irqn_set_channel_mask_enabled(uint irq_index, uint32_t channel_mask, bool enabled) { + invalid_params_if(DMA, irq_index > 1); + if (irq_index) { + dma_set_irq1_channel_mask_enabled(channel_mask, enabled); + } else { + dma_set_irq0_channel_mask_enabled(channel_mask, enabled); + } +} + +/*! \brief Determine if a particular channel is a cause of DMA_IRQ_0 + * \ingroup hardware_dma + * + * \param channel DMA channel + * \return true if the channel is a cause of DMA_IRQ_0, false otherwise + */ +static inline bool dma_channel_get_irq0_status(uint channel) { + check_dma_channel_param(channel); + return dma_hw->ints0 & (1u << channel); +} + +/*! \brief Determine if a particular channel is a cause of DMA_IRQ_1 + * \ingroup hardware_dma + * + * \param channel DMA channel + * \return true if the channel is a cause of DMA_IRQ_1, false otherwise + */ +static inline bool dma_channel_get_irq1_status(uint channel) { + check_dma_channel_param(channel); + return dma_hw->ints1 & (1u << channel); +} + +/*! \brief Determine if a particular channel is a cause of DMA_IRQ_N + * \ingroup hardware_dma + * + * \param irq_index the IRQ index; either 0 or 1 for DMA_IRQ_0 or DMA_IRQ_1 + * \param channel DMA channel + * \return true if the channel is a cause of the DMA_IRQ_N, false otherwise + */ +static inline bool dma_irqn_get_channel_status(uint irq_index, uint channel) { + invalid_params_if(DMA, irq_index > 1); + check_dma_channel_param(channel); + return (irq_index ? dma_hw->ints1 : dma_hw->ints0) & (1u << channel); +} + +/*! \brief Acknowledge a channel IRQ, resetting it as the cause of DMA_IRQ_0 + * \ingroup hardware_dma + * + * \param channel DMA channel + */ +static inline void dma_channel_acknowledge_irq0(uint channel) { + check_dma_channel_param(channel); + hw_set_bits(&dma_hw->ints0, (1u << channel)); +} + +/*! \brief Acknowledge a channel IRQ, resetting it as the cause of DMA_IRQ_1 + * \ingroup hardware_dma + * + * \param channel DMA channel + */ +static inline void dma_channel_acknowledge_irq1(uint channel) { + check_dma_channel_param(channel); + hw_set_bits(&dma_hw->ints1, (1u << channel)); +} + +/*! \brief Acknowledge a channel IRQ, resetting it as the cause of DMA_IRQ_N + * \ingroup hardware_dma + * + * \param irq_index the IRQ index; either 0 or 1 for DMA_IRQ_0 or DMA_IRQ_1 + * \param channel DMA channel + */ +static inline void dma_irqn_acknowledge_channel(uint irq_index, uint channel) { + invalid_params_if(DMA, irq_index > 1); + check_dma_channel_param(channel); + hw_set_bits(irq_index ? &dma_hw->ints1 : &dma_hw->ints0, (1u << channel)); +} + /*! \brief Check if DMA channel is busy * \ingroup hardware_dma * diff --git a/src/rp2_common/hardware_interp/include/hardware/interp.h b/src/rp2_common/hardware_interp/include/hardware/interp.h index 74dd309..35372e9 100644 --- a/src/rp2_common/hardware_interp/include/hardware/interp.h +++ b/src/rp2_common/hardware_interp/include/hardware/interp.h @@ -55,7 +55,7 @@ typedef struct { } interp_config; static inline uint interp_index(interp_hw_t *interp) { - assert(interp == interp0 || interp == interp1); + valid_params_if(INTERP, interp == interp0 || interp == interp1); return interp == interp1 ? 1 : 0; } @@ -70,6 +70,8 @@ static inline uint interp_index(interp_hw_t *interp) { * \param lane The lane number, 0 or 1. */ void interp_claim_lane(interp_hw_t *interp, uint lane); +// The above really should be called this for consistency +#define interp_lane_claim interp_claim_lane /*! \brief Claim the interpolator lanes specified in the mask * \ingroup hardware_interp @@ -86,6 +88,19 @@ void interp_claim_lane_mask(interp_hw_t *interp, uint lane_mask); * \param lane The lane number, 0 or 1 */ void interp_unclaim_lane(interp_hw_t *interp, uint lane); +// The above really should be called this for consistency +#define interp_lane_unclaim interp_unclaim_lane + +/*! \brief Determine if an interpolator lane is claimed + * \ingroup hardware_interp + * + * \param interp Interpolator whose lane to check + * \param lane The lane number, 0 or 1 + * \return true if claimed, false otherwise + * \see interp_claim_lane + * \see interp_claim_lane_mask + */ +bool interp_lane_is_claimed(interp_hw_t *interp, uint lane); /*! \brief Release previously claimed interpolator lanes \see interp_claim_lane_mask * \ingroup hardware_interp diff --git a/src/rp2_common/hardware_interp/interp.c b/src/rp2_common/hardware_interp/interp.c index a5774b7..37e8a91 100644 --- a/src/rp2_common/hardware_interp/interp.c +++ b/src/rp2_common/hardware_interp/interp.c @@ -16,14 +16,13 @@ static_assert(NUM_DMA_CHANNELS <= 16, ""); static uint8_t _claimed; -static inline uint interp_get_bit(interp_hw_t *interp, uint lane) { - return 1u << ((interp_index(interp) << 1u) | lane); +static inline uint interp_lane_bit(interp_hw_t * interp, uint lane) { + return (interp_index(interp) << 1u) | lane; } void interp_claim_lane(interp_hw_t *interp, uint lane) { valid_params_if(INTERP, lane < 2); - uint bit = interp_get_bit(interp, lane); - hw_claim_or_assert((uint8_t *) &_claimed, bit, "Lane is already claimed"); + hw_claim_or_assert((uint8_t *) &_claimed, interp_lane_bit(interp, lane), "Lane is already claimed"); } void interp_claim_lane_mask(interp_hw_t *interp, uint lane_mask) { @@ -34,12 +33,16 @@ void interp_claim_lane_mask(interp_hw_t *interp, uint lane_mask) { void interp_unclaim_lane(interp_hw_t *interp, uint lane) { valid_params_if(INTERP, lane < 2); - uint bit = interp_get_bit(interp, lane); - hw_claim_clear(&_claimed, bit); + hw_claim_clear((uint8_t *) &_claimed, interp_lane_bit(interp, lane)); +} + +bool interp_lane_is_claimed(interp_hw_t *interp, uint lane) { + valid_params_if(INTERP, lane < 2); + return hw_is_claimed((uint8_t *) &_claimed, interp_lane_bit(interp, lane)); } void interp_unclaim_lane_mask(interp_hw_t *interp, uint lane_mask) { - valid_params_if(INTERP, lane_mask && lane_mask <= 0x3); + valid_params_if(INTERP, lane_mask <= 0x3); if (lane_mask & 1u) interp_unclaim_lane(interp, 0); if (lane_mask & 2u) interp_unclaim_lane(interp, 1); } diff --git a/src/rp2_common/hardware_pio/include/hardware/pio.h b/src/rp2_common/hardware_pio/include/hardware/pio.h index 3525d11..07d0669 100644 --- a/src/rp2_common/hardware_pio/include/hardware/pio.h +++ b/src/rp2_common/hardware_pio/include/hardware/pio.h @@ -111,6 +111,11 @@ static inline void check_sm_param(__unused uint sm) { valid_params_if(PIO, sm < NUM_PIO_STATE_MACHINES); } +static inline void check_sm_mask(__unused uint mask) { + valid_params_if(PIO, mask < (1u << NUM_PIO_STATE_MACHINES)); +} + + static inline void check_pio_param(__unused PIO pio) { valid_params_if(PIO, pio == pio0 || pio == pio1); } @@ -554,6 +559,7 @@ static inline void pio_sm_set_enabled(PIO pio, uint sm, bool enabled) { */ 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); } @@ -583,6 +589,7 @@ static inline void pio_sm_restart(PIO pio, uint sm) { */ static inline void pio_restart_sm_mask(PIO pio, uint32_t mask) { check_pio_param(pio); + check_sm_mask(mask); pio->ctrl |= (mask << PIO_CTRL_SM_RESTART_LSB) & PIO_CTRL_SM_RESTART_BITS; } @@ -644,6 +651,7 @@ static inline void pio_sm_clkdiv_restart(PIO pio, uint sm) { */ static inline void pio_clkdiv_restart_sm_mask(PIO pio, uint32_t mask) { check_pio_param(pio); + check_sm_mask(mask); pio->ctrl |= (mask << PIO_CTRL_CLKDIV_RESTART_LSB) & PIO_CTRL_CLKDIV_RESTART_BITS; } @@ -660,10 +668,154 @@ static inline void pio_clkdiv_restart_sm_mask(PIO pio, uint32_t mask) { */ static inline void pio_enable_sm_mask_in_sync(PIO pio, uint32_t mask) { check_pio_param(pio); + check_sm_mask(mask); pio->ctrl |= ((mask << PIO_CTRL_CLKDIV_RESTART_LSB) & PIO_CTRL_CLKDIV_RESTART_BITS) | ((mask << PIO_CTRL_SM_ENABLE_LSB) & PIO_CTRL_SM_ENABLE_BITS); } +/*! \brief PIO interrupt source numbers for pio related IRQs + * \ingroup hardware_pio + */ +enum pio_interrupt_source { + pis_interrupt0 = PIO_INTR_SM0_LSB, + pis_interrupt1 = PIO_INTR_SM1_LSB, + pis_interrupt2 = PIO_INTR_SM2_LSB, + pis_interrupt3 = PIO_INTR_SM3_LSB, + pis_sm0_tx_fifo_not_full = PIO_INTR_SM0_TXNFULL_LSB, + pis_sm1_tx_fifo_not_full = PIO_INTR_SM1_TXNFULL_LSB, + pis_sm2_tx_fifo_not_full = PIO_INTR_SM2_TXNFULL_LSB, + pis_sm3_tx_fifo_not_full = PIO_INTR_SM3_TXNFULL_LSB, + pis_sm0_rx_fifo_not_empty = PIO_INTR_SM0_RXNEMPTY_LSB, + pis_sm1_rx_fifo_not_empty = PIO_INTR_SM1_RXNEMPTY_LSB, + pis_sm2_rx_fifo_not_empty = PIO_INTR_SM2_RXNEMPTY_LSB, + pis_sm3_rx_fifo_not_empty = PIO_INTR_SM3_RXNEMPTY_LSB, +}; + +/*! \brief Enable/Disable a single source on a PIO's IRQ 0 + * \ingroup hardware_pio + * + * \param pio The PIO instance; either \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, enum pio_interrupt_source source, bool enabled) { + check_pio_param(pio); + invalid_params_if(PIO, source >= 12); + 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; either \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, enum pio_interrupt_source source, bool enabled) { + check_pio_param(pio); + invalid_params_if(PIO, source >= 12); + 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; either \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(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; either \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(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; either \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, enum pio_interrupt_source source, bool enabled) { + invalid_params_if(PIO, irq_index > 1); + if (irq_index) { + pio_set_irq1_source_enabled(pio, source, enabled); + } else { + pio_set_irq0_source_enabled(pio, source, enabled); + } +} + +/*! \brief Enable/Disable multiple sources on a PIO's specified (0/1) IRQ index + * \ingroup hardware_pio + * + * \param pio The PIO instance; either \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(PIO, irq_index > 1); + if (irq_index) { + pio_set_irq0_source_mask_enabled(pio, source_mask, enabled); + } else { + pio_set_irq1_source_mask_enabled(pio, source_mask, enabled); + } +} + +/*! \brief Determine if a particular PIO interrupt is set + * \ingroup hardware_pio + * + * \param pio The PIO instance; either \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(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; either \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(PIO, pio_interrupt_num >= 8); + hw_set_bits(&pio->irq, (1u << pio_interrupt_num)); +} + /*! \brief Return the current program counter for a state machine * \ingroup hardware_pio * @@ -1136,6 +1288,17 @@ void pio_sm_unclaim(PIO pio, uint sm); */ 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; either \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); + #ifdef __cplusplus } #endif diff --git a/src/rp2_common/hardware_pio/pio.c b/src/rp2_common/hardware_pio/pio.c index 906f587..0744110 100644 --- a/src/rp2_common/hardware_pio/pio.c +++ b/src/rp2_common/hardware_pio/pio.c @@ -35,6 +35,7 @@ void pio_claim_sm_mask(PIO pio, uint sm_mask) { if (sm_mask & 1u) pio_sm_claim(pio, i); } } + void pio_sm_unclaim(PIO pio, uint sm) { check_sm_param(sm); uint which = pio_get_index(pio); @@ -50,6 +51,12 @@ int pio_claim_unused_sm(PIO pio, bool required) { return index >= (int)base ? index - (int)base : -1; } +bool pio_sm_is_claimed(PIO pio, uint sm) { + check_sm_param(sm); + uint which = pio_get_index(pio); + return hw_is_claimed(&claimed, which * NUM_PIO_STATE_MACHINES + sm); +} + static_assert(PIO_INSTRUCTION_COUNT <= 32, ""); static uint32_t _used_instruction_space[2]; diff --git a/src/rp2_common/hardware_sync/include/hardware/sync.h b/src/rp2_common/hardware_sync/include/hardware/sync.h index 6867cf7..8f91d55 100644 --- a/src/rp2_common/hardware_sync/include/hardware/sync.h +++ b/src/rp2_common/hardware_sync/include/hardware/sync.h @@ -384,6 +384,16 @@ void spin_lock_unclaim(uint lock_num); */ int spin_lock_claim_unused(bool required); +/*! \brief Determine if a spin lock is claimed + * \ingroup hardware_sync + * + * \param lock_num the spin lock number + * \return true if claimed, false otherwise + * \see spin_lock_claim + * \see spin_lock_claim_mask + */ +bool spin_lock_is_claimed(uint lock_num); + #define remove_volatile_cast(t, x) ({__mem_fence_acquire(); (t)(x); }) #ifdef __cplusplus diff --git a/src/rp2_common/hardware_sync/sync.c b/src/rp2_common/hardware_sync/sync.c index 228c52e..a15c8d6 100644 --- a/src/rp2_common/hardware_sync/sync.c +++ b/src/rp2_common/hardware_sync/sync.c @@ -57,3 +57,8 @@ int spin_lock_claim_unused(bool required) { return hw_claim_unused_from_range((uint8_t*)&claimed, required, PICO_SPINLOCK_ID_CLAIM_FREE_FIRST, PICO_SPINLOCK_ID_CLAIM_FREE_LAST, "No spinlocks are available"); } +bool spin_lock_is_claimed(uint lock_num) { + check_lock_num(lock_num); + return hw_is_claimed((uint8_t *) &claimed, lock_num); +} + diff --git a/src/rp2_common/hardware_timer/include/hardware/timer.h b/src/rp2_common/hardware_timer/include/hardware/timer.h index ff1f7c1..1799cd0 100644 --- a/src/rp2_common/hardware_timer/include/hardware/timer.h +++ b/src/rp2_common/hardware_timer/include/hardware/timer.h @@ -144,6 +144,15 @@ void hardware_alarm_claim(uint alarm_num); */ void hardware_alarm_unclaim(uint alarm_num); +/*! \brief Determine if a hardware alarm has been claimed + * \ingroup hardware_timer + * + * \param alarm_num the hardware alarm number + * \return true if claimed, false otherwise + * \see hardware_alarm_claim + */ +bool hardware_alarm_is_claimed(uint alarm_num); + /*! \brief Enable/Disable a callback for a hardware timer on this core * \ingroup hardware_timer * diff --git a/src/rp2_common/hardware_timer/timer.c b/src/rp2_common/hardware_timer/timer.c index 79d040f..f13d249 100644 --- a/src/rp2_common/hardware_timer/timer.c +++ b/src/rp2_common/hardware_timer/timer.c @@ -28,6 +28,11 @@ void hardware_alarm_unclaim(uint alarm_num) { hw_claim_clear(&claimed, alarm_num); } +bool hardware_alarm_is_claimed(uint alarm_num) { + check_hardware_alarm_num_param(alarm_num); + return hw_is_claimed(&claimed, alarm_num); +} + /// tag::time_us_64[] uint64_t time_us_64() { // Need to make sure that the upper 32 bits of the timer diff --git a/src/rp2_common/pico_float/float_none.S b/src/rp2_common/pico_float/float_none.S index 743a75e..55baf29 100644 --- a/src/rp2_common/pico_float/float_none.S +++ b/src/rp2_common/pico_float/float_none.S @@ -34,6 +34,7 @@ wrapper_func __aeabi_f2iz wrapper_func __aeabi_f2lz wrapper_func __aeabi_f2uiz wrapper_func __aeabi_f2ulz +wrapper_func __aeabi_f2d wrapper_func sqrtf wrapper_func cosf wrapper_func sinf diff --git a/src/rp2_common/pico_int64_ops/pico_int64_ops_aeabi.S b/src/rp2_common/pico_int64_ops/pico_int64_ops_aeabi.S index 903820b..0dbc67c 100644 --- a/src/rp2_common/pico_int64_ops/pico_int64_ops_aeabi.S +++ b/src/rp2_common/pico_int64_ops/pico_int64_ops_aeabi.S @@ -10,7 +10,11 @@ #include "pico/asm_helper.S" +#if PICO_INT64_OPS_IN_RAM +.section RAM_SECTION_NAME(__aeabi_lmul) +#else .section SECTION_NAME(__aeabi_lmul) +#endif wrapper_func __aeabi_lmul muls r1, r2 muls r3, r0 diff --git a/src/rp2_common/pico_multicore/CMakeLists.txt b/src/rp2_common/pico_multicore/CMakeLists.txt index 971d345..2401061 100644 --- a/src/rp2_common/pico_multicore/CMakeLists.txt +++ b/src/rp2_common/pico_multicore/CMakeLists.txt @@ -6,7 +6,7 @@ if (NOT TARGET pico_multicore) target_include_directories(pico_multicore INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include) - target_link_libraries(pico_multicore INTERFACE pico_sync) + target_link_libraries(pico_multicore INTERFACE pico_sync hardware_irq) endif() diff --git a/src/rp2_common/pico_multicore/multicore.c b/src/rp2_common/pico_multicore/multicore.c index a7ef5ea..531e294 100644 --- a/src/rp2_common/pico_multicore/multicore.c +++ b/src/rp2_common/pico_multicore/multicore.c @@ -4,7 +4,6 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include "pico/stdlib.h" #include "pico/multicore.h" #include "hardware/sync.h" #include "hardware/irq.h"