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
This commit is contained in:
Graham Sanderson 2021-06-02 13:12:27 -05:00 committed by GitHub
parent 91e9327ff1
commit 5afa3636d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 368 additions and 36 deletions

View File

@ -12,7 +12,7 @@ if (NOT PICO_GCC_TRIPLE)
message("PICO_GCC_TRIPLE set from environment: $ENV{PICO_GCC_TRIPLE}") message("PICO_GCC_TRIPLE set from environment: $ENV{PICO_GCC_TRIPLE}")
else() else()
set(PICO_GCC_TRIPLE arm-none-eabi) 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()
endif() endif()

View File

@ -283,7 +283,7 @@ static void alarm_pool_dump_key(pheap_node_id_t id, void *user_data) {
#endif #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; repeating_timer_t *rt = (repeating_timer_t *)user_data;
assert(rt->alarm_id == id); assert(rt->alarm_id == id);
if (rt->callback(rt)) { if (rt->callback(rt)) {

View File

@ -50,7 +50,7 @@ set(PICO_CMSIS_VENDOR RaspberryPi)
set(PICO_CMSIS_DEVICE RP2040) set(PICO_CMSIS_DEVICE RP2040)
if (PICO_CMSIS_CORE_PATH) if (PICO_CMSIS_CORE_PATH)
add_library(cmsis_core INTERFACE) pico_add_impl_library(cmsis_core)
target_sources(cmsis_core INTERFACE target_sources(cmsis_core INTERFACE
${PICO_CMSIS_CORE_PATH}/CMSIS/Device/${PICO_CMSIS_VENDOR}/${PICO_CMSIS_DEVICE}/Source/system_${PICO_CMSIS_DEVICE}.c ${PICO_CMSIS_CORE_PATH}/CMSIS/Device/${PICO_CMSIS_VENDOR}/${PICO_CMSIS_DEVICE}/Source/system_${PICO_CMSIS_DEVICE}.c
) )

View File

@ -7,6 +7,7 @@
#ifndef _CMSIS_RENAME_EXCEPTIONS_H #ifndef _CMSIS_RENAME_EXCEPTIONS_H
#define _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 // 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 // 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 #define isr_irq25 RTC_IRQ_Handler
#endif #endif
#endif
#endif /* _CMSIS_RENAME_EXCEPTIONS_H */ #endif /* _CMSIS_RENAME_EXCEPTIONS_H */

View File

@ -14,22 +14,13 @@ void hw_claim_unlock(uint32_t save) {
spin_unlock(spin_lock_instance(PICO_SPINLOCK_ID_HARDWARE_CLAIM), save); spin_unlock(spin_lock_instance(PICO_SPINLOCK_ID_HARDWARE_CLAIM), save);
} }
bool hw_is_claimed(uint8_t *bits, uint bit_index) { inline bool hw_is_claimed(const uint8_t *bits, uint bit_index) {
bool rc; return (bits[bit_index >> 3u] & (1u << (bit_index & 7u)));
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;
} }
void hw_claim_or_assert(uint8_t *bits, uint bit_index, const char *message) { void hw_claim_or_assert(uint8_t *bits, uint bit_index, const char *message) {
uint32_t save = hw_claim_lock(); 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); panic(message, bit_index);
} else { } else {
bits[bit_index >> 3u] |= (uint8_t)(1u << (bit_index & 7u)); 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(); uint32_t save = hw_claim_lock();
int found_bit = -1; int found_bit = -1;
for(uint bit=bit_lsb; bit <= bit_msb; bit++) { 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)); bits[bit >> 3u] |= (uint8_t)(1u << (bit & 7u));
found_bit = (int)bit; found_bit = (int)bit;
break; 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) { void hw_claim_clear(uint8_t *bits, uint bit_index) {
uint32_t save = hw_claim_lock(); 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)); bits[bit_index >> 3u] &= (uint8_t) ~(1u << (bit_index & 7u));
hw_claim_unlock(save); hw_claim_unlock(save);
} }

View File

