Hello,
I am trying to learn the DMA of the AM335x. I've been through the spruh73 reference manual, chapter 11, and as Jeffery Jones said in BeetleJuice "This thing reads like stereo instructions...". So I've been through it several times.
So, fortunately, section 11.3.19 has some useful examples, and 11.5.3 has explicit steps to trigger a DMA transfer. So I am attempting to follow them explicitly. I have included that section for your reading pleasure.
My first attempt is something simple: Transfer a big block of memory (0x40000 bytes) from one place to another. All linear addressed. All blocks declared in global memory. Until I can make this work, trying to drive it from a peripheral would only complicate troubleshooting.
I have set it up to use queue 2, and the event is 12 (because it is defined as "open" in the doc) and the DCHMAP is set to a 1:1 assignment of the channel numbers to the maps).
Question: What are any advantages to selecting which queue? And what is the setting to "bypass" a queue, as figure 11-2 shows in the reference manual?
The PaRAM is set to transfer 32767 for A-count, and 8 for B-count. The struct I used indicates that BIDX is a signed 16 bit number, so I kept it to only 15 bits, (0x7fff) in case for some reason, the register is actually using the sign bit.
I have stepped through the code, and examined the registers, and verified that they appear to match the summary in section 11.5.3 (except where step 3.2 and step 3.2 are the exact same steps). I perform step 4.1.iii and wait to see what happens.
However, it is not working. The EDMA3CC_S_IPR register never set a bit to indicate that it completed. I also enabled the interrupts for all three possible events (complete, error, and mem protect error). Those interrupts never fire either. When I pause, or hit a breakpoint in the task (which is basically a sleep loop) the destination buffer is still empty.
I'm pasting the code of the code below. For the enjoyment of anyone who wishes look at it, I've included the entire CCS7 project.
It uses adaptations from StarterWare to program the registers, however, I have also included the necessary edma source files and headers. So the project essentially can stand on it's own. And I've scrubbed it for most of the superfluous or unused files.
/************************************
* Looking for ANY interrupt event to see if the DMA tells us anything
****************************************/
void DmaComplete(unsigned int pValue) { /* tpcc_int_pend_po0 */
Hwi_clearInterrupt(12);
}
void DmaMemprotectErr(unsigned int pValue) { /* tpcc_mpint_pend_po */
Hwi_clearInterrupt(13);
}
void DmaError(unsigned int pValue) { /* tpcc_errint_pend_po */
Hwi_clearInterrupt(14);
}
Void DMATask(UArg a0, UArg a1) {
unsigned int status;
Hwi_Params edmaCompParams; /* Int 12 */
Hwi_Params edmaMemprotectErrParams; /* Int 13 */
Hwi_Params edmaErrorParams; /* Int 14 */
Error_Block eb;
Hwi_Params_init(&edmaCompParams);
edmaCompParams.priority = -1;
edmaCompParams.maskSetting = Hwi_MaskingOption_SELF;
edmaCompParams.enableInt = TRUE;
Error_init(&eb);
Hwi_create(12, DmaComplete, &edmaCompParams, &eb);
Hwi_Params_init(&edmaMemprotectErrParams);
edmaMemprotectErrParams.priority = -1;
edmaMemprotectErrParams.maskSetting = Hwi_MaskingOption_SELF;
edmaMemprotectErrParams.enableInt = TRUE;
Error_init(&eb);
Hwi_create(13, DmaMemprotectErr, &edmaMemprotectErrParams, &eb);
Hwi_Params_init(&edmaErrorParams);
edmaErrorParams.priority = -1;
edmaErrorParams.maskSetting = Hwi_MaskingOption_SELF;
edmaErrorParams.enableInt = TRUE;
Error_init(&eb);
Hwi_create(14, DmaError, &edmaErrorParams, &eb);
Hwi_enableInterrupt(14);
Hwi_enableInterrupt(13);
Hwi_enableInterrupt(12);
Hwi_enable();
SetupEdma ();
EDMA3SetEvt(SOC_EDMA30CC_0_REGS, EDMA3_MEMTSTEVT);
Task_sleep(500);
do {
/* Loop on complete of the IPR bits (base plus 1068 for 1 = completed) */
status = EDMA3GetIntrStatus(SOC_EDMA30CC_0_REGS);
if (status != 0) { /* ANY int status every show up???? */
UARTprintf("Int status is %04x\n",status);
/* Use ICR (base + 1070) to clear */
EDMA3ClrIntr(SOC_EDMA30CC_0_REGS,EDMA3_MEMTSTEVT);
}
Task_sleep(50);
} while (1);
}
void SetupEdma () {
EDMA3CCPaRAMEntry paramSet;
EDMAModuleClkConfig();
/* This set a 1:1 mapping between the channel number and the PaRAM sets
* Then sets ALL the registers to quenum, sets the global "regionID" to 0,
* cleans up all the event flags */
EDMA3Init(SOC_EDMA30CC_0_REGS, EVT_QUEUE_NUM);
/* Enable the EESR for event 12 */
EDMA3EnableDmaEvt(SOC_EDMA30CC_0_REGS, EDMA3_MEMTSTEVT);
/* Enables the channel in the shadow region (is only 0 anyway)
* yet another mapping of the channel to the queue number ( as did in "EDMA3Init)
* Enable the event interrupt
*/
/* Request DMA Channel and TCC */
EDMA3RequestChannel(SOC_EDMA30CC_0_REGS, EDMA3_CHANNEL_TYPE_DMA,
EDMA3_MEMTSTEVT, EDMA3_MEMTSTEVT, EVT_QUEUE_NUM);
/* Now create the PaRAM settings */
/* Fill the PaRAM Set with transfer specific information */
paramSet.srcAddr = (unsigned int) gSrcBuffer;
paramSet.destAddr = (unsigned int) gDstBuffer;
if ((paramSet.destAddr & 0x1F) != 0) {
UARTprintf("Address Alignment Issue (not on 256 bit page)\n"); // For FIFO mode, destAddr must be a 256-bit aligned address. i.e. 5 LSBs should be 0.
return;
}
paramSet.aCnt = 0x7fff; /* 32767 bytes */
paramSet.bCnt = 8; /* Do it in 8 blocks */
paramSet.cCnt = 1; /* Total of 1 time */
paramSet.srcBIdx = paramSet.aCnt;
paramSet.destBIdx = paramSet.aCnt;
paramSet.srcCIdx = 0; /* No jumps of the C index, because we don't */
paramSet.destCIdx = 0;
paramSet.linkAddr = 0xFFFF; /* Address for linking (AutoReloading of a PaRAM Set) A value of 0xFFFF means no linking */
paramSet.bCntReload = 0; // Only relevant for A-sync transfers (we are doing AB sync) ;
/* OPT PaRAM Entries. */
paramSet.opt = 0x00000000u;
/* Source and Destination addressing modes are Incremental. */
paramSet.opt |= EDMA3CC_OPT_DAM; /* Destination is "FiFo" with depth of 1 */
paramSet.opt |= EDMA3CC_OPT_SAM; /* Destination is "FiFo" with depth of 1 */
/* Setting the Transfer Complete Code(TCC). */
paramSet.opt |= ((EDMA3_MEMTSTEVT << EDMA3CC_OPT_TCC_SHIFT) & EDMA3CC_OPT_TCC);
/* Enabling the Completion Interrupt. */
paramSet.opt |= EDMA3CC_OPT_TCINTEN;
/* Transfer synchronization dimension. Specify AB-synchronized. Each event
* triggers the transfer of BCNT arrays of ACNT bytes
*/
paramSet.opt |= EDMA3CC_OPT_SYNCDIM;
/* Now write the PaRAM Set */
EDMA3SetPaRAM(SOC_EDMA30CC_0_REGS, EDMA3_MEMTSTEVT, ¶mSet);
}
Any assistance on this would be appreciated.





