Main Site Documentation

CAN Receive buffer


#1

Hello,

I’m reading data from the CAN-bus. This data comes from an CAT-engine, but after 100 messages my receive buffer is full. How do I empty this buffer?

Kind Regards


#2

Can you show us some code?


#3

Hello,

I Used the standard code that I found here on the website to read the CAN messages. But after 200 messages I get an error that my buffer is full!

Kind Regards


#4

I’ve used the standard code with much more data. No problems.
Could you show us the exact code you used? Including filters, etc.
You mentioned first that it stopped after 100 messages, in your second post after 200 messages. Typo? Or different each time?


#5

Thet init:


// Use channel 1
            canbus = new CAN(CAN.Channel.Channel_1, (uint)(((T2 - 1) << 20) | ((T1 - 1) << 16) | ((BRP - 1) << 0)));
            uint[] explicitIDs = new uint[] { 0x18F00400 };
            canbus.SetExplicitFilters(explicitIDs);

            // Serial port functions
            serialPort.Open();

            // create a message list of 255 messages
            msgList = new CAN.Message[1];
            for (int i = 0; i < msgList.Length; i++)
                msgList[i] = new CAN.Message();

            canbus.GetMessages(msgList, 0, 1);
           
            // subscribe to events
            canbus.DataReceivedEvent += new CANDataReceivedEventHandler(can_DataReceivedEvent);

and now the DataReceiveEvent:


Debug.Print(">>> can_DataReceivedEvent <<<");

            // read as many messages as possible
            int count = sender.GetMessages(msgList, 0, msgList.Length);

            for (int i = 0; i < count; i++)
            {
                long ID = msgList[i].ArbID;
                int value = 0;
                FunctionCode oFunction = Common.FindFunctionCode(ID);
                foreach (SubFunctions o in oFunction.SubFunctions)
                {
                    if (o.SubFunction == "nothing"){ }
                    else
                    {

                        switch (o.ByteLength)
	                    {
	                        case 1:
                                value = ((UInt16)(msgList[i].Data[o.ByteOne])) / o.Divider; 
                                break;
                            case 2:
                                value = ((UInt16)(msgList[i].Data[o.ByteOne] + (msgList[i].Data[(o.ByteOne + 1)] << 8))) / o.Divider; 
                                break;
                            case 4:
                                value = ((UInt16)(msgList[i].Data[o.ByteOne] + (msgList[i].Data[(o.ByteOne + 1)] << 8) + (msgList[i].Data[(o.ByteOne + 2)] << 16) + (msgList[i].Data[(o.ByteOne + 3)] << 24))) / o.Divider;
                                break;
                            default:
                                value = ((UInt16)(msgList[i].Data[o.ByteOne])) / o.Divider; 
                                break;
	                    }

                        if ((value >= (LastValue + 6)) | (value <= (LastValue - 6)))
                        {
                            byte[] outBuffer = Encoding.UTF8.GetBytes("$$" + (oFunction.ID >> 56) + "#" + ((ushort)(oFunction.ID >> 8)) + "#" + o.SubFunction + "#" + value + "\n\r");
                            serialPort.Write(outBuffer, 0, outBuffer.Length);
                            LastValue = value;
                        }

                    }
                }
                Thread.Sleep(10);
            }
            canbus.Reset();
            Thread.Sleep(10);


#6

Looks different than the example.
Why do you define msgList with only 1 Message? Is that the same variable msgList used in the receive interrupt? That will be too small to allow writing etc. parallel to just getting one message at a time.

Why not try the example exactly as it was shown to get a feel for what’s going on. Then you can change the stuff as you want? I think you will need to add more messages to the array anyway.


#7

I tried the same code with a messagelist of 100 and then you read 100 messages at the moment that the receive event occures. But some times the error event occures and says that the buffer is full, because I get tons of data.

So after I’ve proccessed the message list I want to empty the receive buffer. Is this possible?


#8

Can you enable a filter so you only receive important data?


#9

I do use a filter:


uint[] explicitIDs = new uint[] { 0x18F00400 };
            canbus.SetExplicitFilters(explicitIDs);



#10

