EDT DMA Library


Detailed Description

The DMA library provides a set of consistent routines across many of the EDT products, with simple yet powerful ring-buffered DMA (Direct Memory Access) capabilities.

A DMA transfer can be continuous or noncontinuous:

Note:
When developing applications for EDT Digital Video boards such as the PCI DV and PCI DV C-Link, it is recommended that programmers use the higher level EDT Digital Video Library.

For portability, use the library calls edt_reg_read, edt_reg_write, edt_reg_or, or edt_reg_and to read or write the hardware registers, rather than using ioctls.

Elements of EDT Interface Applications

Applications that perform continuous transfers typically include the following elements:

  1. The preprocessor statement:
     #include "edtinc.h" 
    
  2. A call to edt_open to open the device. This returns a pointer to a structure that represents the EDT board in software. All subsequent calls will use this pointer to access the board.
  3. Optionally, setup for writing a file or some other target for the data to be acquired.
  4. A call to edt_configure_ring_buffers to configure the ring buffers.
  5. A call to start the DMA, such as edt_start_buffers.
  6. Data processing calls, as required.
  7. A call to edt_close to close the device.
  8. Appropriate settings in your makefile or C workspace to compile and link the library file libedt.c.

Example

 #include "edtinc.h"
 main()
 {
     EdtDev *edt_p = edt_open("edt", 0) ;
     char *buf_ptr; int outfd = open("outfile", 1) ;
     // Configure a ring buffer with four 1MB buffers 
     edt_configure_ring_buffers(edt_p, 1024*1024, 4, EDT_READ, NULL) ;
     edt_start_buffers(edt_p, 0) ; // 0 starts unlimited buffer DMA

     // This loop will capture data indefinitely, but the write() (or
     // other data processing) must be able to keep up. 
     while ((buf_ptr = edt_wait_for_buffers(edt_p, 1)) != NULL)
          write(outfd, buf_ptr, 1024*1024) ;

     edt_close(edt_p) ;
 }

Applications that perform noncontinuous transfers typically include the following elements:

  1. The preprocessor statement:
     #include "edtinc.h" 
    
  2. A call to edt_open to open the device. This returns a pointer to a structure that represents the EDT board in software. All subsequent calls will use this pointer to access the board.
  3. Optionally, setup for writing a file or some other target for the data to be acquired.
  4. A system read() or write() call to cause one DMA transfer.
  5. Data processing calls, as required.
  6. A call to edt_close to close the device.
  7. Appropriate settings in your makefile or C workspace to compile and link the library file libedt.c.

Assuming that a multichannel Xilinx firmware file has been loaded, this example opens a specific DMA channel with edt_open_channel:

 #include "edtinc.h"
 main()
 {
     EdtDev *edt_p = edt_open_channel("edt", 1, 2) ;
     char buf[1024] ;
     int numbytes, outfd = open("outfile", 1) ;

     // Because read()s are noncontinuous, without hardware
     // handshaking, the data will have gaps between each read().
     while ((numbytes = edt_read(edt_p, buf, 1024)) > 0)
         write(outfd, buf, numbytes) ;
  
     edt_close(edt_p) ;
 }

You can use ring buffer mode for real-time data capture using a small number of buffers (typically 1 MB) configured in a round-robin data FIFO. During capture, the application must be able to transfer or process the data before data acquisition wraps around and overwrites the buffer currently being processed. The example below shows real-time data capture using ring buffers, although it includes no error-checking. In this example, process_data(bufptr) must execute in the same amount of time it takes DMA to fill a single buffer, or faster.

 #include "edtinc.h"
 main()
 { 
   EdtDev *edt_p = edt_open("edt", 0) ;
 
   // Configure four 1 MB buffers:
   // one for DMA
   // one for the second DMA register on most EDT boards
   // one for "process_data(bufptr)" to work on
   // one to keep DMA away from "process_data()"
   //
   edt_configure_ring_buffers(edt_p, 0x100000, 4, EDT_READ, NULL) ;
   edt_start_buffers(edt_p, 0) ; // 0 starts unlimited buffer DMA 
   for (;;)
   {
       char *bufptr ;
       // Wait for each buffer to complete, then process it.
       // The driver continues DMA concurrently with processing.
       // 
       bufptr = edt_wait_for_buffers(edt_p, 1) ;
       process_data(bufptr) ;
   }
 }

Check compiler options in the EDT-provided makefiles.

Multithreaded Programming

The EDT driver is thread-safe, with the following constraints:

  1. Because kernel DMA resources are allocated on a per-thread basis and must be allocated and released in the same thread, perform all DMA operations in the same thread as edt_open and edt_close with respect to each channel. Other threads can open the same channel concurrently with DMA, but must perform no DMA-related operations.
  2. To avoid undefined application or system behavior, or even system crashes, when exiting the program:


Modules

 Startup / Shutdown
 These functions are used to open and close the EDT device.
 Initialization
 FIFO Flushing
 First-in, first-out (FIFO) memory buffers are used to smooth data transmission between different types of data sinks internal to EDT boards.
 Input/Output
 These functions are used to perform and control DMA transfers.
 Register Access
 Register access functions.
 Utility
 Utility functions.


Generated on Mon May 12 16:39:07 2008 by  doxygen 1.5.1