This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
OK, I upload the project here to see if I get more luck with the answers.
Are you using the dma to get data to/from the SD card? That might help aleviate the cpu loading. You might want to look into using a data pipe from bios to help aleviate the sometimes long response time of the sd card. We've got an SD card based Digital Audio Recorder that runs on the ezdsp5535 doing 48Khz stereo, so with the right amount of buffering, you can get the throughput you need.
Just how long are the delays that you are trying to implement?
-S
Thanks for the reply!
Yes, I am using DMA for the SD card but without callback functionality, I got worse performance in callback mode.
For one use I would need short delays from 0 up to several seconds. But additionally I would like to be able to store long loops of up to several minutes.
Your idea of using a data pipe sounds good, the issue will probably be to compensate the delay induced by the data pipe, and in that case I guess there could be problems with the shortest delays.
Maybe you can use a traditional circular buffer for the shorter delays or make your own data pipe construct in a large contiguous block of memory that would give you access to x(k-n), for any n vs. being limited to the FIFO behavior of the BIOS pipe which would create a fixed delay (latency) of x(k-N), where N is total size of your pipe
i.e. N=(K*FRAMESIZE), where K is the number of frames in your pipe.
In your original post you mentioned i2s Tx interupt, as well as a Rx dma interrupt. Are you using the dma for all i2s traffic or just the received side? Is the Rx and Tx running at the same sample rate?
Thanks a lot for the recommendations.
I actually use a circular buffer to read from RX ping-pong buffer and to write to SD card, and another bigger circular buffer to read in anticipation from SD card and to get the delayed samples and write to Tx pingpong buffer.
For i2s I basically use the same scheme used in the ezDSP5535 Connected Audio Framework, that is DMA with callback in Rx provided by the i2s bios driver library and a Tx interrupt controlled by BIOS dispatcher. Should I use DMA in Tx too? The DMA Tx function (I2S_DmaTxCallBack in ddc_i2s.c) looks quite complex and is not used at all, there is an #if 0 in the code provided by TI.
It is in the Tx interrupt where I can easily detect underflows of the Tx ping-pong buffer. During the first minute or so I have lots of underflows I guess because the CPU is getting very loaded. After a minute or so the load of KNL_swi and Idl_busyObj is misteriously exchanged and I don't see any underflows. It's quite weird. That is using a sampling frequency of 16kHz. At 48kHz I get underflows constantly.
Since my pingpong buffers have 64 samples and SD card buffers are 256 samples, there are 4 Tx / Rx interrupts for every buffer read/write in SD card. The audio function has pending semaphores from i2s Rx and Tx. The MMC/SD function is pending on a sempahore from the audio function posted when four Rx buffers are ready. MMC/SD funtion actually posts two semaphores: one after SD write, and another one after SD read.
The audio function is pending on those 2 sempahores every 4 Rx buffers, but there is a delay of 2 buffers between them. I did this in order to balance the load and avoid underflows when there is a lot of SD activity.
What version of the CAF are you using? I've used that once, but am not too familar with it. The framework we use is BIOS and CSL based, doesn't have the additional layer that the ddc_is2.c dda_i2s.c etc. provide.
It is surprising that the CAF framework is using DMA for Codex Rx but not for Codec Tx, although you mention that there is a Tx ping pong buffer, so I guess i'm a bit confused. If the adc and dac sample rates are the same, it is possible to just use the DMA interrupt from the Rx side only, but actually process the Rx and Tx dma/buffers in the same isr (or callback), since the Rx interrupt will always slightly follow the Tx interrupt. Maybe this is what the CAF is doing.
In the end, I think you need to provide an interface layer (pipes or large buffers) between the SD card operation and the audio Codec operation so that they are not so syncronous in nature (i.e. remove the heavy handshaking that is going on with the semaphores) and instead think of it as two somewhat independent tasks (1) Audio Process Tsk that at the sample rate is going to put a frame of adc data into a ADC pipe and read a frame of dac data from a DAC pipe. (2) An sd process that is going to pull a frame of adc data from the ADC pipe and write it to the sd and read a frame of dac data from the sd card and put it to the DAC pipe.
Task (1) is dictated by the sample rate, a realtime contstraint; Task (2) is going to run as fast as it can whenever there is data in available in the ADC pipe or whenever there is room in the DAC pipe.
A while ago, (2003) TI published a book "Express DSP for Dummies" that laid out the above mentioned framework. I don't know if this book is around anymore but the authors are Steve Blonstein and Maher Katorgi. The ISBN number is 0764524887. with ti part number SPRW142
You also might want to try larger frame sizes (larger than the 64 you are using), this might eleviate some of the overhead of all the tasks switching in and out. The sd card can support a "multi-sector" write, i.e. you can write more than 512 byte to it at a time.
PS. Is this a work project, school project or hobby project? (just curious)
-S
Hello, thanks again for you useful recommendations.
I am using CAF 01.52.01.00.
In the original code there is a circular buffer that feeds the Tx interrupt.
I think the reason for using sample by sample interrupt in Tx is related to the use of ASRC on the playback function from USB. I found this comment in the code, regarding I2S Tx DMA:
/* Configuration untested since ASRC only works with I2S in sample-by-sample mode */
I am trying to make work DMA on Tx, but the untested code is not working very well. It is not exactly the same as the Rx DMA, it actually has separate ping and pong buffers, and the DMA Interrupt service routine, swaps the ping and pong buffers and starts a DMA transfer, I am trying to make it simpler and more similar to the Rx DMA, where DMA handles automatically the ping pong buffer, but since the playback (codec Tx) is stereo the routine is called twice.
In order to avoid excessive load issues and for easier testing I disable the SD card routine and I just connect the input to the output, but for now I must have synchronization issues.
I will check on that book you mention it looks interesting, thanks again.
Regarding frame size, original frame sizes were 1ms, (48 samples at 48kHz), I changed them to 64 samples since it was a divisor of SD card minimum buffer size (512 bytes, or 256 samples), but I would prefer not to increase them a lot since that will add undesirable latency to the output audio samples.
This is a hobby project, at least for now, I have always loved DSP. As a hobby I love music and audio. I am a HW engineer, so I am struggling a bit dealing with SW coding and BIOS.
For stereo Tx using dma in ping pong mode, you'll need a two ping pong buffers, one for the LeftChannel and one for the RightChannel. Set these both up for interrupt mode and when you get to the DMA ISR, you'll see in the DMAIFR that both Left and Right DMAs are done (ready), so you can process them in one interrupt. That processing can be a simple as a memcpy of the new Left and Right Dac data into the available ping pong buffer (based on the "last transfer" field of the dma) or you can post a semaphore or swi to run a secondary task. Try to make whatever functionality you have in the DMA ISR as short as possible.
Incidently, if your hobby budget can handle it, for about $400 you can buy a 5515 EVM which has 128Meg of SDRAM so you could probably do your whole project without using an SDCard for its extra storage capacity.
-S
OK I have finally been able to configure automatic TX DMA with ping-pong buffer for both channels. Performance has improved considerably. 48 KHz sampling seems feasible with a 20% CPU load. SD card write process can have longer delays sometimes and in this cases CPU load increases over 60% or even 80% and then I get underflows in th RX DMA.
I wanted to add a data pipe but I saw on the BIOS manual that PIP module is not recommended because is going to be deprecated in future versions of the BIOS, also data pipes are not blocking, and I thought that some kind of blocking mechanism should exist in order to let other tasks take place, so I decided to use SIO module. For some reason, unknown to me, SIO module is greyed out in my TConf tool on CCSv5 (BIOS 5.42.0.07).
I could try the pipe, but I don't know how to add a blocking mechanism without a semaphore. I'm stuck again.
We've typically done this using pipes and an assocaited semaphore, using the "notifyReader/Writer" functions to post a semaphore. For example on adc to SD path (from the converter to the SD card) the pipe notify reader function will post a "write data to disk" semaphore & the "write to disk task" function will pend that same semaphore when it finished. This approach is based on that older "reference frameworks" architecture I mentioned in my previous post.
Not sure why the SIO module is greyed out. It is also greyed out in ccs v4.2 & bios v5.41
Hi Diego,
I am also trying to achieve the same thing, using ezDSP5535 to loopback audio while writing the audio data to SD card. Even though I am using DMA for audio input/out as well as SD card (and using semaphores and SIO in DSP/BIOS), the audio output has frequent breaks and pops. How did you go about solving this issue?
Sorry for the late answer.
Having Tx as well as Rx DMA is very important, but I think that is already your case.
The other thing I did is increasing the size of the DMA ping pong buffers, which adds latency to the real effect and requires more RAM memory utilization, so a compromise has to be made here.
And I also increased the size of the buffers in the SDcard.
I didn't use SIO, just buffers and semaphores. The TX task just waits for the TX DMA semaphore and writes output data into Tx DMA ping pong buffers.
The RX task waits for RX DMA ping pong buffer to be ready and writes the ping pong buffer data into another buffer twice the size of the SDcard buffer. When half of this buffer is full it sends a semaphore to indicate to the SDcard write task that it can write the data into SD card.
The RX task also processes SD card read buffer, once the read buffer has been processed it sends a sempahore to the SD card read task. I actually use a mailbox to pass the pointer to the SD card read task, because the size of the ping pong buffers is smaller than the size of the SD card buffers.