Maybe wrap the entire function in a while statement…


            int count = sender.GetMessages(msgList, 0, msgList.Length);
            while (count > 0)
            {
                for (int i = 0; i < count; i++)
                {
                    long ID = msgList[i].ArbID;
                    int value = 0;
                    FunctionCode oFunction = Common.FindFunctionCode(ID);
                    foreach (SubFunctions o in oFunction.SubFunctions)
                    {
                        if (o.SubFunction == "nothing") { }
                        else
                        {

                            switch (o.ByteLength)
                            {
                                case 1:
                                    value = ((UInt16)(msgList[i].Data[o.ByteOne])) / o.Divider;
                                    break;
                                case 2:
                                    value = ((UInt16)(msgList[i].Data[o.ByteOne] + (msgList[i].Data[(o.ByteOne + 1)] << 8))) / o.Divider;
                                    break;
                                case 4:
                                    value = ((UInt16)(msgList[i].Data[o.ByteOne] + (msgList[i].Data[(o.ByteOne + 1)] << 8) + (msgList[i].Data[(o.ByteOne + 2)] << 16) + (msgList[i].Data[(o.ByteOne + 3)] << 24))) / o.Divider;
                                    break;
                                default:
                                    value = ((UInt16)(msgList[i].Data[o.ByteOne])) / o.Divider;
                                    break;
                            }

                            if ((value >= (LastValue + 6)) | (value <= (LastValue - 6)))
                            {
                                byte[] outBuffer = Encoding.UTF8.GetBytes("$$" + (oFunction.ID >> 56) + "#" + ((ushort)(oFunction.ID >> 8)) + "#" + o.SubFunction + "#" + value + "\n\r");
                                serialPort.Write(outBuffer, 0, outBuffer.Length);
                                LastValue = value;
                            }

                        }
                    }
                }

                count = sender.GetMessages(msgList, 0, msgList.Length);
            }

That way it’ll continue to read messages as long as there is data in the buffer.


#11

Hello,

I understand that with a while-loop I can read the whole buffer, but I only need to read my messagelist once and then renew the data. Because now I need to read the entire buffer from the CAN-receiver and when I’ve read the buffer I can receive new data.

The following is my problem:

I’m reading the RPM of a engine, but when I change the RPM from 800 to 1300 I will only see this when I read data from the buffer. But when the buffer is filled with messages where my RPM is 800, I need to renew the buffer and receive the messages where the RPM is 1300.

I do following now:

  • I read the messages from the CAN-bus.
  • I proccess the data
  • I dispose the CAN-channel
  • Now I declare the CAN-channel again and start with an empty buffer.

But how do I clear the CAN-Buffer without disposing the channel?


#12

Why not just read the data and dump it? We can add a method to discard the receive buffer but you should be able to just read and dump the data.

Your RPM come very few times/sec so your FEZ can easily handle it with no hiccups at all.


#13

I’m using the EMX Develpment System not FEX, but if it’s that easy:

How do I read and dump the data?


#14

All GHI devices share the same libraries so they work the same.

Create a message array size 100 and read your messages into the array…then do not use this data?

I am not sure you are handling messages correctly as you should not have to do this anyway, nor need to dump the receive buffer.

code should be like:

  1. init CAN with filter to receive RPM messages
  2. read CAN message
  3. parse the message and pass on the RPM value to your “other” code that needs to know RPM
  4. Sleep 10ms
  5. go back to step 2

#15

http://ics.nxp.com/support/documents/microcontrollers/pdf/user.manual.lpc24xx.pdf

Take a look at page 477.

If you set bit 2 of the CAN1 CMR (or CAN2 if you are using it) to a 1, it will release the receive buffer.

CAN1.CMR = 0xE0044004
CAN2.CMR = 0xE0048004


private static void ClearCAN1RxBuffer()
{
            Register reg = new Register(0xE0044004);
            reg.SetBits(1 << 2);
}

That’s not the most efficient way to do it (it will create a lot of GC calls), but you get the idea. To reduce the GC calls, make the register a static class variable and just set it in the function.


#16

This would not help as there is much larger buffer in our drivers. The hardware buffer is way too small :slight_smile:


#17

Did you try increasing the receive buffer?
You can do this in the CAN constructor.


#18

How do you mean increasing the receive buffer? I only want to receive the data realtime. At the moment that I do a getmessages then I want to receive the messages realtime.


#19

I think what the GHI guys are trying to say Nick is that once a message is read it is removed from the buffer.

Therefore, if you just read through the message buffer as quickly as you can until you get to the last one of the type you are looking for - you’ll have the latest and have no items left in the buffer.

You may have a typo here which is limiting the amount of messages you can read:


// create a message list of 255 messages
            msgList = new CAN.Message[1];

Should that 1 be 255?

Did you try Silic0re’s code? It should clear out the message list completely each time. If the section of code I listed above is a bug, you’ll only ever read the first message from the queue, even if there are multiple messages there which is why you might be seeing stale data.

Additionally, if you’re seeing more than 90 messages a second, you’ll never get through them all.


#20

The messages are buffered internally. If you specify 1000 as a size in the constructor, EMX will store 1000 messages for you until you are ready to process them.