diff options
Diffstat (limited to 'nuttx/arch/arm/src/stm32/stm32f40xxx_dma.c')
-rw-r--r-- | nuttx/arch/arm/src/stm32/stm32f40xxx_dma.c | 907 |
1 files changed, 0 insertions, 907 deletions
diff --git a/nuttx/arch/arm/src/stm32/stm32f40xxx_dma.c b/nuttx/arch/arm/src/stm32/stm32f40xxx_dma.c deleted file mode 100644 index 40fce8cb5..000000000 --- a/nuttx/arch/arm/src/stm32/stm32f40xxx_dma.c +++ /dev/null @@ -1,907 +0,0 @@ -/**************************************************************************** - * arch/arm/src/stm32/stm32f40xxx_dma.c - * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt <gnutt@nuttx.org> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include <nuttx/config.h> - -#include <stdint.h> -#include <stdbool.h> -#include <semaphore.h> -#include <debug.h> -#include <errno.h> - -#include <nuttx/irq.h> -#include <nuttx/arch.h> -#include <arch/irq.h> - -#include "up_arch.h" -#include "up_internal.h" -#include "os_internal.h" -#include "chip.h" -#include "stm32_dma.h" -#include "stm32_internal.h" - -/* This file supports only the STM32 F4 family (an probably the F2 family - * as well?) - */ - -#if defined(CONFIG_STM32_STM32F40XX) - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -#define DMA1_NSTREAMS 8 -#if STM32_NDMA > 1 -# define DMA2_NSTREAMS 8 -# define DMA_NSTREAMS (DMA1_NSTREAMS+DMA2_NSTREAMS) -#else -# define DMA_NSTREAMS DMA1_NSTREAMS -#endif - -#ifndef CONFIG_DMA_PRI -# define CONFIG_DMA_PRI NVIC_SYSH_PRIORITY_DEFAULT -#endif - -/* Convert the DMA stream base address to the DMA register block address */ - -#define DMA_BASE(ch) (ch & 0xfffffc00) - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* This structure descibes one DMA channel */ - -struct stm32_dma_s -{ - uint8_t stream; /* DMA stream number (0-7) */ - uint8_t irq; /* DMA stream IRQ number */ - uint8_t shift; /* ISR/IFCR bit shift value */ - uint8_t channel; /* DMA channel number (0-7) */ - sem_t sem; /* Used to wait for DMA channel to become available */ - uint32_t base; /* DMA register channel base address */ - dma_callback_t callback; /* Callback invoked when the DMA completes */ - void *arg; /* Argument passed to callback function */ -}; - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/* This array describes the state of each DMA */ - -static struct stm32_dma_s g_dma[DMA_NSTREAMS] = -{ - { - .stream = 0, - .irq = STM32_IRQ_DMA1S0, - .shift = DMA_INT_STREAM0_SHIFT, - .base = STM32_DMA1_BASE + STM32_DMA_OFFSET(0), - }, - { - .stream = 1, - .irq = STM32_IRQ_DMA1S1, - .shift = DMA_INT_STREAM1_SHIFT, - .base = STM32_DMA1_BASE + STM32_DMA_OFFSET(1), - }, - { - .stream = 2, - .irq = STM32_IRQ_DMA1S2, - .shift = DMA_INT_STREAM2_SHIFT, - .base = STM32_DMA1_BASE + STM32_DMA_OFFSET(2), - }, - { - .stream = 3, - .irq = STM32_IRQ_DMA1S3, - .shift = DMA_INT_STREAM3_SHIFT, - .base = STM32_DMA1_BASE + STM32_DMA_OFFSET(4), - }, - { - .stream = 4, - .irq = STM32_IRQ_DMA1S4, - .shift = DMA_INT_STREAM4_SHIFT, - .base = STM32_DMA1_BASE + STM32_DMA_OFFSET(4), - }, - { - .stream = 5, - .irq = STM32_IRQ_DMA1S5, - .shift = DMA_INT_STREAM5_SHIFT, - .base = STM32_DMA1_BASE + STM32_DMA_OFFSET(5), - }, - { - .stream = 6, - .irq = STM32_IRQ_DMA1S6, - .shift = DMA_INT_STREAM6_SHIFT, - .base = STM32_DMA1_BASE + STM32_DMA_OFFSET(6), - }, - { - .stream = 7, - .irq = STM32_IRQ_DMA1S7, - .shift = DMA_INT_STREAM7_SHIFT, - .base = STM32_DMA1_BASE + STM32_DMA_OFFSET(7), - }, -#if STM32_NDMA > 1 - { - .stream = 0, - .irq = STM32_IRQ_DMA2S0, - .shift = DMA_INT_STREAM0_SHIFT, - .base = STM32_DMA2_BASE + STM32_DMA_OFFSET(0), - }, - { - .stream = 1, - .irq = STM32_IRQ_DMA2S1, - .shift = DMA_INT_STREAM1_SHIFT, - .base = STM32_DMA2_BASE + STM32_DMA_OFFSET(1), - }, - { - .stream = 2, - .irq = STM32_IRQ_DMA2S2, - .shift = DMA_INT_STREAM2_SHIFT, - .base = STM32_DMA2_BASE + STM32_DMA_OFFSET(2), - }, - { - .stream = 3, - .irq = STM32_IRQ_DMA2S3, - .shift = DMA_INT_STREAM3_SHIFT, - .base = STM32_DMA2_BASE + STM32_DMA_OFFSET(3), - }, - { - .stream = 4, - .irq = STM32_IRQ_DMA2S4, - .base = STM32_DMA2_BASE + STM32_DMA_OFFSET(4), - }, - { - .stream = 5, - .irq = STM32_IRQ_DMA2S5, - .shift = DMA_INT_STREAM5_SHIFT, - .base = STM32_DMA2_BASE + STM32_DMA_OFFSET(5), - }, - { - .stream = 6, - .irq = STM32_IRQ_DMA2S6, - .shift = DMA_INT_STREAM6_SHIFT, - .base = STM32_DMA2_BASE + STM32_DMA_OFFSET(6), - }, - { - .stream = 7, - .irq = STM32_IRQ_DMA2S7, - .shift = DMA_INT_STREAM7_SHIFT, - .base = STM32_DMA2_BASE + STM32_DMA_OFFSET(7), - }, -#endif -}; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * DMA register access functions - ****************************************************************************/ - -/* Get non-channel register from DMA1 or DMA2 */ - -static inline uint32_t dmabase_getreg(struct stm32_dma_s *dmast, uint32_t offset) -{ - return getreg32(DMA_BASE(dmast->base) + offset); -} - -/* Write to non-channel register in DMA1 or DMA2 */ - -static inline void dmabase_putreg(struct stm32_dma_s *dmast, uint32_t offset, uint32_t value) -{ - putreg32(value, DMA_BASE(dmast->base) + offset); -} - -/* Get channel register from DMA1 or DMA2 */ - -static inline uint32_t dmast_getreg(struct stm32_dma_s *dmast, uint32_t offset) -{ - return getreg32(dmast->base + offset); -} - -/* Write to channel register in DMA1 or DMA2 */ - -static inline void dmast_putreg(struct stm32_dma_s *dmast, uint32_t offset, uint32_t value) -{ - putreg32(value, dmast->base + offset); -} - -/************************************************************************************ - * Name: stm32_dmatake() and stm32_dmagive() - * - * Description: - * Used to get exclusive access to a DMA channel. - * - ************************************************************************************/ - -static void stm32_dmatake(FAR struct stm32_dma_s *dmast) -{ - /* Take the semaphore (perhaps waiting) */ - - while (sem_wait(&dmast->sem) != 0) - { - /* The only case that an error should occur here is if the wait was awakened - * by a signal. - */ - - ASSERT(errno == EINTR); - } -} - -static inline void stm32_dmagive(FAR struct stm32_dma_s *dmast) -{ - (void)sem_post(&dmast->sem); -} - -/************************************************************************************ - * Name: stm32_dmastream - * - * Description: - * Get the g_dma table entry associated with a DMA controller and a stream number - * - ************************************************************************************/ - -static inline FAR struct stm32_dma_s *stm32_dmastream(unsigned int stream, - unsigned int controller) -{ - int index; - - DEBUGASSERT(stream < DMA_NSTREAMS && controller < STM32_NDMA); - - /* Convert the controller + stream based on the fact that there are 8 streams - * per controller. - */ - -#if STM32_NDMA > 1 - index = controller << 3 | stream; -#else - index = stream; -#endif - - /* Then return the stream structure associated with the stream index */ - - return &g_dma[index]; -} - -/************************************************************************************ - * Name: stm32_dmamap - * - * Description: - * Get the g_dma table entry associated with a bit-encoded DMA selection - * - ************************************************************************************/ - -static inline FAR struct stm32_dma_s *stm32_dmamap(unsigned long dmamap) -{ - /* Extract the DMA controller number from the bit encoded value */ - - unsigned int controller = STM32_DMA_CONTROLLER(dmamap); - - /* Extact the stream number from the bit encoded value */ - - unsigned int stream = STM32_DMA_STREAM(dmamap); - - /* Return the table entry associated with the controller + stream */ - - return stm32_dmastream(stream, controller); -} - -/************************************************************************************ - * Name: stm32_dmastreamdisable - * - * Description: - * Disable the DMA stream - * - ************************************************************************************/ - -static void stm32_dmastreamdisable(struct stm32_dma_s *dmast) -{ - uint32_t regoffset; - uint32_t regval; - - /* Disable all interrupts at the DMA controller */ - - regval = dmast_getreg(dmast, STM32_DMA_SCR_OFFSET); - regval &= ~DMA_SCR_ALLINTS; - - /* Disable the DMA stream */ - - regval &= ~DMA_SCR_EN; - dmast_putreg(dmast, STM32_DMA_SCR_OFFSET, regval); - - /* Clear pending stream interrupts by setting bits in the upper or lower IFCR - * register - */ - - if (dmast->stream < 4) - { - regoffset = STM32_DMA_LIFCR_OFFSET; - } - else - { - regoffset = STM32_DMA_HIFCR_OFFSET; - } - - dmabase_putreg(dmast, regoffset, (DMA_STREAM_MASK << dmast->shift)); -} - -/************************************************************************************ - * Name: stm32_dmainterrupt - * - * Description: - * DMA interrupt handler - * - ************************************************************************************/ - -static int stm32_dmainterrupt(int irq, void *context) -{ - struct stm32_dma_s *dmast; - uint32_t status; - uint32_t regoffset = 0; - unsigned int stream = 0; - unsigned int controller = 0; - - /* Get the stream and the controller that generated the interrupt */ - - if (irq >= STM32_IRQ_DMA1S0 && irq <= STM32_IRQ_DMA1S6) - { - stream = irq - STM32_IRQ_DMA1S0; - controller = DMA1; - } - else if (irq == STM32_IRQ_DMA1S7) - { - stream = 7; - controller = DMA1; - } - else -#if STM32_NDMA > 1 - if (irq >= STM32_IRQ_DMA2S0 && irq <= STM32_IRQ_DMA2S4) - { - stream = irq - STM32_IRQ_DMA2S0; - controller = DMA2; - } - else if (irq >= STM32_IRQ_DMA2S5 && irq <= STM32_IRQ_DMA2S7) - { - stream = irq - STM32_IRQ_DMA2S5 + 5; - controller = DMA2; - } - else -#endif - { - PANIC(OSERR_INTERNAL); - } - - /* Get the stream structure from the stream and controller numbers */ - - dmast = stm32_dmastream(stream, controller); - - /* Select the interrupt status register (either the LISR or HISR) - * based on the stream number that caused the interrupt. - */ - - if (stream < 4) - { - regoffset = STM32_DMA_LISR_OFFSET; - } - else - { - regoffset = STM32_DMA_HISR_OFFSET; - } - - /* Get the interrupt status for this stream */ - - status = (dmabase_getreg(dmast, regoffset) >> dmast->shift) & DMA_STREAM_MASK; - - /* Clear fetched stream interrupts by setting bits in the upper or lower IFCR - * register - */ - - if (stream < 4) - { - regoffset = STM32_DMA_LIFCR_OFFSET; - } - else - { - regoffset = STM32_DMA_HIFCR_OFFSET; - } - - dmabase_putreg(dmast, regoffset, (status << dmast->shift)); - - /* Invoke the callback */ - - if (dmast->callback) - { - dmast->callback(dmast, status, dmast->arg); - } - return OK; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: stm32_dmainitialize - * - * Description: - * Initialize the DMA subsystem - * - * Returned Value: - * None - * - ****************************************************************************/ - -void weak_function up_dmainitialize(void) -{ - struct stm32_dma_s *dmast; - int stream; - - /* Initialize each DMA stream */ - - for (stream = 0; stream < DMA_NSTREAMS; stream++) - { - dmast = &g_dma[stream]; - sem_init(&dmast->sem, 0, 1); - - /* Attach DMA interrupt vectors */ - - (void)irq_attach(dmast->irq, stm32_dmainterrupt); - - /* Disable the DMA stream */ - - stm32_dmastreamdisable(dmast); - - /* Enable the IRQ at the NVIC (still disabled at the DMA controller) */ - - up_enable_irq(dmast->irq); - - /* Set the interrrupt priority */ - - up_prioritize_irq(dmast->irq, CONFIG_DMA_PRI); - } -} - -/**************************************************************************** - * Name: stm32_dmachannel - * - * Description: - * Allocate a DMA channel. This function gives the caller mutually - * exclusive access to the DMA channel specified by the 'dmamap' argument. - * DMA channels are shared on the STM32: Devices sharing the same DMA - * channel cannot do DMA concurrently! See the DMACHAN_* definitions in - * stm32_dma.h. - * - * If the DMA channel is not available, then stm32_dmachannel() will wait - * until the holder of the channel relinquishes the channel by calling - * stm32_dmafree(). WARNING: If you have two devices sharing a DMA - * channel and the code never releases the channel, the stm32_dmachannel - * call for the other will hang forever in this function! Don't let your - * design do that! - * - * Hmm.. I suppose this interface could be extended to make a non-blocking - * version. Feel free to do that if that is what you need. - * - * Input parameter: - * dmamap - Identifies the stream/channel resource. For the STM32 F4, this - * is a bit-encoded value as provided by the the DMAMAP_* definitions - * in chip/stm32f40xxx_dma.h - * - * Returned Value: - * Provided that 'dmamap' is valid, this function ALWAYS returns a non-NULL, - * void* DMA channel handle. (If 'dmamap' is invalid, the function will - * assert if debug is enabled or do something ignorant otherwise). - * - * Assumptions: - * - The caller does not hold he DMA channel. - * - The caller can wait for the DMA channel to be freed if it is no - * available. - * - ****************************************************************************/ - -DMA_HANDLE stm32_dmachannel(unsigned int dmamap) -{ - FAR struct stm32_dma_s *dmast; - - /* Get the stream index from the bit-encoded channel value */ - - dmast = stm32_dmamap(dmamap); - DEBUGASSERT(dmast != NULL); - - /* Get exclusive access to the DMA channel -- OR wait until the channel - * is available if it is currently being used by another driver - */ - - stm32_dmatake(dmast); - - /* The caller now has exclusive use of the DMA channel. Assign the - * channel to the stream and return an opaque reference to the stream - * structure. - */ - - dmast->channel = STM32_DMA_CHANNEL(dmamap); - return (DMA_HANDLE)dmast; -} - -/**************************************************************************** - * Name: stm32_dmafree - * - * Description: - * Release a DMA channel. If another thread is waiting for this DMA channel - * in a call to stm32_dmachannel, then this function will re-assign the - * DMA channel to that thread and wake it up. NOTE: The 'handle' used - * in this argument must NEVER be used again until stm32_dmachannel() is - * called again to re-gain access to the channel. - * - * Returned Value: - * None - * - * Assumptions: - * - The caller holds the DMA channel. - * - There is no DMA in progress - * - ****************************************************************************/ - -void stm32_dmafree(DMA_HANDLE handle) -{ - struct stm32_dma_s *dmast = (struct stm32_dma_s *)handle; - - DEBUGASSERT(handle != NULL); - - /* Release the channel */ - - stm32_dmagive(dmast); -} - -/**************************************************************************** - * Name: stm32_dmasetup - * - * Description: - * Configure DMA before using - * - ****************************************************************************/ - -void stm32_dmasetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, - size_t ntransfers, uint32_t scr) -{ - struct stm32_dma_s *dmast = (struct stm32_dma_s *)handle; - uint32_t regoffset; - uint32_t regval; - - dmadbg("paddr: %08x maddr: %08x ntransfers: %d scr: %08x\n", - paddr, maddr, ntransfers, scr); - - /* "If the stream is enabled, disable it by resetting the EN bit in the - * DMA_SxCR register, then read this bit in order to confirm that there is no - * ongoing stream operation. Writing this bit to 0 is not immediately - * effective since it is actually written to 0 once all the current transfers - * have finished. When the EN bit is read as 0, this means that the stream is - * ready to be configured. It is therefore necessary to wait for the EN bit - * to be cleared before starting any stream configuration. ..." - */ - - while ((dmast_getreg(dmast, STM32_DMA_SCR_OFFSET) & DMA_SCR_EN) != 0); - - /* "... All the stream dedicated bits set in the status register (DMA_LISR - * and DMA_HISR) from the previous data block DMA transfer should be cleared - * before the stream can be re-enabled." - * - * Clear pending stream interrupts by setting bits in the upper or lower IFCR - * register - */ - - if (dmast->stream < 4) - { - regoffset = STM32_DMA_LIFCR_OFFSET; - } - else - { - regoffset = STM32_DMA_HIFCR_OFFSET; - } - - dmabase_putreg(dmast, regoffset, (DMA_STREAM_MASK << dmast->shift)); - - /* "Set the peripheral register address in the DMA_SPARx register. The data - * will be moved from/to this address to/from the memory after the - * peripheral event. - */ - - dmast_putreg(dmast, STM32_DMA_SPAR_OFFSET, paddr); - - /* "Set the memory address in the DMA_SM0ARx ... register. The data will be - * written to or read from this memory after the peripheral event." - * - * Note that in double-buffered mode it is explicitly assumed that the second - * buffer immediately follows the first. - */ - - dmast_putreg(dmast, STM32_DMA_SM0AR_OFFSET, maddr); - if (scr & DMA_SCR_DBM) - { - dmast_putreg(dmast, STM32_DMA_SM1AR_OFFSET, maddr + ntransfers); - } - - /* "Configure the total number of data items to be transferred in the - * DMA_SNDTRx register. After each peripheral event, this value will be - * decremented." - * - * "When the peripheral flow controller is used for a given stream, the value - * written into the DMA_SxNDTR has no effect on the DMA transfer. Actually, - * whatever the value written, it will be forced by hardware to 0xFFFF as soon - * as the stream is enabled..." - */ - - dmast_putreg(dmast, STM32_DMA_SNDTR_OFFSET, ntransfers); - - /* "Select the DMA channel (request) using CHSEL[2:0] in the DMA_SxCR register." - * - * "Configure the stream priority using the PL[1:0] bits in the DMA_SCRx" - * register." - */ - - regval = dmast_getreg(dmast, STM32_DMA_SCR_OFFSET); - regval &= ~(DMA_SCR_PL_MASK|DMA_SCR_CHSEL_MASK); - regval |= scr & DMA_SCR_PL_MASK; - regval |= (uint32_t)dmast->channel << DMA_SCR_CHSEL_SHIFT; - dmast_putreg(dmast, STM32_DMA_SCR_OFFSET, regval); - - /* "Configure the FIFO usage (enable or disable, threshold in transmission and - * reception)" - * - * "Caution is required when choosing the FIFO threshold (bits FTH[1:0] of the - * DMA_SxFCR register) and the size of the memory burst (MBURST[1:0] of the - * DMA_SxCR register): The content pointed by the FIFO threshold must exactly - * match to an integer number of memory burst transfers. If this is not in the - * case, a FIFO error (flag FEIFx of the DMA_HISR or DMA_LISR register) will be - * generated when the stream is enabled, then the stream will be automatically - * disabled." - * - * The FIFO is disabled in circular mode when transferring data from a - * peripheral to memory, as in this case it is usually desirable to know that - * every byte from the peripheral is transferred immediately to memory. It is - * not practical to flush the DMA FIFO, as this requires disabling the channel - * which triggers the transfer-complete interrupt. - * - * NOTE: The FEIFx error interrupt is not enabled because the FEIFx seems to - * be reported spuriously causing good transfers to be marked as failures. - */ - - regval = dmast_getreg(dmast, STM32_DMA_SFCR_OFFSET); - regval &= ~(DMA_SFCR_FTH_MASK | DMA_SFCR_FS_MASK | DMA_SFCR_FEIE); - if (!((scr & (DMA_SCR_CIRC | DMA_SCR_DIR_MASK)) == (DMA_SCR_CIRC | DMA_SCR_DIR_P2M))) - { - regval |= (DMA_SFCR_FTH_FULL | DMA_SFCR_DMDIS); - } - dmast_putreg(dmast, STM32_DMA_SFCR_OFFSET, regval); - - /* "Configure data transfer direction, circular mode, peripheral & memory - * incremented mode, peripheral & memory data size, and interrupt after - * half and/or full transfer in the DMA_CCRx register." - * - * Note: The CT bit is always reset. - */ - - regval = dmast_getreg(dmast, STM32_DMA_SCR_OFFSET); - regval &= ~(DMA_SCR_PFCTRL|DMA_SCR_DIR_MASK|DMA_SCR_PINC|DMA_SCR_MINC| - DMA_SCR_PSIZE_MASK|DMA_SCR_MSIZE_MASK|DMA_SCR_PINCOS| - DMA_SCR_CIRC|DMA_SCR_DBM|DMA_SCR_CT| - DMA_SCR_PBURST_MASK|DMA_SCR_MBURST_MASK); - scr &= (DMA_SCR_PFCTRL|DMA_SCR_DIR_MASK|DMA_SCR_PINC|DMA_SCR_MINC| - DMA_SCR_PSIZE_MASK|DMA_SCR_MSIZE_MASK|DMA_SCR_PINCOS| - DMA_SCR_DBM|DMA_SCR_CIRC| - DMA_SCR_PBURST_MASK|DMA_SCR_MBURST_MASK); - regval |= scr; - dmast_putreg(dmast, STM32_DMA_SCR_OFFSET, regval); -} - -/**************************************************************************** - * Name: stm32_dmastart - * - * Description: - * Start the DMA transfer - * - * Assumptions: - * - DMA handle allocated by stm32_dmachannel() - * - No DMA in progress - * - ****************************************************************************/ - -void stm32_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg, bool half) -{ - struct stm32_dma_s *dmast = (struct stm32_dma_s *)handle; - uint32_t scr; - - DEBUGASSERT(handle != NULL); - - /* Save the callback info. This will be invoked whent the DMA commpletes */ - - dmast->callback = callback; - dmast->arg = arg; - - /* Activate the stream by setting the ENABLE bit in the DMA_SCRx register. - * As soon as the stream is enabled, it can serve any DMA request from the - * peripheral connected on the stream. - */ - - scr = dmast_getreg(dmast, STM32_DMA_SCR_OFFSET); - scr |= DMA_SCR_EN; - - /* In normal mode, interrupt at either half or full completion. In circular - * and double-buffered modes, always interrupt on buffer wrap, and optionally - * interrupt at the halfway point. - */ - - if ((scr & (DMA_SCR_DBM|DMA_SCR_CIRC)) == 0) - { - /* Once half of the bytes are transferred, the half-transfer flag (HTIF) is - * set and an interrupt is generated if the Half-Transfer Interrupt Enable - * bit (HTIE) is set. At the end of the transfer, the Transfer Complete Flag - * (TCIF) is set and an interrupt is generated if the Transfer Complete - * Interrupt Enable bit (TCIE) is set. - */ - - scr |= (half ? (DMA_SCR_HTIE|DMA_SCR_TEIE) : (DMA_SCR_TCIE|DMA_SCR_TEIE)); - } - else - { - /* In non-stop modes, when the transfer completes it immediately resets - * and starts again. The transfer-complete interrupt is thus always - * enabled, and the half-complete interrupt can be used in circular - * mode to determine when the buffer is half-full, or in double-buffered - * mode to determine when one of the two buffers is full. - */ - - scr |= (half ? DMA_SCR_HTIE : 0) | DMA_SCR_TCIE | DMA_SCR_TEIE; - } - - dmast_putreg(dmast, STM32_DMA_SCR_OFFSET, scr); -} - -/**************************************************************************** - * Name: stm32_dmastop - * - * Description: - * Cancel the DMA. After stm32_dmastop() is called, the DMA channel is - * reset and stm32_dmasetup() must be called before stm32_dmastart() can be - * called again - * - * Assumptions: - * - DMA handle allocated by stm32_dmachannel() - * - ****************************************************************************/ - -void stm32_dmastop(DMA_HANDLE handle) -{ - struct stm32_dma_s *dmast = (struct stm32_dma_s *)handle; - stm32_dmastreamdisable(dmast); -} - -/**************************************************************************** - * Name: stm32_dmaresidual - * - * Description: - * Read the DMA bytes-remaining register. - * - * Assumptions: - * - DMA handle allocated by stm32_dmachannel() - * - ****************************************************************************/ - -size_t stm32_dmaresidual(DMA_HANDLE handle) -{ - struct stm32_dma_s *dmast = (struct stm32_dma_s *)handle; - uint32_t residual; - - /* Fetch the count of bytes remaining to be transferred. - * - * If the FIFO is enabled, this count may be inaccurate. ST don't - * appear to document whether this counts the peripheral or the memory - * side of the channel, and they don't make the memory pointer - * available either. - * - * For reception in circular mode the FIFO is disabled in order that - * this value can be useful. - */ - - residual = dmast_getreg(dmast, STM32_DMA_SNDTR_OFFSET); - - return (size_t)residual; -} - -/**************************************************************************** - * Name: stm32_dmasample - * - * Description: - * Sample DMA register contents - * - * Assumptions: - * - DMA handle allocated by stm32_dmachannel() - * - ****************************************************************************/ - -#ifdef CONFIG_DEBUG_DMA -void stm32_dmasample(DMA_HANDLE handle, struct stm32_dmaregs_s *regs) -{ - struct stm32_dma_s *dmast = (struct stm32_dma_s *)handle; - irqstate_t flags; - - flags = irqsave(); - regs->lisr = dmabase_getreg(dmast, STM32_DMA_LISR_OFFSET); - regs->hisr = dmabase_getreg(dmast, STM32_DMA_HISR_OFFSET); - regs->scr = dmast_getreg(dmast, STM32_DMA_SCR_OFFSET); - regs->sndtr = dmast_getreg(dmast, STM32_DMA_SNDTR_OFFSET); - regs->spar = dmast_getreg(dmast, STM32_DMA_SPAR_OFFSET); - regs->sm0ar = dmast_getreg(dmast, STM32_DMA_SM0AR_OFFSET); - regs->sm1ar = dmast_getreg(dmast, STM32_DMA_SM1AR_OFFSET); - regs->sfcr = dmast_getreg(dmast, STM32_DMA_SFCR_OFFSET); - irqrestore(flags); -} -#endif - -/**************************************************************************** - * Name: stm32_dmadump - * - * Description: - * Dump previously sampled DMA register contents - * - * Assumptions: - * - DMA handle allocated by stm32_dmachannel() - * - ****************************************************************************/ - -#ifdef CONFIG_DEBUG_DMA -void stm32_dmadump(DMA_HANDLE handle, const struct stm32_dmaregs_s *regs, - const char *msg) -{ - struct stm32_dma_s *dmast = (struct stm32_dma_s *)handle; - uint32_t dmabase = DMA_BASE(dmast->base); - - dmadbg("DMA Registers: %s\n", msg); - dmadbg(" LISR[%08x]: %08x\n", dmabase + STM32_DMA_LISR_OFFSET, regs->lisr); - dmadbg(" HISR[%08x]: %08x\n", dmabase + STM32_DMA_HISR_OFFSET, regs->hisr); - dmadbg(" SCR[%08x]: %08x\n", dmast->base + STM32_DMA_SCR_OFFSET, regs->scr); - dmadbg(" SNDTR[%08x]: %08x\n", dmast->base + STM32_DMA_SNDTR_OFFSET, regs->sndtr); - dmadbg(" SPAR[%08x]: %08x\n", dmast->base + STM32_DMA_SPAR_OFFSET, regs->spar); - dmadbg(" SM0AR[%08x]: %08x\n", dmast->base + STM32_DMA_SM0AR_OFFSET, regs->sm0ar); - dmadbg(" SM1AR[%08x]: %08x\n", dmast->base + STM32_DMA_SM1AR_OFFSET, regs->sm1ar); - dmadbg(" SFCR[%08x]: %08x\n", dmast->base + STM32_DMA_SFCR_OFFSET, regs->sfcr); -} -#endif - -#endif /* CONFIG_STM32_STM32F40XX */ |