@ -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. * 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 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 * \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 /*! \brief Atomically unclaim a resource
* \ingroup hardware_claim * \ingroup hardware_claim

View File

@ -112,7 +112,7 @@ bool clock_configure(enum clock_index clk_index, uint32_t src, uint32_t auxsrc,
clock->div = div; clock->div = div;
// Store the configured frequency // Store the configured frequency
configured_freq[clk_index] = freq; configured_freq[clk_index] = (uint32_t)(((uint64_t) src_freq << 8) / div);
return true; return true;
} }

View File

@ -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"); 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 #ifndef NDEBUG
void print_dma_ctrl(dma_channel_hw_t *channel) { void print_dma_ctrl(dma_channel_hw_t *channel) {

View File

@ -34,8 +34,12 @@ extern "C" {
* * Memory to memory * * Memory to memory
*/ */
// this is not defined in generated dreq.h // these are not defined in generated dreq.h
#define DREQ_FORCE 63 #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 // PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_DMA, Enable/disable DMA assertions, type=bool, default=0, group=hardware_dma
#ifndef PARAM_ASSERTIONS_ENABLED_DMA #ifndef PARAM_ASSERTIONS_ENABLED_DMA
@ -94,6 +98,16 @@ void dma_channel_unclaim(uint channel);
*/ */
int dma_claim_unused_channel(bool required); 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 /** \brief DMA channel configuration
* \defgroup channel_config channel_config * \defgroup channel_config channel_config
* \ingroup hardware_dma * \ingroup hardware_dma
@ -465,7 +479,7 @@ static inline void dma_channel_abort(uint channel) {
while (dma_hw->abort & (1ul << channel)) tight_loop_contents(); 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 * \ingroup hardware_dma
* *
* \param channel DMA channel * \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); 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 * \ingroup hardware_dma
* *
* \param channel_mask Bitmask of all the channels to enable/disable. Channel 0 = bit 0, channel 1 = bit 1 etc. * \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 * \ingroup hardware_dma
* *
* \param channel DMA channel * \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); 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 * \ingroup hardware_dma
* *
* \param channel_mask Bitmask of all the channels to enable/disable. Channel 0 = bit 0, channel 1 = bit 1 etc. * \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 /*! \brief Check if DMA channel is busy
* \ingroup hardware_dma * \ingroup hardware_dma
* *

View File

@ -55,7 +55,7 @@ typedef struct {
} interp_config; } interp_config;
static inline uint interp_index(interp_hw_t *interp) { 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; 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. * \param lane The lane number, 0 or 1.
*/ */
void interp_claim_lane(interp_hw_t *interp, uint lane); 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 /*! \brief Claim the interpolator lanes specified in the mask
* \ingroup hardware_interp * \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 * \param lane The lane number, 0 or 1
*/ */
void interp_unclaim_lane(interp_hw_t *interp, uint lane); 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 /*! \brief Release previously claimed interpolator lanes \see interp_claim_lane_mask
* \ingroup hardware_interp * \ingroup hardware_interp

View File

@ -16,14 +16,13 @@ static_assert(NUM_DMA_CHANNELS <= 16, "");
static uint8_t _claimed; static uint8_t _claimed;
static inline uint interp_get_bit(interp_hw_t *interp, uint lane) { static inline uint interp_lane_bit(interp_hw_t * interp, uint lane) {
return 1u << ((interp_index(interp) << 1u) | lane); return (interp_index(interp) << 1u) | lane;
} }
void interp_claim_lane(interp_hw_t *interp, uint lane) { void interp_claim_lane(interp_hw_t *interp, uint lane) {
valid_params_if(INTERP, lane < 2); valid_params_if(INTERP, lane < 2);
uint bit = interp_get_bit(interp, lane); hw_claim_or_assert((uint8_t *) &_claimed, interp_lane_bit(interp, lane), "Lane is already claimed");
hw_claim_or_assert((uint8_t *) &_claimed, bit, "Lane is already claimed");
} }
void interp_claim_lane_mask(interp_hw_t *interp, uint lane_mask) { 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) { void interp_unclaim_lane(interp_hw_t *interp, uint lane) {
valid_params_if(INTERP, lane < 2); valid_params_if(INTERP, lane < 2);
uint bit = interp_get_bit(interp, lane); hw_claim_clear((uint8_t *) &_claimed, interp_lane_bit(interp, lane));
hw_claim_clear(&_claimed, bit); }
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) { 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 & 1u) interp_unclaim_lane(interp, 0);
if (lane_mask & 2u) interp_unclaim_lane(interp, 1); if (lane_mask & 2u) interp_unclaim_lane(interp, 1);
} }

View File

@ -111,6 +111,11 @@ static inline void check_sm_param(__unused uint sm) {
valid_params_if(PIO, sm < NUM_PIO_STATE_MACHINES); 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) { static inline void check_pio_param(__unused PIO pio) {
valid_params_if(PIO, pio == pio0 || pio == pio1); 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) { static inline void pio_set_sm_mask_enabled(PIO pio, uint32_t mask, bool enabled) {
check_pio_param(pio); check_pio_param(pio);
check_sm_mask(mask);
pio->ctrl = (pio->ctrl & ~mask) | (enabled ? mask : 0u); 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) { static inline void pio_restart_sm_mask(PIO pio, uint32_t mask) {
check_pio_param(pio); check_pio_param(pio);
check_sm_mask(mask);
pio->ctrl |= (mask << PIO_CTRL_SM_RESTART_LSB) & PIO_CTRL_SM_RESTART_BITS; 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) { static inline void pio_clkdiv_restart_sm_mask(PIO pio, uint32_t mask) {
check_pio_param(pio); check_pio_param(pio);
check_sm_mask(mask);
pio->ctrl |= (mask << PIO_CTRL_CLKDIV_RESTART_LSB) & PIO_CTRL_CLKDIV_RESTART_BITS; 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) { static inline void pio_enable_sm_mask_in_sync(PIO pio, uint32_t mask) {
check_pio_param(pio); check_pio_param(pio);
check_sm_mask(mask);
pio->ctrl |= ((mask << PIO_CTRL_CLKDIV_RESTART_LSB) & PIO_CTRL_CLKDIV_RESTART_BITS) | pio->ctrl |= ((mask << PIO_CTRL_CLKDIV_RESTART_LSB) & PIO_CTRL_CLKDIV_RESTART_BITS) |
((mask << PIO_CTRL_SM_ENABLE_LSB) & PIO_CTRL_SM_ENABLE_BITS); ((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 /*! \brief Return the current program counter for a state machine
* \ingroup hardware_pio * \ingroup hardware_pio
* *
@ -1136,6 +1288,17 @@ void pio_sm_unclaim(PIO pio, uint sm);
*/ */
int pio_claim_unused_sm(PIO pio, bool required); 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 #ifdef __cplusplus
} }
#endif #endif

