Apologies in advance for the length of this reply!!
I am trying to make a data logger, so an option to log all CAN is the ultimate aim. For the buses I am logging, it is 500kbps, with all frames 8 bytes, running at 2200-2400 frames/second pretty consistently. There is a slight waxing and waning due to the scheduler, but they are basically all periodic frames, so it doesn’t vary much. I have set the HW buffer to 10,000 messages, but they key thing is that the buffer is filling up, so it will always max out at some point however high I set the buffer.
In tests, reading multiple messages at a time with ReadMessages() was faster than reading them individually with ReadMessage() (not surprisingly!), and I have tried various combinations of number of messages to read at a time, and bytes to write to file at a time. At the moment, writing 1-2K to the file at a time, and reading 100 messages at a time to process seems to be about the best performance.
As you hint, getting the data from the CAN in to a byte array to write to a file seems to be the longest part. If I just retrieve the messages, don’t touch them, but write a dummy byte array for each message (to simulate everything but the CAN data extraction itself), my queue of incoming messages does not increase, and stays below 100. As soon as I start to do any transfer of data from CAN to the file-write buffer, then I can’t keep up with incoming CAN. At 2000+ frames/second, I need to be able to grab the CAN timestamp, ArbID and 8 bytes of data in less than 0.5ms, leaving enough time for writes to file every 50-100 messages or so.
Are there any examples of RLP for CAN? I have dabbled with RLP only once before when trying to speed up writes to a display but it was very basic indeed.
For interest, my main test loop currently looks like this…
msgsReceived = loggerCAN1.ReadMessages(CAN1RxMsg, 0, CAN1RxMsg.Length);
for (int i = 0; i < msgsReceived; i++)
PrintDebugtime("Checking msg " + i.ToString());
// Copy CAN info in to Byte Array
// 8 byte timestamp
Array.Copy(BitConverter.GetBytes(CAN1RxMsg[i].TimeStamp.Ticks), 0, CANLogByteArray, (i*21), 8);
// 1byte channel
CANLogByteArray[(i*21) + 8] = 1;
// 4 byte ArbID
Array.Copy(BitConverter.GetBytes(CAN1RxMsg[i].ArbitrationId), 0, CANLogByteArray, (i*21) + 9, 4);
// 8 bytes of data
Array.Copy(CAN1RxMsg[i].Data, 0, CANLogByteArray, (i * 21) + 13, 8);
PrintDebugtime("After data bytes");
PrintDebugtime("About to write");
CANFileLog2.Write(CANLogByteArray, 0, msgsReceived * 21);
With the rough-and-ready debug time routine :
public void PrintDebugtime(string DebugText)
Debug.Print(DebugText + "-" + (Microsoft.SPOT.Hardware.Utility.GetMachineTime().Ticks - oldTicks).ToString());
oldTicks = Microsoft.SPOT.Hardware.Utility.GetMachineTime().Ticks;
It gives a flavour of the timing (ignoring the fact that it takes time to do the debug print itself, typically :
Checking msg 98-9656
After data bytes-2661
Checking msg 99-9636
After data bytes-2671
About to write-1660
I am not sure yet why it takes 9636 ticks to go from writing data bytes for message 98 to the “Checking msg 99” as that should be almost the next command as it restarts the loop. Does a for loop take that long to evaluate? Dropping out of the loop takes only 1660 ticks to get to the “About to write” print as a counterpoint…
You can see that frame 99 takes 4665+1757+3142+2671 = about 12,200 ticks to copy the data over (about 1.2ms per message). The write to file of 21 bytes *100 takes 267221 ticks (27ms), so about 0.25ms per message.
My head is swimming with all the different variables I have tried adjusting and ways to move bytes, so I hope I am not missing something obviously slowing it down…