Abstract:
Some applications use real-time data, such as those in audio, radar, and sonar processing. For real-time applications, blocks of data must be processed within a set amount of time. This data must also be received from some source. To input real-time data in a Gedae flow graph, a function box must be created which encapsulates the driver for the appropriate I/O device.
Problem:
For real-time applications, Gedae has to collect and process a block of data within a certain time constraint avoiding errors or dropping data.
Solution:

Maximizing processor usage results in minimizing system cost. By overlapping DMA data transfers and processing, processor usage is kept high.
This example works only on specific embedded systems. Slight system specific changes were made. Parts of the code examples were replaced with pseudo code.
| File location: FGlibraries/boxes/real_time/v_dev_input |
| Name: v_dev_input Type: static Comment: "Receive real-time input from an device. N_out == the vector size of the outputs. N_input == the vector size of the I/O data block" Input: { int N_out; int N_input; } Local: { int needs_to_fire; /* number of vectors of real-time data to collect */ int fired; /* current vector being collected */ } Output: { stream float out1[N_out]; stream float out2[N_out]; } Include: { #include < e_dev_input.h > /* found in ~/gedae/include/embeddable */ } Reset: { init_dev_input(N_input); /* register interrupt handlers */ needs_to_fire = 0; fired = 0; } Apply: { int progress = 0; if (needs_to_fire == 0) { /**** BEGINNING NEW EXECUTION OF FUNCTION ****/ needs_to_fire = size(out1)/N_out; /* calculate the firing granularity */ fired = 0; } while (needs_to_fire) { |
 
Notice there are no direct references to the Sharc system. Hiding all the Sharc specific calls in the underlying functions (init_dev_input() and read_dev_input()) is recommended. These functions are prototyped in the header file e_dev_input.h (from the Include method). Also, in the Apply method the firing granularity is checked to see if multiple real-time data sets are to be processed as one large block. This allows for transparent scalability.
 
| File location: ~/gedae/include/embeddable/e_dev_input.h |
| #ifndef __e_dev_input_h_ #define __e_dev_input_h_ void init_dev_input(int N_input); #endif |
 
 
| File location: ~/gedae/source/embeddable/e_dev_input.c |
| static int BUFFER_SIZE; static float *CURRENT_BUFFER; /* handle to global buffer */ static float *DEVICE_INPUT_BUFFER1; /* global buffer1 */ static float *DEVICE_INPUT_BUFFER2; /* global buffer2 */ static int DATA_READY; /* used to indicate if data is ready */ void init_dev_input(int N_input) { /**** SET TO: NO DATA IS AVAILABLE YET ****/ /**** REGISTER "I/O HAS DATA READY" INTERRUPT HANDLER ****/ /**** REGISTER "DMA COMPLETE" INTERRUPT HANDLER ****/ |
When the "SIG_DEV_DATA_READY" interrupt occurs, "read_iodev_handler" gets called. The handler starts a DMA that copies the real-time data into one of the double buffers. Since the DMA processes in the background, the handler can exit right away, allowing normal processing to continue. When the DMA transfers complete, the interrupt "SIG_DMA_COMPLETE" occurs. The "dma_done_handler" sets the "DATA_READY_FLAG". The following is the code for the interrupt handler:
| /**** READ DATA FROM THE REAL-TIME INPUT DEVICE ****/ static void read_iodev_handler(void) { /**** HANDLE THE DOUBLE BUFFERING ****/ if (CURRENT_BUFFER == DEVICE_INPUT_BUFFER1) { CURRENT_BUFFER = DEVICE_INPUT_BUFFER2; } else { CURRENT_BUFFER = DEVICE_INPUT_BUFFER1; } /**** GET INPUT FROM REAL TIME IO DEVICE ****/ /**** DMA DONE INTERRUPT HANDLER ****/ |
| /**** CALLED FROM THE RESET METHOD ****/ int read_dev_input(float *out1, float *out2, int N_out) { if (!DATA_READY) { /**** DATA NOT READY ****/ return 0; } else { float *buffer = CURRENT_BUFFER; /**** DATA IS READY ****/ /**** DO ANY PRELIMINARY PROCESSING HERE ****/ return 1; /* success */ |
List of pseudo functions:
The follow functions and data are definitions of the pseudo code used above.
interrupt_handler(SIGNAL, (*handler()));
Register an interrupt handler based on a signal.
SIG_DEV_DATA_READY
This is an interrupt signal flag indicating
when the I/O device has data that is ready to be transferred to memory.
SIG_DMA_COMPLETE
This is an interrupt signal value that represent
when the DMA engine has finished moving the requested data.
start_dma(source_addr, dest_addr, size);
This is like memcpy() but uses a DMA in the
background that runs in parallel with the Sharc processor.
input_device_addr
This is a handle to the I/O device that contains
the real-time data.
Example of a real-time algorithm designed with Gedae:
If you have Gedae installed, to view the flowgraph and this trace table type from the <user_gedae> / <host> directory:
gedae -file appnotes/real_time/real_time -events demo
Application Note last updated 3/24/98