FEZ Mini serial speed without RLP

Hi,

I am using serial port to communicate with PC at baud rate 115200, the PC sends 9.6k bytes per second (~1000 messages per second of small 8-10 byte messages), the code uses serial port “datareceived” event, the parsing code is an efficient state machine with most of the variables are general & static (saw the GC fires up every several seconds but don’t think this is relevant much)
the main thread “sleep(1)” and i used the “serialbuffer” class found in this forum for the actual port reading

i am getting around~280 messages (1/4!) of the messages, any ideas on how to improve the code?

Liran

Welcome to the community!

Every several (?) seconds is certainly relevant. Post your code and we’ll be able to help you more.

Using code tags will make your post more readable. This can be done in two ways:[ol]
Click the “101010” icon and paste your code between the

 tags or...
Select the code within your post and click the "101010" icon.[/ol]
(Generated by QuickReply)

attached below are relevant pieces from the code (ones i can post), let me know what you think
now (after further reading) i think that

  1. i should cancel the sleep in the main thread since i am using events/interrupts anyway
  2. i should use a better buffer class, preferably a circular buffer without any copying or moving

PS-sorry about the previous post (button got pressed…)

serial buffer class from one of the repies in the forum

 
 public class SerialBuffer
    {
        private byte[] m_Buffer;
        private int m_StartIndex;
        private int m_EndIndex;

        public SerialBuffer(int Size)
        {
            m_Buffer = new byte[Size];
            m_StartIndex = 0;
            m_EndIndex = 0;
        }

        public int DataSize
        {
            get
            {
                return m_EndIndex - m_StartIndex;
            }
        }

        public byte[] Buffer
        {
            get
            {
                return m_Buffer;
            }
        }

        private void ShiftBuffer()
        {
            Array.Copy(m_Buffer, m_StartIndex, m_Buffer, 0,DataSize);
            m_EndIndex = DataSize;
            m_StartIndex = 0;
        }
  
        private void ExpandBuffer(int NewSize)
        {
            byte[] NewBuffer = new byte[NewSize];
            Array.Copy(m_Buffer, m_StartIndex, NewBuffer, 0, DataSize);
            m_Buffer = NewBuffer;
            m_EndIndex = DataSize;
            m_StartIndex = 0;
        }

        public void DeleteFromStart(int BytesCount)
        {
            Array.Copy(m_Buffer, BytesCount, m_Buffer, 0, DataSize);
            m_EndIndex = DataSize-BytesCount;
            m_StartIndex = 0;
        }
        public void EmptyBuffer()
        {
            m_StartIndex = 0;
            m_EndIndex = 0;
        }

        public void LoadSerial(SerialPort Port)
        {

            int BytesToRead = Port.BytesToRead;

            if (m_Buffer.Length < m_EndIndex + BytesToRead)
            {
                if (m_Buffer.Length - DataSize >= BytesToRead)
                    ShiftBuffer();
                else
                    ExpandBuffer(DataSize + BytesToRead);
            }

            Port.Read(m_Buffer, m_EndIndex, BytesToRead);
            m_EndIndex += BytesToRead;
        }
    }

main routine

 
        public static void Main()
        {
            Debug.EnableGCMessages(false);

            InterruptPort button1 = new InterruptPort((Cpu.Pin)FEZ_Pin.Digital.LDR,true,Port.ResistorMode.PullUp,Port.InterruptMode.InterruptEdgeHigh);
            button1.OnInterrupt += new NativeEventHandler(OnButtonPressed);


            Thread.CurrentThread.Priority = ThreadPriority.Highest;

            pCOM1 = new SerialPort("COM1", 115200);
            pCOM1.ReadTimeout = 0;
            pCOM1.Handshake = Handshake.None;
            pCOM1.DataReceived += new SerialDataReceivedEventHandler(COM1_HandleRX);
            pCOM1.Open();
            pCOM1.Flush();
            
            pCOM2 = new SerialPort("COM2", 57600);
            pCOM2.Open();

            while (true)
            {
                Thread.Sleep(1);
            }
        }

serial data received event

 
        private static void COM1_HandleRX(object sender, SerialDataReceivedEventArgs e)
        {
            if (e.EventType != SerialData.Chars) return;

            pBuffer.LoadSerial(COM1);
            while (iNow < pBuffer.DataSize)
            {
                switch (iState)
                {
                 ...
                }
            }
        }

Using code tags will make your post more readable. This can be done in two ways:[ol]
Click the “101010” icon and paste your code between the

 tags or...
Select the code within your post and click the "101010" icon.[/ol]
(Generated by QuickReply)

@ Gralin: He really tried, but clicked the QuickReply button instead…

@ Wouter - ok i see what happened.

@ LiranSNewbie - just edit your post and add [ code ] [ /code ] tags before and after your source code.

try subscribing for datareceived event after opening serial port instead of before.

@ Gralin: done.

@ Mike: what this should do? before or after isn’t it the same?

No it is not the same, first open the port, then subscribe to the event.

@ LiranS - in .net mf 4.1 you have to subscribe before openning the port. This bug was fixed in 4.2

Gralin, i think it’s the other way around: in 4.1 first open then subscribe

Garlin & Eric: I will change the order if that would help however the code works fine, just too slow…so i am guessing it is not the event subscription time, and if it is then how and why?

let the program run for a very long time. watch the available bytes in the GC messages. If available bytes are reducing then your processing is not keeping up with the data stream. if the available bytes are not reducing, then you are losing data, assuming the data is actually sent.

@ EriSan500 - of course you are right. I was replying on my phone in a hurry. sorry for that.

To my opinion dealing with event for serial communication, is convenient but is really time consumming and in some case unefficient. Each time, I obtain better speed and less GC call by hand tuning a polling code.

@ leforban: i understand the less GC, i am on it, but tuning multiple serial devices (currently 2 but potential 3) by hand inside the main loop seems tricky, i assume you constantly using “Read” and readtimeout of 0? how much better speed do you get?

The architecture of my code is quite simple. My board has 4 Com port (An IMU at 38400 bds, 2 NMEA at 4800 and 1 Zigbee) It also uses the COM CDC.

The main loops on each comp Port. I process the IMU on less than 14ms and NMEA datas on 50ms. This could be improved but my boss wants to keep a flexible frontend where data are stored in a big array indexed by a key. As the key is known only at runtime, it does not help to save time.

In main loop I call IMU.read. This method looks for an amount of bytes, if the number of bytes is enough it starts to look for delimiters, if delimiters are ok, it parses the stream.
The problem is that events stop execution very often, this does not help the CLR to speed up the code.

I’ll try to replace my buffer class with a better ring buffer class to reduce or better to eliminate GC calls hope this will increase packets speed.
how would a “native” serial ISR look like? are there any examples for such ISR? tried to avoid using RLP just for convenience but don’t mind getting my hands dirty for speed

Try to write a polling code for you serial port. The fact is that with serial event implementation, you are receiving data while parsing and processing last chunks of data. Therefore, the CLR has to stop its current execution (may be stores the current state of the register, pointer and so on, start the methods invoked by the event), go back to finish the last reception and so on, if you are receiving data continuously at a fast rate, event handler is convenient but really unefficient.