Hi,
I have written code for memory to memory transfer using eDMA. When Channel(4) is started the channel is not becoming active and transfer is not happening.
Also channel/configuration errors are not seen here. I have attached my code files(DMAfiles.zip), and also snap shots of TCDs.
Configured the eDMA controller based on LS1046A Reference manual.
Is anyone has any idea or suggestion on my code?
Is there any other configuration i have to do to make it work?
I believe DMAMUX is not required to configure for memory to memory transfer, as there is no information in the datasheet.
Thanks in advance.
#include "dma.h"
#define _DMA_C_
void DMA_Start_Chan(unsigned char Chan);
void DMA_ChanDisable(unsigned char Chan);
void DMA_Check_Status(unsigned char Chan, DMA_Chan_Status_t * status);
void Set_DMA_Mux(unsigned char PeripheralSrc, unsigned char Chan, unsigned char MuxN);
void Clear_DMA_Mux(unsigned char PeripheralSrc, unsigned char Chan, unsigned char MuxN);
unsigned int Little_To_Big_Endian(unsigned int num);
void ClearAllOtherTCDs(void);
void TestDMA1(void);
void Configure_DMA_TCD(DMA_TCD_Struct_t * tcd, unsigned char TCD_num);
DMA_TCD_Struct_t TransCntrlDescr;
const unsigned int tempCst[5]={0,32,64,96,128};
unsigned int SRC_addr[5000]={0};
unsigned int DST_addr[5000];
const unsigned int TCDChannelsConfigured[32]={0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
/********************************************************************************************
********************************************************************************************/
void TestDMA1(void)
{
volatile unsigned int *DMA_TCD_Reg = (volatile unsigned int *)DMA_TCD_START_ADDR;
unsigned char TCD_num=0;
DMA_Chan_Status_t DMA_status;
unsigned int i=0;
TCD_num = 4;
Clear_DMA_Mux(63,TCD_num,1);
/* The Round robin arbitration is enabled. */
*(unsigned int *)DMA_CR = Little_To_Big_Endian((unsigned int)0x0000000C);
/* before updating the TCD, ensure the channel request is disabled */
DMA_ChanDisable(TCD_num);
TransCntrlDescr.SourceAddr = (unsigned int)((unsigned long long)&SRC_addr[0] & 0x00000000FFFFFFFF);
TransCntrlDescr.Word1.Word1_BitFields.SrcAddrModulo = (unsigned int)0;
TransCntrlDescr.Word1.Word1_BitFields.SourceSize = (unsigned int)2;/* 2-> 32bit, 3-> 64bit*/
TransCntrlDescr.Word1.Word1_BitFields.DestAddrModulo = (unsigned int)0;
TransCntrlDescr.Word1.Word1_BitFields.DestSize = (unsigned int)2;/* 2-> 32bit, 3-> 64bit*/
TransCntrlDescr.Word1.Word1_BitFields.SignedOffset = (unsigned int)4;/* 4 bytes to get incremented every read*/
TransCntrlDescr.Word2.NBytes = (unsigned int) 64; /* Number of bytes to transfer */
TransCntrlDescr.LastSourceAddrAdjst = (unsigned int) -64;
TransCntrlDescr.DestAddr = (unsigned int)((unsigned long long)&DST_addr[0] & 0x00000000FFFFFFFF);
TransCntrlDescr.Word5.Word5_BitFields.CITER_E_Link = (unsigned int)0;
TransCntrlDescr.Word5.Word5_BitFields.CITER_or_LinkCH = (unsigned int)0;
TransCntrlDescr.Word5.Word5_BitFields.CITER = (unsigned int)2;/*Major loop count is 1 */
TransCntrlDescr.Word5.Word5_BitFields.DestOffset = (unsigned int)4;/* 4 bytes to get incremented every write*/
TransCntrlDescr.LastDestAddrAdjst = (unsigned int) 64;
TransCntrlDescr.Word7.Word7_BitFields.BITER_E_Link = (unsigned int)0;
TransCntrlDescr.Word7.Word7_BitFields.BITER_or_LinkCH = (unsigned int)0;
/* CITER and BITER value should be same. This represents the major loop count to
indicate how many time the minor loop needs to be repeated */
TransCntrlDescr.Word7.Word7_BitFields.BITER = (unsigned int)2;
TransCntrlDescr.Word7.Word7_BitFields.BWC = (unsigned int)0;
TransCntrlDescr.Word7.Word7_BitFields.Reserved = (unsigned int)0;
TransCntrlDescr.Word7.Word7_BitFields.Major_LinkCH = (unsigned int)0;
TransCntrlDescr.Word7.Word7_BitFields.Done = (unsigned int)0;
TransCntrlDescr.Word7.Word7_BitFields.Active = (unsigned int)0;
TransCntrlDescr.Word7.Word7_BitFields.Major_E_Link = (unsigned int)0;
TransCntrlDescr.Word7.Word7_BitFields.E_SG = (unsigned int)0;
TransCntrlDescr.Word7.Word7_BitFields.D_Req = (unsigned int)0;
TransCntrlDescr.Word7.Word7_BitFields.INT_Half = (unsigned int)0;
TransCntrlDescr.Word7.Word7_BitFields.INT_Maj = (unsigned int)0;
TransCntrlDescr.Word7.Word7_BitFields.Start = (unsigned int)0;
/* Get the TCD address to configure. Each TCD structure is 32 bytes in length */
DMA_TCD_Reg = (volatile unsigned int *)(DMA_TCD_START_ADDR + ((unsigned int)32 * TCD_num ));
/* Place all the 32 bits value into DMA TCD address*/
*DMA_TCD_Reg = Little_To_Big_Endian((unsigned int) TransCntrlDescr.SourceAddr);
DMA_TCD_Reg++;
*DMA_TCD_Reg = Little_To_Big_Endian((unsigned int) TransCntrlDescr.Word1.FullWord1);
DMA_TCD_Reg++;
*DMA_TCD_Reg = Little_To_Big_Endian((unsigned int) TransCntrlDescr.Word2.NBytes);
DMA_TCD_Reg++;
*DMA_TCD_Reg = Little_To_Big_Endian((unsigned int) TransCntrlDescr.LastSourceAddrAdjst);
DMA_TCD_Reg++;
*DMA_TCD_Reg =Little_To_Big_Endian((unsigned int) TransCntrlDescr.DestAddr);
DMA_TCD_Reg++;
*DMA_TCD_Reg = Little_To_Big_Endian((unsigned int) TransCntrlDescr.Word5.FullWord5);
DMA_TCD_Reg++;
*DMA_TCD_Reg = Little_To_Big_Endian((unsigned int) TransCntrlDescr.LastDestAddrAdjst);
DMA_TCD_Reg++;
*DMA_TCD_Reg = Little_To_Big_Endian((unsigned int) TransCntrlDescr.Word7.FullWord7);
ClearAllOtherTCDs();
*(unsigned int *)DMA_ERQ = Little_To_Big_Endian((unsigned int)0x00000000);
*(unsigned int *)DMA_EEI = (unsigned int)0x00000000;
*(volatile unsigned char *)DMA_CINT = (unsigned char)0x40;/* clears all interrupts*/
/* If error is present, then clear it*/
if(*(volatile unsigned int *)DMA_ERR)
{
*(volatile unsigned int *)DMA_ERR = (unsigned int)0xFFFFFFFF;
}
/* Setting mux is not required for memory to memory transfer. Also the reference manual
does not give any detailed information on what to set if memory to memory transfer for DMAMUX
Set_DMA_Mux(63,TCD_num,1);*/
DMA_Start_Chan(TCD_num);
while(1)
{
i++;
if(i==0xFFFFFFFF)
{
DMA_Check_Status(TCD_num, (DMA_Chan_Status_t *)&DMA_status);
}
}
}
/********************************************************************************************
********************************************************************************************/
/* Starts the specified DMA channel */
void DMA_Start_Chan(unsigned char Chan)
{
volatile unsigned char *DMA_SetEnableReqReg = (volatile unsigned char *)DMA_SERQ;
volatile unsigned int *DMA_TCRnCSR_Reg = (volatile unsigned int *)DMA_TCD_START_ADDR/*DMA_SSRT*/;
/* Set the required DMA channel per the parameter in the DMA_SERQ register to start the channel */
*DMA_SetEnableReqReg = (unsigned char)(Chan & (unsigned char)0x1F);
*(volatile unsigned int *)DMA_ERQ = Little_To_Big_Endian((unsigned int) (1 << Chan));
/* to point the last 32 bit of TCD structure*/
DMA_TCRnCSR_Reg =(volatile unsigned int *) (DMA_TCD_START_ADDR + (unsigned int)(Chan * ((unsigned int)32)) + (unsigned int)28);
*DMA_TCRnCSR_Reg |= 0x00000100;
#if 0
/* Request the channel service by placing TRUE in the START bit , this is software initiated request.
If DMA is configured for any hardware request, then below register is not necessary to update*/
*DMA_TCRnCSR_Reg = (unsigned char)(Chan & (unsigned char)0x1F);
#endif
}
/********************************************************************************************
********************************************************************************************/
/* Clears the specified DMA channel */
void DMA_ChanDisable(unsigned char Chan)
{
volatile unsigned char *DMA_ClearEnableReqReg = (volatile unsigned char *)DMA_CERQ;
/* Set the required DMA channel per the parameter in the DMA_SERQ register to start the channel */
*DMA_ClearEnableReqReg = (unsigned char)(Chan & (unsigned char)0x1F);
*(volatile unsigned char *)DMA_CDNE = (unsigned char)(Chan & (unsigned char)0x1F);
}
/********************************************************************************************
********************************************************************************************/
void Configure_DMA_TCD(DMA_TCD_Struct_t * tcd, unsigned char TCD_num) /* TCD0 to TCD31*/
{
volatile unsigned int *DMA_TCD_Reg = (volatile unsigned int *)DMA_TCD_START_ADDR;
/* before updating the TCD, ensure the channel request is disabled */
DMA_ChanDisable(TCD_num);
/* Get the TCD address to configure. Each TCD structure is 32 bytes in length */
DMA_TCD_Reg = (volatile unsigned int *)(DMA_TCD_START_ADDR + ((unsigned int)32 * TCD_num ));
/* Place all the 32 bits value into DMA TCD address*/
*DMA_TCD_Reg = Little_To_Big_Endian((unsigned int) tcd->SourceAddr);
DMA_TCD_Reg++;
*DMA_TCD_Reg = Little_To_Big_Endian((unsigned int) tcd->Word1.FullWord1);
DMA_TCD_Reg++;
*DMA_TCD_Reg = Little_To_Big_Endian((unsigned int) tcd->Word2.NBytes);
DMA_TCD_Reg++;
*DMA_TCD_Reg = Little_To_Big_Endian((unsigned int) tcd->LastSourceAddrAdjst);
DMA_TCD_Reg++;
*DMA_TCD_Reg =Little_To_Big_Endian((unsigned int) tcd->DestAddr);
DMA_TCD_Reg++;
*DMA_TCD_Reg = Little_To_Big_Endian((unsigned int) tcd->Word5.FullWord5);
DMA_TCD_Reg++;
*DMA_TCD_Reg = Little_To_Big_Endian((unsigned int) tcd->LastDestAddrAdjst);
DMA_TCD_Reg++;
*DMA_TCD_Reg = Little_To_Big_Endian((unsigned int) tcd->Word7.FullWord7);
}
/********************************************************************************************
********************************************************************************************/
void DMA_Check_Status(unsigned char Chan, DMA_Chan_Status_t * status)
{
volatile unsigned int *DMA_TCRnCSR_Reg = (volatile unsigned int *)DMA_TCD_START_ADDR;
unsigned int Value =0;
/* to point the last 32 bit of TCD structure*/
DMA_TCRnCSR_Reg = (unsigned int *)(DMA_TCD_START_ADDR + (unsigned int)(Chan * 32) + (unsigned int)28);
/* Get the DONE and ACTIVE flag bit state */
Value=*DMA_TCRnCSR_Reg;
status->Done = (unsigned char)((Value & 0x00000080) >> 7);
status->Active = (unsigned char)((Value & 0x00000040) >> 6);
status->ChannelError = *(volatile unsigned int *)DMA_ERR;
}
/********************************************************************************************
********************************************************************************************/
/* Peripheral source will range from 0 to 63, Channels are 0 to 15, MuxN is 1 or 2 */
void Set_DMA_Mux(unsigned char PeripheralSrc, unsigned char Chan, unsigned char MuxN)
{
volatile unsigned char *DMAMUX1_CHCFG = (volatile unsigned char *) DMAMUX1_BASE_ADDR;
volatile unsigned char *DMAMUX2_CHCFG = (volatile unsigned char *) DMAMUX2_BASE_ADDR;
/* Triggered mode is disabled here*/
if(MuxN == 1)
{
DMAMUX1_CHCFG = (volatile unsigned char *)(DMAMUX1_BASE_ADDR + (Chan & (unsigned char)0x0F));
*DMAMUX1_CHCFG = (unsigned char)((unsigned char)0x80 | (PeripheralSrc & (unsigned char)0x3F));
}
else if (MuxN == 2)
{
DMAMUX2_CHCFG = (volatile unsigned char *)(DMAMUX2_BASE_ADDR + (Chan & (unsigned char)0x0F));
*DMAMUX2_CHCFG = (unsigned char)((unsigned char)0x80 | (PeripheralSrc & (unsigned char)0x3F));
}
else
{
/* wrong request*/
}
}
/********************************************************************************************
********************************************************************************************/
/* Peripheral source will range from 0 to 63, Channels are 0 to 15, MuxN is 1 or 2 */
void Clear_DMA_Mux(unsigned char PeripheralSrc, unsigned char Chan, unsigned char MuxN)
{
volatile unsigned char *DMAMUX1_CHCFG = (volatile unsigned char *) DMAMUX1_BASE_ADDR;
volatile unsigned char *DMAMUX2_CHCFG = (volatile unsigned char *) DMAMUX2_BASE_ADDR;
if(MuxN == 1)
{
DMAMUX1_CHCFG = (volatile unsigned char *)(DMAMUX1_BASE_ADDR + (Chan & (unsigned char)0x0F));
*DMAMUX1_CHCFG = (unsigned char)(*DMAMUX1_CHCFG & (unsigned char)0x7F);
}
else if (MuxN == 2)
{
DMAMUX2_CHCFG = (volatile unsigned char *)(DMAMUX2_BASE_ADDR + (Chan & (unsigned char)0x0F));
*DMAMUX2_CHCFG = (unsigned char)(*DMAMUX2_CHCFG & (unsigned char)0x7F);
}
else
{
/* wrong request*/
}
}
unsigned int Little_To_Big_Endian(unsigned int num)
{
return (((num >> 24) & 0x000000ff) | ((num >>
}
void ClearAllOtherTCDs(void)
{
unsigned int i=0;
*(volatile unsigned char *)DMA_CDNE = (unsigned char)0x40;
for(i=0;i<32;i++)
{
TransCntrlDescr.DestAddr = TransCntrlDescr.DestAddr + (unsigned int)64;
if(TCDChannelsConfigured[i] == 0)
{
Configure_DMA_TCD(&TransCntrlDescr,i);
}
}
}
Regards,
Ganesh
Hi,
Thank you for your response. Through TRACE32 (debugger) seen the eDMA module control register content and TCD content, both looks fine. here are the snaps (snaps are also included as part of previous attachment).
Memory dump.
Referring the QorIQ LS1046A Reference Manual, 18.4.3 TCD structure please check that addresses of all pairs of 16-bit TCD registers in your code are as follows:
DMA_TCDn_SOFF has address 0x2C0_1006
DMA_TCDn_ATTR has address 0x2C0_1004
etc.
Hi,
Thank you for your response. Through TRACE32 (debugger) seen the eDMA module control register content and TCD content, both looks fine. here are the snaps (snaps are also included as part of previous attachment).
Channel(4) TCD
Memory Dump: Channel(4)
Hi,
Here is the requested data.
Memory dump for Channel(4) TCD before setting the TCD_CSR START bit:
16bit Memory dump.
32bit Memory dump.
Memory dump for Channel(4) TCD after setting TCD_CSR START bit:
16bit Memory dump
32bit Memory dump
The above memory dump is with respect to the code I have shared originally here. The section 18.4.5 in the reference manual says about the endianness for TCD structure and it matches here.
Based on the recent suggestion from one of the thread in the forum (QorIQ LS1046A DMAMUX no always-enabled/on slot DMA source config information in the reference manual) which is not documented in the reference manual actually. DMAMUX peripheral source 63 is configured (for enabling always enabled slot) and then observed the behavior using the same software. I did not see data transfer happening still, but saw errors present in the DMA_ES register for channel 4 after setting START bit. The errors were popped for following.
DAE – Destination Address Error
DOE – Destination Offset Error
SBE- Source Bus Error
I have tried modifying the SSIZE and DSIZE as 0 (8bit transfer), still that does not work, it throws the error for NCE - NBYTES/CITER Configuration Error in the DMA_ES register.
Please let me know what could be the issue.
Excuse me, but it already was written:
Referring the QorIQ LS1046A Reference Manual, 18.4.3 TCD structure please check that addresses of all pairs of 16-bit TCD registers in your code are as follows:
DMA_TCDn_SOFF has address 0x2C0_1006
DMA_TCDn_ATTR has address 0x2C0_1004
etc.
Thanks. After alligning 16-bit register, i was able to see eDMA transferring data. Following things need to take care if you are implementing eDMA transfer.
1. For memory to memory transfer, DMAMUX should be configured with 63 value (which is Always enabled source). It is also there in the "QorIQ LS1046A DMAMUX no always-enabled/on slot DMA source config information in the reference manual".
2. If you are using TRACE32, then it wont show values correctly for eDMA peripheral registers. As 16-bit registers are not aligned.