DAVE app I2S002: Get two channel I2S TX working in DMA mode

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
Not applicable
Hi, I am using the DAVE app I2S002 with the XMC4500 Relax Kit board. What I try to do is to get half-duplex I2S TX with DMA with both audio channels (right/left) working. Currently I see only I2S data on the left I2S channel. The right channel data frame is always high (or low depending on the SCTR.PDL bit setting). Both the frame width and data width are set to 16 bit, which should be correct. SCLKOUT is 1.5 MHZ and SELOX (WCLK) is 48 kHz.

I guess that I only get left channel I2S TX data has something to do with the DMA configuration or DMA itself, because when I switch to the I2S002 app setting half-duplex I2C TX without DMA I can see audio data on both the left and the right channel. During my research on the configuration settings for DMA I didn't find a solution for my problem.

I would be really grateful if you could help me on this. In XMC4500's manual I can't find a solution to this problem. Please let me know if you need any specific information from me.
0 Likes
6 Replies
Not applicable
Hi,

How did you configure the DMA and how did the transfer is trigger?
Do you trigger a transfer on one channel and another transfer for the other channel?
0 Likes
Not applicable
Let me explain the configuration a bit more detailed.
I use 32 bit of audio data (16 bit left, 16 bit right channel). I thought that this way I could transfer right and left channel data at the same time.

uint32_t __attribute__((aligned(32))) TXBuf[]={0x0, 0xf990f99, 0x21212121, 0x2ff32ff3, 0x40004000, 0x4d084d08, 0x5a825a82, 0x64dd64dd, 0x6ed96ed9, 0x75d375d3, 0x7ba37ba3,
0x7ec17ec1, 0x7fff7fff, 0x7f0b7f0b, 0x7ba37ba3, 0x76ad76ad, 0x6ed96ed9, 0x66396639, 0x5a825a82, 0x4ece4ece, 0x40004000, 0x32033203, 0x21212121,
0x11d011d0, 0x0, 0xf068f068, 0xdee0dee0, 0xd00ed00e, 0xc001c001, 0xb2f9b2f9, 0xa57fa57f, 0x9b249b24, 0x91289128, 0x8a2e8a2e, 0x845e845e, 0x81408140,
0x80018001, 0x80f680f6, 0x845e845e, 0x89548954, 0x91289128, 0x99c899c8, 0xa57fa57f, 0xb133b133, 0xc001c001, 0xcdfecdfe, 0xdee0dee0, 0xee31ee31};


I left the DMA configuration as it was generated by the I2S002 app. I tried a to tweak a few things, but as I didn't help I always reset them as they were before. The DMA transfer is configured to be triggered by the I2S peripheral. I assume it gets triggered depending on the filling level of IN or TBUF which in turn should depend on how fast the data gets sent out to the I2S bus. You see below, that I write into IN, which means that I use the Transmit FIFO which in turn writes into TBUF.

        /* Configure destination address */
Handle->TxDMAHandle->ChConfig.DstAddress = (uint32_t)&(Handle->I2SRegs->IN[0]);
Handle->TxDMAHandle->ChannelEnabled = TRUE;
Handle->TxDMAHandle->HWHandshakeEnable = TRUE;
Handle->TxDMAHandle->ChConfig.TransferFlow = DMA_MEM2PRF_DMA;
Handle->TxDMAHandle->ChConfig.SrcMSize = DMA_MSIZE_8;
Handle->TxDMAHandle->ChConfig.DstMSize = DMA_MSIZE_8;
Handle->TxDMAHandle->ChConfig.SrcInc = DMA_ADDR_INCREMENT;
Handle->TxDMAHandle->ChConfig.DstInc = DMA_ADDR_NOCHANGE ;
Handle->TxDMAHandle->ChConfig.LinkedListPtr = TX_LINKED_LIST_PTR;
Handle->TxDMAHandle->ChConfig.ChPriority = DMA_PRIORITY_0;
Handle->TxDMAHandle->ChConfig.TransferType = DMA_LLIST_SAR_RELOAD_DAR;

/* Configure DMA transfer width and block size as per word length selected */
if(Handle->Config.WordWidth <= 8U)
{
Handle->TxDMAHandle->ChConfig.SrcTrWidth = DMA_TRANS_WIDTH_8;
Handle->TxDMAHandle->ChConfig.DstTrWidth = DMA_TRANS_WIDTH_8;
Handle->TxDMAHandle->ChConfig.BlockSize = (Handle->DynamicData->TxBuf.BufferSize/2U);
}
else
{
Handle->TxDMAHandle->ChConfig.SrcTrWidth = DMA_TRANS_WIDTH_16 ;
Handle->TxDMAHandle->ChConfig.DstTrWidth = DMA_TRANS_WIDTH_16;
Handle->TxDMAHandle->ChConfig.BlockSize = (Handle->DynamicData->TxBuf.BufferSize/4U);
}

/* Initilialize the DMA channel */
Status = DMA002_SetChannelTransferParams(Handle->TxDMAHandle, &(Handle->TxDMAHandle->ChConfig));

if(Status != DAVEApp_SUCCESS)
{
Status = I2S002_DMA_ERROR;
Handle->DynamicData->I2SStatus = I2S002_FAIL;
DBG002_ERROR(DBG002_GID_I2S002,Status, 0, NULL);
break;
}

