summaryrefslogtreecommitdiff
path: root/nuttx/arch/arm/src/sam3u/sam3u_dmac.c
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2010-03-28 16:10:36 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2010-03-28 16:10:36 +0000
commitb2b4e94276a9e54322925e95a61dd82820242725 (patch)
treed7fc37fa3bad9580960d9a712a87da5e0cfa2403 /nuttx/arch/arm/src/sam3u/sam3u_dmac.c
parentddf824b8aa26b9825850a910461557243ecf4225 (diff)
downloadpx4-nuttx-b2b4e94276a9e54322925e95a61dd82820242725.tar.gz
px4-nuttx-b2b4e94276a9e54322925e95a61dd82820242725.tar.bz2
px4-nuttx-b2b4e94276a9e54322925e95a61dd82820242725.zip
A little more DMA logic
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@2558 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx/arch/arm/src/sam3u/sam3u_dmac.c')
-rwxr-xr-xnuttx/arch/arm/src/sam3u/sam3u_dmac.c179
1 files changed, 123 insertions, 56 deletions
diff --git a/nuttx/arch/arm/src/sam3u/sam3u_dmac.c b/nuttx/arch/arm/src/sam3u/sam3u_dmac.c
index e52fed880..7a686ca15 100755
--- a/nuttx/arch/arm/src/sam3u/sam3u_dmac.c
+++ b/nuttx/arch/arm/src/sam3u/sam3u_dmac.c
@@ -69,12 +69,13 @@
struct sam3u_dma_s
{
uint8_t chan; /* DMA channel number (0-6) */
- uint8_t flags; /* DMA channel flags */
bool inuse; /* TRUE: The DMA channel is in use */
+ uint16_t flags; /* DMA channel flags */
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 */
- volatile uint16_t xfrsize; /* Total transfer size */
+ uint16_t bufsize; /* Transfer buffer size in bytes */
+ volatile uint16_t remaining; /* Total number of bytes remaining to be transferred */
};
/****************************************************************************
@@ -85,6 +86,22 @@ struct sam3u_dma_s
static sem_t g_dmasem;
+/* CTRLA field lookups */
+
+static const uint32_t g_srcwidth[3] =
+{
+ DMACHAN_CTRLA_SRCWIDTH_BYTE,
+ DMACHAN_CTRLA_SRCWIDTH_HWORD,
+ DMACHAN_CTRLA_SRCWIDTH_WORD
+};
+
+static const uint32_t g_destwidth[3] =
+{
+ DMACHAN_CTRLA_DSTWIDTH_BYTE,
+ DMACHAN_CTRLA_DSTWIDTH_HWORD,
+ DMACHAN_CTRLA_DSTWIDTH_WORD
+};
+
/* This array describes the state of each DMA */
static struct sam3u_dma_s g_dma[CONFIG_SAM3U_NDMACHAN] =
@@ -201,42 +218,23 @@ static inline void
sam3u_settxctrla(struct sam3u_dma_s *dmach, uint32_t dmasize, uint32_t otherbits)
{
uint32_t regval;
- uint32_t flags;
+ unsigned int ndx;
DEBUGASSERT(dmach && dmasize <= DMACHAN_CTRLA_BTSIZE_MAX);
regval = (dmasize << DMACHAN_CTRLA_BTSIZE_SHIFT) | otherbits;
/* Since this is a transmit, the source is described by the memeory selections */
- flags = dmach->flags & DMACH_FLAG_MEMWIDTH_MASK;
- if (flags == DMACH_FLAG_MEMWIDTH_8BITS)
- {
- regval |= DMACHAN_CTRLA_SRCWIDTH_BYTE;
- }
- else if (flags == DMACH_FLAG_MEMWIDTH_16BITS)
- {
- regval |= DMACHAN_CTRLA_SRCWIDTH_HWORD;
- }
- else /* if (flags == DMACH_FLAG_MEMWIDTH_32BITS) */
- {
- regval |= DMACHAN_CTRLA_SRCWIDTH_WORD;
- }
+ ndx = (dmach->flags & DMACH_FLAG_MEMWIDTH_MASK) >> DMACH_FLAG_MEMWIDTH_SHIFT;
+ DEBUGASSERT(ndx < 3);
+ regval |= g_srcwidth[ndx];
+ return regval;
/* Since this is a transmit, the destination is described by the peripheral selections */
- flags = dmach->flags & DMACH_FLAG_PERIPHWIDTH_MASK;
- if (flags == DMACH_FLAG_PERIPHWIDTH_8BITS)
- {
- regval |= DMACHAN_CTRLA_DSTWIDTH_BYTE;
- }
- else if (flags == DMACH_FLAG_PERIPHWIDTH_16BITS)
- {
- regval |= DMACHAN_CTRLA_DSTWIDTH_HWORD;
- }
- else /* if (flags == DMACH_FLAG_PERIPHWIDTH_32BITS) */
- {
- regval |= DMACHAN_CTRLA_DSTWIDTH_WORD;
- }
+ ndx = (dmach->flags & DMACH_FLAG_PERIPHWIDTH_MASK) >> DMACH_FLAG_PERIPHWIDTH_SHIFT;
+ DEBUGASSERT(ndx < 3);
+ regval |= g_destwidth[ndx];
return regval;
}
@@ -252,44 +250,108 @@ sam3u_settxctrla(struct sam3u_dma_s *dmach, uint32_t dmasize, uint32_t otherbits
static inline void
sam3u_setrxctrla(struct sam3u_dma_s *dmach, uint32_t dmasize, uint32_t otherbits)
{
- uint32_t regval;
- uint32_t flags;
+ uint32_t regval;
+ unsigned int ndx;
DEBUGASSERT(dmach && dmasize <= DMACHAN_CTRLA_BTSIZE_MAX);
regval = (dmasize << DMACHAN_CTRLA_BTSIZE_SHIFT) | otherbits;
/* Since this is a receive, the source is described by the peripheral selections */
- flags = dmach->flags & DMACH_FLAG_PERIPHWIDTH_MASK;
- if (flags == DMACH_FLAG_PERIPHWIDTH_8BITS)
- {
- regval |= DMACHAN_CTRLA_SRCWIDTH_BYTE;
- }
- else if (flags == DMACH_FLAG_PERIPHWIDTH_16BITS)
- {
- regval |= DMACHAN_CTRLA_SRCWIDTH_HWORD;
- }
- else /* if (flags == DMACH_FLAG_PERIPHWIDTH_32BITS) */
- {
- regval |= DMACHAN_CTRLA_SRCWIDTH_WORD;
- }
+ ndx = (dmach->flags & DMACH_FLAG_PERIPHWIDTH_MASK) >> DMACH_FLAG_PERIPHWIDTH_SHIFT;
+ DEBUGASSERT(ndx < 3);
+ regval |= g_srcwidth[ndx];
/* Since this is a receive, the destination is described by the memory selections */
- flags = dmach->flags & DMACH_FLAG_MEMWIDTH_MASK;
- if (flags == DMACH_FLAG_MEMWIDTH_8BITS)
- {
- regval |= DMACHAN_CTRLA_DSTWIDTH_BYTE;
- }
- else if (flags == DMACH_FLAG_MEMWIDTH_16BITS)
+ ndx = (dmach->flags & DMACH_FLAG_MEMWIDTH_MASK) >> DMACH_FLAG_MEMWIDTH_SHIFT;
+ DEBUGASSERT(ndx < 3);
+ regval |= g_destwidth[ndx];
+ return regval;
+}
+
+/************************************************************************************
+ * Name: sam3u_srcctrlb
+ *
+ * Description:
+ * Set source related CTRLB fields
+ *
+ ************************************************************************************/
+
+static void sam3u_srcctrlb(struct sam3u_dma_s *dmach, bool lli, bool autoincr)
+{
+ uint32_t regval;
+
+ /* Fetch CTRLB and clear the configurable bits */
+
+ regval = getreg32(dmach->base + SAM3U_DMACHAN_CTRLB_OFFSET);
+ regval &= ~ (DMACHAN_CTRLB_SRCDSCR | DMACHAN_CTRLB_SRCINCR_MASK | 1<<31);
+
+ /* Disable the source descriptor if we are not using the LLI transfer mode */
+
+ if (lli)
{
- regval |= DMACHAN_CTRLA_DSTWIDTH_HWORD;
+ regval |= DMACHAN_CTRLB_SRCDSCR;
}
- else /* if (flags == DMACH_FLAG_MEMWIDTH_32BITS) */
+
+ /* Select address incrementing */
+
+ regval |= autoincr ? DMACHAN_CTRLB_SRCINCR_INCR ? DMACHAN_CTRLB_SRCINCR_FIXED;
+
+ /* Save the updated CTRLB value */
+
+ putreg32(regval, dmach->base + SAM3U_DMACHAN_CTRLB_OFFSET)
+}
+
+/************************************************************************************
+ * Name: sam3u_destctrlb
+ *
+ * Description:
+ * Set destination related CTRLB fields
+ *
+ ************************************************************************************/
+
+static void sam3u_destctrlb(struct sam3u_dma_s *dmach, bool lli, bool autoincr)
+{
+ uint32_t regval;
+
+ /* Fetch CTRLB and clear the configurable bits */
+
+ regval = getreg32(dmach->base + SAM3U_DMACHAN_CTRLB_OFFSET);
+ regval &= ~ (DMACHAN_CTRLB_DSTDSCR | DMACHAN_CTRLB_DSTINCR_MASK);
+
+ /* Disable the source descriptor if we are not using the LLI transfer mode */
+
+ if (lli)
{
- regval |= DMACHAN_CTRLA_DSTWIDTH_WORD;
+ regval |= DMACHAN_CTRLB_DSTDSCR;
}
- return regval;
+
+ /* Select address incrementing */
+
+ regval |= autoincr ? DMACHAN_CTRLB_DESTINCR_INCR ? DMACHAN_CTRLB_DESTINCR_FIXED;
+
+ /* Save the updated CTRLB value */
+
+ putreg32(regval, dmach->base + SAM3U_DMACHAN_CTRLB_OFFSET)
+}
+
+/************************************************************************************
+ * Name: sam3u_flowcontrol
+ *
+ * Description:
+ * Select flow control
+ *
+ ************************************************************************************/
+
+static inline void sam3u_flowcontrol(struct sam3u_dma_s *dmach, uint32_t setting)
+{
+ uint32_t regval;
+
+ regval = getreg32(dmach->base + SAM3U_DMACHAN_CTRLB_OFFSET);
+ regval &= ~(DMACHAN_CTRLB_FC_MASK);
+ regval |= setting;
+ putreg(regval, dmach->base + SAM3U_DMACHAN_CTRLB_OFFSET);
}
/************************************************************************************
@@ -355,6 +417,11 @@ void weak_function up_dmainitialize(void)
* the required FIFO size and flow control capabilities (determined by
* dma_flags) then gives the caller exclusive access to the DMA channel.
*
+ * The naming convention in all of the DMA interfaces is that one side is
+ * the 'peripheral' and the other is 'memory'. Howerver, the interface
+ * could still be used if, for example, both sides were memory although
+ * the naming would be awkward.
+ *
* Returned Value:
* If a DMA channel if the required FIFO size is available, this function
* returns a non-NULL, void* DMA channel handle. NULL is returned on any
@@ -362,7 +429,7 @@ void weak_function up_dmainitialize(void)
*
****************************************************************************/
-DMA_HANDLE sam3u_dmachannel(uint8_t dmach_flags)
+DMA_HANDLE sam3u_dmachannel(uint16_t dmach_flags)
{
struct sam3u_dma_s *dmach;
unsigned int chndx;
@@ -406,7 +473,7 @@ DMA_HANDLE sam3u_dmachannel(uint8_t dmach_flags)
/* Initialize the transfer state */
- dmach->xfrsize = 0;
+ dmach->remaining = 0;
break;
}
}