From e76d5a9008e854d609c5d92f05c1f587cd5779c4 Mon Sep 17 00:00:00 2001 From: Graham Sanderson Date: Tue, 12 Oct 2021 09:04:59 -0500 Subject: [PATCH] add dma_timer related methods (#604) --- .../include/hardware/platform_defs.h | 1 + src/rp2_common/hardware_dma/dma.c | 20 ++++++ .../hardware_dma/include/hardware/dma.h | 69 +++++++++++++++++++ 3 files changed, 90 insertions(+) diff --git a/src/rp2040/hardware_regs/include/hardware/platform_defs.h b/src/rp2040/hardware_regs/include/hardware/platform_defs.h index 437594c..01f9362 100644 --- a/src/rp2040/hardware_regs/include/hardware/platform_defs.h +++ b/src/rp2040/hardware_regs/include/hardware/platform_defs.h @@ -19,6 +19,7 @@ #define NUM_CORES _u(2) #define NUM_DMA_CHANNELS _u(12) +#define NUM_DMA_TIMERS _u(4) #define NUM_IRQS _u(32) #define NUM_PIOS _u(2) #define NUM_PIO_STATE_MACHINES _u(4) diff --git a/src/rp2_common/hardware_dma/dma.c b/src/rp2_common/hardware_dma/dma.c index 230fa16..90fde06 100644 --- a/src/rp2_common/hardware_dma/dma.c +++ b/src/rp2_common/hardware_dma/dma.c @@ -18,6 +18,7 @@ static_assert(__builtin_offsetof(dma_hw_t, ch[1].ctrl_trig) == DMA_CH1_CTRL_TRIG static_assert(NUM_DMA_CHANNELS <= 16, ""); static uint16_t _claimed; +static uint8_t _timer_claimed; void dma_channel_claim(uint channel) { check_dma_channel_param(channel); @@ -44,6 +45,25 @@ bool dma_channel_is_claimed(uint channel) { return hw_is_claimed((uint8_t *) &_claimed, channel); } +void dma_timer_claim(uint timer) { + check_dma_timer_param(timer); + hw_claim_or_assert(&_timer_claimed, timer, "DMA timer %d is already claimed"); +} + +void dma_timer_unclaim(uint timer) { + check_dma_timer_param(timer); + hw_claim_clear(&_timer_claimed, timer); +} + +int dma_claim_unused_timer(bool required) { + return hw_claim_unused_from_range(&_timer_claimed, required, 0, NUM_DMA_TIMERS-1, "No DMA timers are available"); +} + +bool dma_timer_is_claimed(uint timer) { + check_dma_timer_param(timer); + return hw_is_claimed(&_timer_claimed, timer); +} + #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 526d632..3d24654 100644 --- a/src/rp2_common/hardware_dma/include/hardware/dma.h +++ b/src/rp2_common/hardware_dma/include/hardware/dma.h @@ -54,6 +54,10 @@ static inline void check_dma_channel_param(__unused uint channel) { #endif } +static inline void check_dma_timer_param(__unused uint timer_num) { + valid_params_if(DMA, timer_num < NUM_DMA_TIMERS); +} + inline static dma_channel_hw_t *dma_channel_hw_addr(uint channel) { check_dma_channel_param(channel); return &dma_hw->ch[channel]; @@ -715,6 +719,71 @@ inline static void dma_sniffer_disable(void) { dma_hw->sniff_ctrl = 0; } +/*! \brief Mark a dma timer as used + * \ingroup hardware_dma + * + * Method for cooperative claiming of hardware. Will cause a panic if the timer + * is already claimed. Use of this method by libraries detects accidental + * configurations that would fail in unpredictable ways. + * + * \param timer the dma timer + */ +void dma_timer_claim(uint timer); + +/*! \brief Mark a dma timer as no longer used + * \ingroup hardware_dma + * + * Method for cooperative claiming of hardware. + * + * \param timer the dma timer to release + */ +void dma_timer_unclaim(uint timer); + +/*! \brief Claim a free dma timer + * \ingroup hardware_dma + * + * \param required if true the function will panic if none are available + * \return the dma timer number or -1 if required was false, and none were free + */ +int dma_claim_unused_timer(bool required); + +/*! \brief Determine if a dma timer is claimed + * \ingroup hardware_dma + * + * \param timer the dma timer + * \return true if the timer is claimed, false otherwise + * \see dma_timer_claim + */ +bool dma_timer_is_claimed(uint timer); + +/*! \brief Set the divider for the given DMA timer + * \ingroup hardware_dma + * + * The timer will run at the system_clock_freq * numerator / denominator, so this is the speed + * that data elements will be transferred at via a DMA channel using this timer as a DREQ + * + * \param timer the dma timer + * \param numerator the fraction's numerator + * \param denominator the fraction's denominator + */ +static inline void dma_timer_set_fraction(uint timer, uint16_t numerator, uint16_t denominator) { + check_dma_timer_param(timer); + dma_hw->timer[timer] = (((uint32_t)numerator) << DMA_TIMER0_X_LSB) | (((uint32_t)denominator) << DMA_TIMER0_Y_LSB); +} + +/*! \brief Return the DREQ number for a given DMA timer + * \ingroup hardware_dma + * + * \param timer DMA timer number 0-3 + */ +static inline uint dma_get_timer_dreq(uint timer_num) { + static_assert(DREQ_DMA_TIMER1 == DREQ_DMA_TIMER0 + 1, ""); + static_assert(DREQ_DMA_TIMER2 == DREQ_DMA_TIMER0 + 2, ""); + static_assert(DREQ_DMA_TIMER3 == DREQ_DMA_TIMER0 + 3, ""); + check_dma_timer_param(timer_num); + return DREQ_DMA_TIMER0 + timer_num; +} + #ifndef NDEBUG void print_dma_ctrl(dma_channel_hw_t *channel); #endif