问题
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?
回答1:
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.
回答2:
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.
回答3:
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();
}
}
来源:https://stackoverflow.com/questions/30499210/using-dma-to-access-high-speed-serial-port