Add function to 1) wait for a free channel, and 2) free a DMA channel
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@2144 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
parent
522251ef65
commit
842fe8c9ab
@ -40,6 +40,7 @@
|
|||||||
#include <nuttx/config.h>
|
#include <nuttx/config.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <semaphore.h>
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
@ -71,20 +72,13 @@
|
|||||||
* Private Types
|
* Private Types
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/* Pinch a byte if is possible if there are not very many DMA channels */
|
|
||||||
|
|
||||||
#if DMA_NCHANNELS > 8
|
|
||||||
typedef uint16 dma_bitset_t;
|
|
||||||
#else
|
|
||||||
typedef uint8 dma_bitset_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* This structure descibes one DMA channel */
|
/* This structure descibes one DMA channel */
|
||||||
|
|
||||||
struct stm32_dma_s
|
struct stm32_dma_s
|
||||||
{
|
{
|
||||||
ubyte chan; /* DMA channel number */
|
ubyte chan; /* DMA channel number */
|
||||||
ubyte irq; /* DMA channel IRQ number */
|
ubyte irq; /* DMA channel IRQ number */
|
||||||
|
sem_t sem; /* Used to wait for DMA channel to become available */
|
||||||
uint32 base; /* DMA register channel base address */
|
uint32 base; /* DMA register channel base address */
|
||||||
dma_callback_t callback; /* Callback invoked when the DMA completes */
|
dma_callback_t callback; /* Callback invoked when the DMA completes */
|
||||||
};
|
};
|
||||||
@ -93,11 +87,6 @@ struct stm32_dma_s
|
|||||||
* Private Data
|
* Private Data
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/* This bitset indicates which DMA channels have been allocated */
|
|
||||||
|
|
||||||
static dma_bitset_t g_dmaallocated;
|
|
||||||
static sem_t g_allocsem;
|
|
||||||
|
|
||||||
/* This array describes the state of each DMA */
|
/* This array describes the state of each DMA */
|
||||||
|
|
||||||
static struct stm32_dma_s g_dma[DMA_NCHANNELS] =
|
static struct stm32_dma_s g_dma[DMA_NCHANNELS] =
|
||||||
@ -202,6 +191,33 @@ static inline void dmachan_putreg(struct stm32_dma_s *dmach, uint32 offset, uint
|
|||||||
putreg32(value, dmach->base + offset);
|
putreg32(value, dmach->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 *dmach)
|
||||||
|
{
|
||||||
|
/* Take the semaphore (perhaps waiting) */
|
||||||
|
|
||||||
|
while (sem_wait(&dmach->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 *dmach)
|
||||||
|
{
|
||||||
|
(void)sem_post(&dmach->sem);
|
||||||
|
}
|
||||||
|
|
||||||
/************************************************************************************
|
/************************************************************************************
|
||||||
* Name: stm32_dmainterrupt
|
* Name: stm32_dmainterrupt
|
||||||
*
|
*
|
||||||
@ -275,6 +291,7 @@ void weak_function stm32_dmainitialize(void)
|
|||||||
|
|
||||||
for (chan = 0; chan < DMA_NCHANNELS; chan++)
|
for (chan = 0; chan < DMA_NCHANNELS; chan++)
|
||||||
{
|
{
|
||||||
|
sem_init(&g_dma[chan].sem, 0, 1);
|
||||||
irq_attach(g_dma[chan].irq, stm32_dmainterrupt);
|
irq_attach(g_dma[chan].irq, stm32_dmainterrupt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -292,35 +309,47 @@ void weak_function stm32_dmainitialize(void)
|
|||||||
|
|
||||||
DMA_HANDLE stm32_dmachannel(int chan)
|
DMA_HANDLE stm32_dmachannel(int chan)
|
||||||
{
|
{
|
||||||
struct stm32_dma_s *dmach = NULL;
|
struct stm32_dma_s *dmach = &g_dma[chan];
|
||||||
irqstate_t flags;
|
|
||||||
dma_bitset_t before;
|
|
||||||
int bit = (1 << chan);
|
|
||||||
|
|
||||||
DEBUGASSERT(chan < DMA_NCHANNELS);
|
DEBUGASSERT(chan < DMA_NCHANNELS);
|
||||||
|
|
||||||
/* This is essentially a test and set. We simply disable interrupts to
|
/* Get exclusive access to the DMA channel -- OR wait until the channel
|
||||||
* create the critical section. This is brutal (but very quich) and assures
|
* is available if it is currently being used by another driver
|
||||||
* that we have exclusive access to the allocation bitset
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
flags = irqsave();
|
stm32_dmatake(dmach);
|
||||||
before = g_dmaallocated;
|
|
||||||
g_dmaallocated |= bit;
|
|
||||||
irq_restore(flags);
|
|
||||||
|
|
||||||
/* Was this channel been available? */
|
/* The caller now has exclusive use of the DMA channel */
|
||||||
|
|
||||||
if ((before & bit) == 0)
|
|
||||||
{
|
|
||||||
/* Yes.. then the caller has it, return it */
|
|
||||||
|
|
||||||
dmach = &g_dma[chan];
|
|
||||||
}
|
|
||||||
|
|
||||||
return (DMA_HANDLE)dmach;
|
return (DMA_HANDLE)dmach;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: stm32_dmarelease
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Release a DMA 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 *dmach = (struct stm32_dma_s *)handle;
|
||||||
|
|
||||||
|
DEBUGASSERT(handle != NULL);
|
||||||
|
|
||||||
|
/* Release the channel */
|
||||||
|
|
||||||
|
stm32_dmagive(dmach);
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: stm32_dmasetup
|
* Name: stm32_dmasetup
|
||||||
*
|
*
|
||||||
|
@ -503,6 +503,19 @@ EXTERN void weak_function stm32_dmainitialize(void);
|
|||||||
|
|
||||||
EXTERN DMA_HANDLE stm32_dmachannel(int chan);
|
EXTERN DMA_HANDLE stm32_dmachannel(int chan);
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: stm32_dmarelease
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Release a DMA channel
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
EXTERN void stm32_dmafree(DMA_HANDLE handle);
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: stm32_dmasetup
|
* Name: stm32_dmasetup
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user