hello,
I am using the system services and driver model to write a driver for the AD5663 DAC. I am building it upon the ADI sport driver with DMA using a two dimensional "ping pong" buffer. The idea is to fill one subbuffer, while the DMA transfere the other. This works fine, but I see a potensial problem in the way I get DMA events in my interrupt callback. The only event i get is the ADI_DEV_EVENT_SUB_BUFFER_PROCESSED. I never see the ADI_DEV_EVENT_BUFFER_PROCESSED. I had hoped to be able to determine which subbuffer the DMA had completed this way. My next approch was to use the pointer to the buffer received in the callback, but this pointer allways points to the start of the whole buffer, so there is no indication of what buffer that is actually processed. By examining system services source (adi_dma.c) I see the the following statements which I belive confirms my observation:
// CASE (circular)
case ADI_DMA_MODE_CIRCULAR:
// determine if it's an inner loop interrupt or an outer loop interrupt
if (pChannel->Config->b_DI_SEL == ADI_DMA_DI_SEL_OUTER_LOOP) {
Event = ADI_DMA_EVENT_OUTER_LOOP_PROCESSED;
} else {
Event = ADI_DMA_EVENT_INNER_LOOP_PROCESSED;
}
// override the pArg callback parameter to be the buffer start address
pArg = pChannel->StartAddr;
break;
Should i use another DMA model in my case? Is there a way to be absolutely sure that my program is syncronized to the DMA buffer handling? When I stop the transfere, will the DMA be re-initialised to start with a clean buffer structure or may it start in the subbuffer?
mads-l
Hi,
I believe, in your case, chained or chained loopback dataflow mode would be much more suitable than circular mode.
Circular Mode:
Circular mode is suitable for steady, continuous dataflow, where the entire data fits in a 64K byte maximum contiguous block of memory. The memory is considered to be one single buffer, but the DMA can be configured to generate callback (ADI_DEV_EVENT_SUB_BUFFER_PROCESSED event) after processing equally sized smaller packets called a sub-buffer. This event can be used to keep in track of number of bytes processed by DMA, which in turn can be used to calculate the address of the sub-buffer that was processed.
Chained Loopback mode:
Two 1D buffers can be chained and operated in 'ping-pong' fashion. The device driver posts a callback (ADI_DEV_EVENT_BUFFER_PROCESSED) event whenever a buffer gets processed. Application can specify the 1D buffer address as callback parameter and get the processed buffer address passed as callback argument (*pArg). Application can simply read/write data from/to the processed buffer. Because loopback is used, the application never needs to re-supply the buffer to the driver, since the driver continually loops through the same set of buffers. In this mode, the buffers can/must be submitted only when the device (DMA) dataflow is disabled. The DMA registers are configured only once based in the 1D buffer field settings, since the same set of buffers are re-used. This method is suitable for steady, continuous dataflow.
Chained mode:
This mode is almost similar to Chained loopback mode, except that the application can submit a new set of buffer(s) even when the device (DMA) dataflow is enabled. The submitted buffers are sent or received by the DMA only once and the processed buffer is handed back to the application inside its callback function with ADI_DEV_EVENT_BUFFER_PROCESSED event. This mode is much suitable for packet-based data that may be sent and/or received in a non-continuous or "bursty" manner.
Attached file contains code snippet that shows how to configure and operate a device in chained/chained loopback mode using 'ping-pong' buffer.
Hope this helps.
Regards,
Bala.
Hi Bala,
I find very useful your answer and I've been able to write a working example with ping-pong buffer and Chained Loopback Mode.
But I have two questions:
Is this an expected behaviour?
Chained Loopback mode:
...
The DMA registers are configured only once based in the 1D buffer field settings, since the same set of buffers are re-used. This method is suitable for steady, continuous dataflow
but which DMA channels are used? And how can I use different DMA channels for SPORT read and write?
Your example is really useful, because unfortunately I wasn't able to find any information on how to use System Services to configure and use SPORTs
Thanks
vix
Hi Vix,
when the ADI_DEV_EVENT_BUFFER_PROCESSED is generated for the first time, both the DataBuffer0 and DataBuffer1 are already full. The pArg parameter is oPingBuffer, and so DataBuffer0 is processed inside the callback. The second time, the DataBuffer0 is filled with new data, but pArg is oPongBuffer, and so DataBuffer1 is processed.
Is this an expected behaviour?
Yes. This is the expected behaviour of a ping-pong buffer. The reason you see both data buffers full could be due to
a) Size of the data buffer. I guess the buffer is small enough to be filled by the time the DMA manager passes the callback to application
And/or
b) DMA Streaming must have enabled - which means that the DMA continues filling in the next buffer in chain regardless of a callback posted to application or not. Enabling this mode is trivial to get the maximum DMA performance, especially for Audio and Video data exchange.
SPORT driver uses the default DMA channel mapped by the hardware (as mentioned in the Hardware Ref Manual - DMA section). You can change the default DMA mappings by using 'ADI_DEV_CMD_SET_OUTBOUND_DMA_CHANNEL_ID' and 'ADI_DEV_CMD_SET_OUTBOUND_DMA_CHANNEL_ID' with the DMA channel ID as command specific value. List of DMA channel id supported by a processor is available in DMA manager header file (adi_dma.h). Please note that the DMA channel id can not be changed after issuing a set dataflow method command.
Our Blackfin Software Development Kit contains applications that use SPORT for audio playback. You can download it for free from http://sdk.analog.com/dw/sdks.aspx?file=LSI3
Regards,
Bala.
I've already thought about this possibility, and I increased a lot the buffer size, but the second buffer was filled.
I looked again at your example, but I don't find the instruction that enables the DMA streaming. Is this a default setting?
Then I have another question that is driving me crazy: I modified your example and I have a working example performing SPORT0 acquisition.
Then I integrated this working code into a VDK example (the INET example supplied by ADI) and the SPORT0 acquisition doesn't work anymore.
The ADI_DEV_EVENT_BUFFER_PROCESSED is generated, but the DataBuffer0 and DataBuffer1 content is completely wrong.
Moreover the first time this event is generated, the first 4 elements of buffer DataBuffer0 haven't been updated by DMA (and DataBuffe1 is completely filled).
Is your example supposed to work with VDK?
Thanks
vix
Hi,
as you are having problems incorporating your Device Driver into an LwIP application, I would recommend that you take a look at EE-332 "Building Complex VDK/LwIP Applications Using Blackfin Processors". This Engineer to Engineer Note provides guidelines for incorporating other System Peripherals into an LwIP application, managing resources when doing so, and avoiding common pitfalls customers encounter when combining LwIP and other Device Drivers. EE-332 is available from the following link:
http://www.analog.com/ee-notes
regards,
Craig.
I would recommend that you take a look at EE-332 "Building Complex VDK/LwIP Applications Using Blackfin Processors".
I think the Application Note number is wrong: the correct one is EE-312.
I've already read this documents, and other ones without help.
But I think I fount the reason of the problem: I must force placing of DataBuffer0 and DataBuffer1 to L1 memory.
In the VDK example, the linker placed these buffer to external SDRAM and this doesn't work.
Is this a mandatory setting to have SPORT0 RX working?
Hi again,
you are correct; I gave the wrong EE-Note number in my previous reply. As you have seen it is EE-312 that I meant. Regarding the placement of the SPORT buffers in L1 - the SPORT driver does not have an explicit requirement that buffers should be placed in L1 memory.
What seems more likely in this case is that when the buffers were in SRAM there was some contention between LwIP SDRAM accesses (LwIP uses SDRAM for it's heap and stack), and the SDRAM access to the SPORT buffers. It is likely that the SPORT access may be blocking LwIP access to SDRAM to the point where there is an overflow of traffic, or vice versa.
If you would like us to help further to determine the cause of the problem when the buffers are in SDRAM, we would need a little more information regarding your setup: use of data and instruction cache, what are you using SPORT for, etc. If possible, it would be beneficial to take a look at your code.
If you are unable to post your project here, you can contact us via private support and include a link to this thread:
http://www.analog.com/processors/support
regards,
Craig.