From 85e7ad5ef1bcac5ce79f59477f85337ddde082f4 Mon Sep 17 00:00:00 2001 From: Steins7 Date: Sat, 6 Apr 2024 17:26:56 +0200 Subject: [PATCH] Document DMA driver --- drv/dma.c | 66 ++++++++++++++++++++++++++---------------------- drv/dma.h | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 107 insertions(+), 34 deletions(-) diff --git a/drv/dma.c b/drv/dma.c index 7fd4085..7d68b09 100644 --- a/drv/dma.c +++ b/drv/dma.c @@ -95,21 +95,6 @@ void dma_reset(enum DmaPeriph dma, enum DmaChannel channel) regs->CPAR = 0; } -void dma_exit_critical(enum DmaPeriph dma, enum DmaChannel channel) -{ - switch (dma) { - case DMA_PERIPH_1: - nvic_enable(NVIC_IRQ_DMA1_CHANNEL1 + channel); - break; - case DMA_PERIPH_2: - nvic_enable(NVIC_IRQ_DMA2_CHANNEL1 + channel); - break; - default: - return; - break; - } -} - void dma_start(enum DmaPeriph dma, enum DmaChannel channel, volatile void* mem, uint16_t size) { @@ -132,21 +117,6 @@ void dma_start(enum DmaPeriph dma, enum DmaChannel channel, } } -void dma_enter_critical(enum DmaPeriph dma, enum DmaChannel channel) -{ - switch (dma) { - case DMA_PERIPH_1: - nvic_disable(NVIC_IRQ_DMA1_CHANNEL1 + channel); - break; - case DMA_PERIPH_2: - nvic_disable(NVIC_IRQ_DMA2_CHANNEL1 + channel); - break; - default: - return; - break; - } -} - void dma_stop(enum DmaPeriph dma, enum DmaChannel channel) { switch (dma) { @@ -168,6 +138,36 @@ void dma_stop(enum DmaPeriph dma, enum DmaChannel channel) } } +void dma_enter_critical(enum DmaPeriph dma, enum DmaChannel channel) +{ + switch (dma) { + case DMA_PERIPH_1: + nvic_disable(NVIC_IRQ_DMA1_CHANNEL1 + channel); + break; + case DMA_PERIPH_2: + nvic_disable(NVIC_IRQ_DMA2_CHANNEL1 + channel); + break; + default: + return; + break; + } +} + +void dma_exit_critical(enum DmaPeriph dma, enum DmaChannel channel) +{ + switch (dma) { + case DMA_PERIPH_1: + nvic_enable(NVIC_IRQ_DMA1_CHANNEL1 + channel); + break; + case DMA_PERIPH_2: + nvic_enable(NVIC_IRQ_DMA2_CHANNEL1 + channel); + break; + default: + return; + break; + } +} + uint16_t dma_get_remaining(enum DmaPeriph dma, enum DmaChannel channel) { switch (dma) { @@ -185,6 +185,9 @@ uint16_t dma_get_remaining(enum DmaPeriph dma, enum DmaChannel channel) //--local functions------------------------------------------------------------- +/** + * Applies the given configuration mask to the given DMA channel + */ static void configure_dma(volatile struct DMA* dma, enum DmaChannel channel, enum DmaConfig config_mask, volatile void* periph) { @@ -195,6 +198,9 @@ static void configure_dma(volatile struct DMA* dma, enum DmaChannel channel, regs->CPAR = (uint32_t)periph; } +/** + * Starts the given DMA channel using the given parameters + */ static void start_dma(volatile struct DMA* dma, enum DmaChannel channel, volatile void* mem, uint16_t size) { diff --git a/drv/dma.h b/drv/dma.h index 1e38987..5367530 100644 --- a/drv/dma.h +++ b/drv/dma.h @@ -15,11 +15,19 @@ //--type definitions------------------------------------------------------------ +/** + * Available DMA peripherals. Note that some of these peripherals may not be + * available on all chips + */ enum DmaPeriph { DMA_PERIPH_1, DMA_PERIPH_2, }; +/** + * Available DMA channels. Note that some of these channels may not be + * available on all chips and all DMA peripheral + */ enum DmaChannel { DMA_CHANNEL_1 = 0, DMA_CHANNEL_2, @@ -30,6 +38,9 @@ enum DmaChannel { DMA_CHANNEL_7, //not available for DMA 2 }; +/** + * Configuration options for memory-to-peripheral transfers + */ enum DmaConfig { DMA_CONFIG_IRQ_COMPLETE = (0x1 << 1), DMA_CONFIG_IRQ_HALF = (0x1 << 2), @@ -51,6 +62,9 @@ enum DmaConfig { DMA_CONFIG_PRIO_VHIGH = (0x3 << 12), }; +/** + * Configuration options for memory-to-memory transfers + */ enum DmaConfigM2M { DMA_CONFIG_M2M_IRQ_COMPLETE = (0x1 << 1), DMA_CONFIG_M2M_IRQ_HALF = (0x1 << 2), @@ -69,14 +83,25 @@ enum DmaConfigM2M { DMA_CONFIG_M2M_PRIO_VHIGH = (0x3 << 12), }; +/** + * Available sources for a DMA IRQ. These sources can be enabled independently + * in the DMA configuration. + */ enum DmaIRQSource { DMA_IRQ_SOURCE_COMPLETE = (0x1 << 1), DMA_IRQ_SOURCE_HALF = (0x1 << 2), DMA_IQR_SOURCE_ERROR = (0x2 << 3), }; +/** + * Prototype of the IRQ callbacks that the applicative code can provide + */ typedef void (*DmaCallback)(enum DmaIRQSource, volatile void* param); +/** + * Generic struct used to share DAM configs between peripheral drivers and + * services providing DMA interfaces + */ struct DmaParam { void* periph; enum DmaConfig config; //DMA config, must correspond to peripheral @@ -87,25 +112,67 @@ struct DmaParam { //--functions------------------------------------------------------------------- +/** + * Configures the given DMA channel with the provided configuration, to perform + * a transfer to or from the given peripheral register. The specified callback, + * if any, will be called on the enabled IRQ sources, with the specified + * parameter, if any. + * + * This function doesn't initiate transfers, use dma_start() for that + */ void dma_configure(enum DmaPeriph dma, enum DmaChannel channel, enum DmaConfig config_mask, volatile void* periph, DmaCallback callback, volatile void* cb_param); +/** + * Unimplemented + */ void dma_configure_mem2mem(enum DmaPeriph dma, enum DmaChannel channel, enum DmaConfigM2M config_mask, const void* src, void* dest, uint16_t size, DmaCallback callback, void* cb_param); +/** + * Resets the given DMA channel, restoring the default configuration and + * disabling it + */ void dma_reset(enum DmaPeriph dma, enum DmaChannel channel); -void dma_exit_critical(enum DmaPeriph dma, enum DmaChannel channel); - +/** + * Initiate a transfer on the given DMA channel, to or from the given memory + * address, and of the specified size. + * + * Should only be used after the channel has been configured through + * dma_configure() + * All transfers started must be eventually stopped, or the channel reset, for + * proper IRQ behavior. + */ void dma_start(enum DmaPeriph dma, enum DmaChannel channel, volatile void* mem, uint16_t size); -void dma_enter_critical(enum DmaPeriph dma, enum DmaChannel channel); - +/** + * Stops a transfer on the given DMA channel. If the transfer has already + * ended, properly shutdown the channel. Configuration is not lost after calling + * this function and dma_start() may be called again + */ void dma_stop(enum DmaPeriph dma, enum DmaChannel channel); +/** + * Enters a DMA critical section, disabling the given channel's IRQs until + * dma_exit_critical() is called + */ +void dma_enter_critical(enum DmaPeriph dma, enum DmaChannel channel); + +/** + * Exists a DMA critical section previously entered through + * dma_enter_critical(). Reenables the given channel's IRQs + */ +void dma_exit_critical(enum DmaPeriph dma, enum DmaChannel channel); + +/** + * Returns the remaining number of bytes to be transmitted while a transfer is + * running. When no transfer is running, returns the number of bytes to transfer + * next + */ uint16_t dma_get_remaining(enum DmaPeriph dma, enum DmaChannel channe);