View File

@ -35,6 +35,7 @@ void pio_claim_sm_mask(PIO pio, uint sm_mask) {
if (sm_mask & 1u) pio_sm_claim(pio, i); if (sm_mask & 1u) pio_sm_claim(pio, i);
} }
} }
void pio_sm_unclaim(PIO pio, uint sm) { void pio_sm_unclaim(PIO pio, uint sm) {
check_sm_param(sm); check_sm_param(sm);
uint which = pio_get_index(pio); 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; 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_assert(PIO_INSTRUCTION_COUNT <= 32, "");
static uint32_t _used_instruction_space[2]; static uint32_t _used_instruction_space[2];

View File

@ -384,6 +384,16 @@ void spin_lock_unclaim(uint lock_num);
*/ */
int spin_lock_claim_unused(bool required); 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); }) #define remove_volatile_cast(t, x) ({__mem_fence_acquire(); (t)(x); })
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -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"); 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);
}

View File

@ -144,6 +144,15 @@ void hardware_alarm_claim(uint alarm_num);
*/ */
void hardware_alarm_unclaim(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 /*! \brief Enable/Disable a callback for a hardware timer on this core
* \ingroup hardware_timer * \ingroup hardware_timer
* *

View File

@ -28,6 +28,11 @@ void hardware_alarm_unclaim(uint alarm_num) {
hw_claim_clear(&claimed, 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[] /// tag::time_us_64[]
uint64_t time_us_64() { uint64_t time_us_64() {
// Need to make sure that the upper 32 bits of the timer // Need to make sure that the upper 32 bits of the timer

View File

@ -34,6 +34,7 @@ wrapper_func __aeabi_f2iz
wrapper_func __aeabi_f2lz wrapper_func __aeabi_f2lz
wrapper_func __aeabi_f2uiz wrapper_func __aeabi_f2uiz
wrapper_func __aeabi_f2ulz wrapper_func __aeabi_f2ulz
wrapper_func __aeabi_f2d
wrapper_func sqrtf wrapper_func sqrtf
wrapper_func cosf wrapper_func cosf
wrapper_func sinf wrapper_func sinf

View File

@ -10,7 +10,11 @@
#include "pico/asm_helper.S" #include "pico/asm_helper.S"
#if PICO_INT64_OPS_IN_RAM
.section RAM_SECTION_NAME(__aeabi_lmul)
#else
.section SECTION_NAME(__aeabi_lmul) .section SECTION_NAME(__aeabi_lmul)
#endif
wrapper_func __aeabi_lmul wrapper_func __aeabi_lmul
muls r1, r2 muls r1, r2
muls r3, r0 muls r3, r0

View File

@ -6,7 +6,7 @@ if (NOT TARGET pico_multicore)
target_include_directories(pico_multicore INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include) 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() endif()

View File

@ -4,7 +4,6 @@
* SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: BSD-3-Clause
*/ */
#include "pico/stdlib.h"
#include "pico/multicore.h" #include "pico/multicore.h"
#include "hardware/sync.h" #include "hardware/sync.h"
#include "hardware/irq.h" #include "hardware/irq.h"