/* Configure Source Address for Tx DMA Handle */
Handle->TxDMAHandle->ChConfig.SrcAddress = (uint32_t)TxPPBuffer[0].StartAddrs;
DMA002_AddLLItem(&TxListHead,&TxPPB[0],&(Handle->TxDMAHandle->ChConfig));

/* Configure Source Address for Tx DMA Handle */
Handle->TxDMAHandle->ChConfig.SrcAddress = (uint32_t)TxPPBuffer[1].StartAddrs;
DMA002_AddLLItem(&TxListHead,&TxPPB[1],&(Handle->TxDMAHandle->ChConfig));

/* Create the Linked List */
TxPPB[1].llp = (uint32_t)&TxPPB[0];

DMA002_SetListener((Handle->TxDMAHandle),&I2SDmaTxListener,(uint32_t)Handle);
Status = DMA002_StartTransfer(Handle->TxDMAHandle);
if(Status != DAVEApp_SUCCESS)
{
Status = I2S002_DMA_ERROR;
Handle->DynamicData->I2SStatus = I2S002_FAIL;
DBG002_ERROR(DBG002_GID_I2S002,Status, 0, NULL);
break;
}

/* Enable standard transmit buffer interrupt */
WR_REG(Handle->I2SRegs->TBCTR,(uint32_t)USIC_CH_TBCTR_STBIEN_Msk, USIC_CH_TBCTR_STBIEN_Pos,(uint32_t)0x01U);

/* Enable WA generation */
SET_BIT(Handle->I2SRegs->PCR_IISMode, USIC_CH_PCR_IISMode_WAGEN_Pos);
Handle->DynamicData->I2SStatus = I2S002_STATE_STREAMING;

SrcBufPtr8 = (uint8_t*)CurrentTxBufPtr->StartAddrs;
SrcBufPtr16 = (uint16_t*)CurrentTxBufPtr->StartAddrs;

/* Trigger transmit interrupt */
SRno = (((uint32_t)Handle->I2SRegs->TBCTR & USIC_CH_TBCTR_STBINP_Msk) >> USIC_CH_TBCTR_STBINP_Pos);

/* Trigger standard transmit interrupt by setting FMR.SIOx bit */
Handle->I2SRegs->FMR |= ((uint32_t)(0x01U << (USIC_CH_FMR_SIO0_Pos + SRno)));
break;

My approach was to try to copy the full 32 bits of data at each transfer. So I tried to change this configuration:

Handle->TxDMAHandle->ChConfig.SrcTrWidth = DMA_TRANS_WIDTH_16 ;
Handle->TxDMAHandle->ChConfig.DstTrWidth = DMA_TRANS_WIDTH_16;
Handle->TxDMAHandle->ChConfig.BlockSize = (Handle->DynamicData->TxBuf.BufferSize/4U);


To this:

Handle->TxDMAHandle->ChConfig.SrcTrWidth = DMA_TRANS_WIDTH_32 ;
Handle->TxDMAHandle->ChConfig.DstTrWidth = DMA_TRANS_WIDTH_32;
Handle->TxDMAHandle->ChConfig.BlockSize = (Handle->DynamicData->TxBuf.BufferSize/8U);


But I still see only left channel audio data. Also in the debugger I see that the higher 16 bit of TBUFx are not filled. I am new to the DMA topic at least for the XMC4500. Maybe I chose the completely wrong approach and I should copy only 16 bit of data at a time, but only twice as often. Probably there is some limitation that allows me to copy only 16 bit of data at a time? As the TBUFx registers are 32 bit wide I assumed that it must be possible somehow to copy 32 bits at once (even with DMA).
0 Likes
Not applicable
One thing that confuses me a bit is that there are buffer registers TBUF00 to TBUF31 that have the higher 16 bits reserved so only 16 bit values can be written into them. On the other hand there is this common TBUF register. Here all 32 bits can be used. Maybe I've missed something when reading the manual, but currently that doesn't really make sense to me.
0 Likes
Not applicable
Hi,

All TBUF[00 - 31] are 16-bit wide, the 00 - 31 is basically the value generated for Transmit Control Information (TCI) when you place data into different TBUF.
Actually whichever TBUF[xx] you place, is practically the same Transmit buffer.
So if you place 32-bit data into the TBUF, the upper 16-bit of data will be truncated.
I guess this is why you only transfer the data for one side.
0 Likes
Not applicable
Thank you for your answer. I managed to make it work now. It was critical to understand what TCI is used for and how it maps to the different INx (or TBUFx) registers.

It was also important for me to understand what expressions like TBUF[15:0] actually mean:

In this case, data written to TBUF[15:0] (or IN[15:0]
if a FIFO data buffer is used) is considered as left channel data, whereas data written to
TBUF[31:16] (or IN[31:16] if a FIFO data buffer is used) is considered as right channel
data.


This means TBUF0 - TBUF15, not the bits 0 - 15 of the TBUF registers like I thought before. This confused me very much at the beginning. Especially as the manual itself explicitly uses the [] syntax also for register bits.

When the extent of register fields, groups register bits, or groups of pins are
collectively named in the body of the document, they are represented as
“NAME[A:B]”, which defines a range for the named group from B to A.


Probably the manual should be a bit more explicit in this aspect. Anyway, thank you very much for your assistance.
0 Likes
Not applicable
Hi thowe,

Thanks for your valuable feedback.
I will inform the reference manual author regarding your feedback and see how we can further improve our manual in future.
0 Likes