I am developing an acquisition device which requires DMA operation to transfer large data frames to the main memory. For now I am assuming the destination is a contiguous memory region so I am allocating it (say 1 MB) at boot time as described in section "Do-it-yourself allocation" from ldd2-ch13. The driver can then access that region by calling ioremap().
The current system works as follows:
A memory-mapped control register enables a user-space application to Start/Stop the device
Upon start, the device begins to transfer the acquired data to the assigned memory region continuously (and circularly) at ~8MB/s.
- The reserved memory region has the size of two frames in order to employ a double-buffering technique.
- Once a complete frame has been transferred, the device triggers an interrupt.
I have developed a simple char driver which provides a blocking read() function so that the user-space can read a new data frame every time an interrupt is received.
After running a few tests, I realized that the user-space application misses some frames when running the following code:
for(i=0;i<NUM_FRAMES;i++) {
read(dev_d,buf,FRAME_SIZE);/*Read frame*/
for(j=0;j<FRAME_SIZE;j++) /*File dump*/
fprintf(fp,"%d",buf[j]);
fprintf(fp,"\n");
}
I suspect that the application's process is being put to sleep between two subsequent reads, allowing the device to rewrite the memory location which should have already been read.
Since I have no experience in kernel development I would like to know how is the correct way to implement a driver for such a device in order to ensure synchronization. Basically I am trying to implement a simple shared memory communication for a real-time acquisition device and I need to guarantee that the OS is able to read all the acquired data frames.
read()
rate has to be as fast as that frame rate. Your "file dump" loop is not efficient. This is a classic real-time problem: you have to process the data faster than it arrives, or buffer that data. Network interfaces increase double-buffering to N-buffers or rings. Maybe you'll have to also use multithreading, i.e. a dedicated input thread that always has a pendingread()
request. – sawdustsplice()
solution? Is that some way to enable the driver to directly write to a specific file without any user-space intervention? – zmlread()
. The "novice mistake" you're making is not realizing the cycles consumed by performing inefficient I/O. Tryfprintf()
ing just the first 4 bytes, and see if there's still skipped frames. Then evaluate what kind of actual processing needs to be done, and how long that might take per frame. Make sure you have a workable top-level scheme or the big picture before you worry about implementation details. – sawdustfprintf()
just for debugging, or are you personally going to be reviewing this data in realtime? Why can't you write each of these frames as one block of 512-bytes of raw binary data rather than convert each byte to decimal in precious realtime? That's what I mean about the "big picture": if you're going to save the frames, just save it raw, and then convert it offline or a low-priority background process. "Do you know..." -- I have to admit ignorance aboutsplice()
. "read a whole a frame..." -- It's your driver; you tell us how/when a read request is satisfied! – sawdust