4

I use serialport component in c# and it works well! But the question is how can it be faster to handle high speed (e.g. 2 Mbps) data transfers.

As I have researched about this, I have found that memory can be accessed directly (using DMA like this link ). Can anybody tell me how can I define and use it in my application?

Hamzahfrq
  • 696
  • 1
  • 6
  • 25
Mohammad Gohari
  • 241
  • 3
  • 12

3 Answers3

8

No, the [c#] tag puts this a million miles out of reach. The code snippet on that web page is not real, it is just a "pattern". It does things you cannot do in C#, like handling interrupts, obtaining the physical memory address of buffers, directly programming the device registers. On the kind of machines that can execute C# code, not counting the Micro Framework, this can only be done by device drivers.

It would be the kind of code that could run on a micro-controller, the kind of processor that doesn't run with a protected-mode operating system. Even then it is stretch, it invokes DMA by unstated magic, never actually starting the transfer on a transmit for example. No sign of a DMA controller either, required to arbitrate bus access between devices. It is fake code.

When you use real hardware you always get a device driver with it that takes care of talking to the device. If the device actually supports DMA, very unusual, then the device driver programmer would not avoid using it. The SerialPort class you use in a C# program uses the operating system api, one that's universal for any kind of serial port device. It passes your I/O requests to the device driver to get the job done.

The interface between the operating system api and the device driver is covered by IOCTLs. This MSDN page documents the ones for Windows. There's a pretty close match between the IOCTLs and the api, the api layer is pretty thin. When you take a closer look, it will be obvious that none of them have anything to do with DMA. They can't, it is strictly a driver implementation detail.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Thanks Hans Passant for your complete answer. the device i've connected to is my product. it's packet contains million samples data that i can't process them quickly, i use FT232R USB UART Driver to talk with windows. you mean that i write mine driver? if answer is true, how can i write my driver to connect with device and do my data process before interfering CPU? – Mohammad Gohari Jun 09 '15 at 04:06
  • "How do I write a driver" is a question you can't get an answer for here. It takes a book, they've been written, I recommend Walter Oney's. Fwiw, you don't need a serial port driver at all, that chip uses USB on the host side. The driver *emulates* a serial port, makes it easy to use from a program. – Hans Passant Jun 09 '15 at 08:44
  • Do you suggest me to research about Directx (Like webcam readers)? – Mohammad Gohari Jun 12 '15 at 17:06
  • No, this doesn't have anything to do with graphics. You are not ready for this, keep it on the shelf until you learn a lot more. What you have already works fine, it doesn't need any improvement. – Hans Passant Jun 12 '15 at 17:10
  • i configured the direct memory access (DMA) channel of the XMEGA in my microcontroller progrmam as i had learned here: [CONFIG DMACHx](http://avrhelp.mcselec.com/index.html?config_dmachx.htm) and now i transfer data directly over memory!! what is next step??!! – Mohammad Gohari Jun 12 '15 at 19:16
  • Asked and answered. Educate yourself. You're not ready yet for Walter Oney, you need to understand the way computers work better. Important to grasp the difference between graphics, USB and serial ports first. You can't get it from using a configuration program nor from poking at random Internet web pages. If reading books isn't your preference then formal education in a school is never a bad idea. – Hans Passant Jun 12 '15 at 19:34
1

I believe you don't need to make serial access any faster, and instead tune your c# application to handle the data transfer faster. Run a profiler of your choice and measure what percentage of time is spent in serialport component's methods. I predict that will be quite low, meaning any efforts towards making serialport faster will be spent in vain.

Codeguard
  • 7,787
  • 2
  • 38
  • 41
  • thanks Codeguard. My application is a simple one that just has a event to receive data and a function to process data. depend on machine speed, i have various data loss! – Mohammad Gohari Jun 09 '15 at 03:53
  • 1
    You still need to run a profiler to make sure. Sometimes the problem is quite non-obvious. – Codeguard Jun 09 '15 at 08:26
1

You got it completelly wrong.

First of all, you are in an environment in which you don't have direct access to hardware (Windows), so something like you described is basically impossible without writing a kernel driver (and you don't want to, belive me).

Second, the operating system and it's drivers are already very optimized, if it needs to use DMA transfers it should already do it.

Third, you will not get those speeds unless your serial controller supports it, and they usually don't, a PC's RS232 controller is normally up to 115200bauds but some controllers get up to 1Mb.

But there is another option, go USB without USB :D

From your question I suppose you're interfacing some type of microcontroller with a PC and you don't want to program an USB driver for the controller (or it doesn't have the capability of USB), so a very good option is to use an RS-232 to USB cable, those usually supports very fast speeds, I personally have used the FTDI RS-232 3v3 and it gets up to 3Mb (http://www.ftdichip.com/Support/Documents/DataSheets/Cables/DS_TTL-232R_CABLES.pdf).

On the end you will be programming a normal serial port code but it will use the more extended USB interface (it's another advantage, not all PC's today come with a serial port).

After that, to really benefit from the speed up, remember to set to the port a very big read/write buffer (at least 1Mb), do a non-blockin receiving routine and send big chuncks of data (which must fit in the write buffer).

Remember that your device must match the same speed as selected, so, if you set it to 2-3Mbps your device must run the serial interface at the exact same speed.

Here is an example of the receiving part of what I described:

    SerialPort sp;
    Queue<byte[]> buffer = new Queue<byte[]>();
    AutoResetEvent dataAvailable = new AutoResetEvent(false);
    Thread processThread;

    public void Start()
    {
        //Start the processing thread
        processThread = new Thread(ProcessData);
        processThread.Start();

        //Open the serial port at 3Mbps and with buffers of 3Mb
        sp = new SerialPort("COM12", 3145728, Parity.None, 8, StopBits.One);
        sp.ReadBufferSize = 1024 * 1024 * 3;
        sp.WriteBufferSize = 1024 * 1024 * 3;
        sp.DataReceived += sp_DataReceived;
        sp.Open();
    }

    //This thread processes the stored chunks doing the less locking possible
    void ProcessData(object state)
    {

        while (true)
        {

            dataAvailable.WaitOne();

            while (buffer.Count > 0)
            {

                byte[] chunk;

                lock (buffer)
                    chunk = buffer.Dequeue();

                //Process the chunk here as you wish

            }

        }

    }

    //The receiving function only stores data in a list of chunks
    void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        while (sp.BytesToRead > 0)
        { 
            byte[] chunk = new byte[sp.BytesToRead];
            sp.Read(chunk, 0, chunk.Length);

            lock (buffer)
                buffer.Enqueue(chunk);

            dataAvailable.Set();
        }
    }
Gusman
  • 14,905
  • 2
  • 34
  • 50
  • thanks Gusman. my code is same as yours(using thread,buffer and list) – Mohammad Gohari Jun 12 '15 at 16:56
  • when i process the chunk, it works so slowly depends on speed of CPU & Hardware compatibility. I think i should use some low-level Application Programming Interfaces (like Directx for video). – Mohammad Gohari Jun 12 '15 at 17:04
  • A `Queue` would be more appropriate instead of having to call `List.RemoveAt` on each access. And then a `ConcurrentQueue` would also remove the need for locking. – vgru May 06 '16 at 15:33
  • Yes @Groo, you're right, that's just a "professional deformation", I used lists for so many years that sometimes I forget about other generic collections more suitables for concrete tasks :) – Gusman May 06 '16 at 16:33