Implementing audio delay using SSI and DMA

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Implementing audio delay using SSI and DMA

Jump to solution
1,610 Views
RValls
Contributor III


Hello everybody!

I need to implement an audio delay for 8 audio channels. The audio format is TDM, meaning 8 slots per frame, using only one RX pin and one TX pin.

Right now, I am already receiving and transmitting the 8 channels, by using two eDMA channels, one for the reception and one for the transmission of the data.

The eDMA channels are configured to work automatically, without intervention of the uC.

The implementation just consists in having a buffer of N audio frames (each one consisting in the 8 audio channel slots). The receiver DMA channel stores continuously into this buffer, and the transmitter DMA channel reads continuously from this buffer.

The problem is that, for implementing a different delay per audio channel, I need that the receiver DMA channel stores each audio sample in a different frame, thus when the transmitter DMA channel reads the frames continuously, each one of the slots will be effectively delayed.

So, I think it can be done by having the receiving DMA channel to use the scatter feature, and configuring 8 different TCDs, forming a circular linked list, each one containing the offset to apply to each slot.

In order to make this work, I have to set up the DMA channel to have only one minor loop iteration, and only one major loop iteration, so each transaction will trigger a TCD change.

In order to take one step at a time, I have managed to make the basic RX-DMA-Memory and Memory-DMA-TX work. Now, the next step would be to make the RX-DMA-Memory work with only one iteration, and the last step would be to make it work with the scatter feature.

Here comes the problem. When I set the RX-DMA to have only one major loop iteration, the system stops working. If it has any other iteration count (two, four, eight...) everything works fine.

My RX-DMA configuration is as follows:

#define DMA_CHANNEL_RX 1

#define DMA_CHANNEL_TX 2

#define TDM_SAMPLE_SIZE 4

#define alignment 128

tcd=(edma_tcd_t*)&DMA0->TCD[DMA_CHANNEL_RX];

tcd->SADDR=(uint32_t)&I2S0->RDR[0];

tcd->SOFF=0;

tcd->ATTR=DMA_ATTR_SMOD(0) | DMA_ATTR_SSIZE(kEDMA_TransferSize4Bytes)

  | DMA_ATTR_DMOD(alignment) | DMA_ATTR_DSIZE(kEDMA_TransferSize4Bytes);

tcd->NBYTES= TDM_SAMPLE_SIZE;

tcd->SLAST=0;

tcd->DADDR=(uint32_t)&tdm->frames[tdm->rx+tdm->delay[0]][0];

tcd->DOFF=TDM_SAMPLE_SIZE;

tcd->CITER=2; //If set to 1 iteration, it stops working

tcd->BITER=2; //If set to 1 iteration, it stops working

tcd->DLAST_SGA=0;

tcd->CSR= 0

  | DMA_CSR_MAJORLINKCH(DMA_CHANNEL_RX)

  | DMA_CSR_MAJORELINK_MASK

  ;

Does somebody faced a similar problem?

I am using the KSDK v2.0, and a Kinetis K64 uC.

Thank you very much for your help, it is really appreciated,

Best regards,

Ruben

0 Kudos
1 Solution
961 Views
RValls
Contributor III

After several tests, with the linked TCDs is not possible without the intervention of the CPU, since the DMA does not update the TCD, so each time it reloads again the same addresses, without updating them after each transaction.

So my solution in the end has been pretty similar, but instead of using TCDs, using different DMA channels, so after each audio slot, each DMA channel performs a copy to memory and, when it finishes, it executes the next channel. Now I'm using:

- 1 DMA channel for reception.

- 8 DMA channels for copy from input buffer to the actual memory.

- 1 DMA channel for transmission.

It works pretty fine.

Thank you very much,

Best regards,

Ruben

View solution in original post

0 Kudos
3 Replies
962 Views
RValls
Contributor III

After several tests, with the linked TCDs is not possible without the intervention of the CPU, since the DMA does not update the TCD, so each time it reloads again the same addresses, without updating them after each transaction.

So my solution in the end has been pretty similar, but instead of using TCDs, using different DMA channels, so after each audio slot, each DMA channel performs a copy to memory and, when it finishes, it executes the next channel. Now I'm using:

- 1 DMA channel for reception.

- 8 DMA channels for copy from input buffer to the actual memory.

- 1 DMA channel for transmission.

It works pretty fine.

Thank you very much,

Best regards,

Ruben

0 Kudos
962 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi,

Currently, you use DMA to transfer the SAI receiver data register to a memory buffer, the buffer memory will be like this:

slot0/slot1/slot2/slot3/slot4/slot5/slot6/slot7/slot0/slot1/slot2...

But for the transmitter, if you use DMA to transfer data in the above buffer to SAI transmitter register, and want to set up different delay for each slot, because the address  in the buffer implies the delay,  it means that you need select the address in the buffer to transfer. If you use DMA, because DMA is inflexible to select the position in the buffer, I suggest you use interrupt mode to transfer data in the buffer to SAI transmitter register. In the transmitter ISR, you can  know the current slot, and select the data in the buffer and write to SAI transmitter register. Even if you scatter/gather mode of DMA to implement your scheme, I think you have to use CPU to poll the DMA status, change the TCD.major.linkch field as a TCD indentification by cpu.

Hope it can help you.

BR

Xiangjun Rong

0 Kudos
961 Views
RValls
Contributor III

Hi Xiangjun,

I was having an issue with the CITER, not being able to set it to 1, but found that it didn't worked fine if CITER=1 and having the channel LINKING to itself.

I changed to CITER=1 and LINK to another channel, and now it works fine (don't know why, but now it works :smileygrin: )

Now, I want to implement the delay as follows:

- 1 DMA channel for receive data from SSI into an intermediate buffer. This buffer is big enough to hold two entire frames, thus acting like a ping-pong buffer. The buffer is aligned, so I can use the DMA module feature.

- 1 DMA channel for copying the data in the intermediate buffer into their corresponding place in memory. I want to do this with no CPU intervention by setting up 8 linked TCDs, each one holding its destination address calculated with the channel delay. The destination memory is also aligned, in order to also be able to use the DMA modulo feature.

- 1 DMA channel for transmit data from the memory to the SSI.

Now I am stuck setting up the DMA channel for copying data using linked TCDs.

May you show me some example?

Best regards,

Ruben

0 Kudos