Cerb-family managed CAN drivers

Cerb-family managed CAN drivers

This is a simple driver to add CAN functionality to cerberus, cerbuino and any product related to the cerb-family, even mountaineer boards.

The implementation is done completely in C# using register access, which makes it simple to debug and improve. This will also make it run slower, which is not a problem for transmit but receive may not be able to keep up with traffic. Once driver is all proven functions, it is best to be moved into an RLP or directly on the firmware to give better performance.

The original debugging comments are still in the code but they are all commented out. They may be beneficial if needed to know what is in certain registers as certain times. Feel free to delete them if they do not suit your needs.

There is also an included example sends the same CAN message through 20 times then one extended ID message.

To calculate CAN’s Phase Segments and Synchronization Jump Width you can (<-- pun) download a CAN calculator from this website: http://intrepidcs.com/support/mbtime.htm For oscillator, input 42 mHz as this is the peripheral clock speed of the bus that utilizes CAN.

3 Likes

Excellent - I’ll try this out as soon as possible!

Hello. Has this CAN class event for detect incoming message?

Yes, but my skills are not so good. I will try it. Or I have to work with Panda II.

I found address of CAN interrupt register (CAN_IER). How can I map interrupt on register change? Please.

Anything new?

Just asking if someone add some feature. The wiki says partial available. I expect that some day it will write done.

@ Aron - (sorry if my english is bad :p)

Hi, I’m using your driver for CAN on the Cerberus. I can send messages on a CAN bus but I need to send them every 1000ms.

When I do this with a timer, it does send the CAN messages periodic but there is a big timing problem (the CAN messages are sent around every 5000ms).

I think this is because the Cerberus needs to much time to run trough your class. You mentioned the class can be implemented in the firmware, this would be a big difference I guess.

The problem now is that I don’t know how to implement the class in my firmware. I already made a dll from your class and added in the references of my solution but if I doe this, I can’t program my Cerberus anymore (it blocks).

Could you help me out please?

@ Luftje, welcome to the forum.

I suspect that your problem will not be (just) because of this driver, but it will require you to share more details with us. You might even need to show us a sample of your code that is the minimum someone else would need to use to show your problem - ie that really means the first step you would need to do is to simplify your program, perhaps just send a simple message in the timer and do little else. Once you have that, then you should start to dig deeper into where the bulk of your time is spent.

@ Brett - Hi Brett, thanks for your reply

[title]This is my program:[/title]

namespace CerberusTest
{
    public partial class Program
    {
        CAN test = null;
        //message to send
        byte[] message = { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 };

        void ProgramStarted()
        {
            //enable debugging on the Cerberus
            Debug.GC(true);

            // From bit timing calculator, 42Mhz clock with 500Kbps CAN clock, we need 21TQ
            // sync 1 + T1 + T2 = 21
            // UInt32 CAN_BPS = 250 * 1000;
            UInt32 PhaseSegment1 = 12;
            UInt32 PhaseSegment2 = 8;
            UInt32 SynchronizationJumpWidth = 1;
            // UInt32 TQ = 21;

            UInt32 BaudRatePrescaler = 4;// 16; // 4;// 42000000 / CAN_BPS / TQ;

            //creating the CAN object
            test = new CAN(CAN.CANChannel.Channel1, PhaseSegment1, PhaseSegment2, SynchronizationJumpWidth, BaudRatePrescaler);

            Debug.Print("CAN object created");

            Gadgeteer.Timer myTimer = new Gadgeteer.Timer(1000);
            myTimer.Tick += new GT.Timer.TickEventHandler(myTimer_Tick);
            myTimer.Start();
        }

        void myTimer_Tick(GT.Timer timer)
        {
            //every time a CAN messag is sent, blink LED
            PulseDebugLED();

            try
            {
                //send CAN message
                test.PostMessage(0x127, false, false, message);
                Debug.Print("Message sent");
            }
            catch (Exception ex)
            {
                Debug.Print(ex.ToString());
            }
        }
    }
}

As you can see, I just send a send message every 1000 ms via CAN channel1 in a very simple program to the GHI CAN module. If I debug the code, I can see when the program wants to create the CAN object, the program slows down. So this is the line where the program comes in to the driver. Maybe you see any bod coding here?

Thanks

I’d try to put some System Timer measurements around the different phases of the app and see what’s going on. A one-off “create” delay isn’t really an issue, is it? Initialisation happens once so you don’t really care if it takes overly long. The key in my view is around when the timer fires - how often does it take longer than 1 sec, and then in the postmessage method what takes time there?

@ Brett - Hi Brett, I managed to resolve my timing problem. My tinming problem did’t occured once but every time i posted a message when the timer ticked. I took a look aroud in the driver class writen by Aron at the “PostMessage(…)” method. I set a debug point after every loop that was being executed. The program needed the most time when entering next part of code:


//while (((CAN_MSR.Read() & 2) != 2)) //&& (wait_ack != INAK_TIMEOUT))
                //    wait_ack++;

                //////if ((CAN_MSR.Read() & 2) == 2)
                //////    Debug.Print("CAN failed to exit Sleep Mode");
                //////else
                //////    Debug.Print("CAN not sleeping... Transmitting!");

So the program “blocks” when executing the while loop. Becaus I don’t need to read CAN messages I can delete this lines, for people who do have to read CAN and also send it like I have to, this lines may not be commented I guess… But it works for me.

[title]New problem:[/title]

I created an IO-extention board to read switches with 12V (so I simply use transistors as switches to convert it to 3.3V). I need to supply the Cerberus board with this io-extention board. When I do attatch it, the Cerberus is powered but the program isn’t running good. When I combine the io-board with the USB-client, it does work… . Dont’t really understand this. Maybe the only way to supply the Cerberus is via the USB connector?

Thanks for the help

Can you clarify, are you powering the Cerberus by the 12v source you mention? If so, how is that regulated and how is it connected to the Cerberus? Can you also explain what you mean by not running good? Does the code work but some part not appear to communicate for instance? Is it possible you have a ground plane issue - when you connect the usb to the pc you have a gnd plane to the pc over the usb cable… do you have the entire board connected to anything other than power??

Any thoughts when the Cerb family will receive the same CAN drivers as the EMX and FEZ products? This lack of high speed drivers will prevent s from moving to this product line. Thanks.

If you need CAN, we recommend using one of the premium offers.

@ Diesel Engineer - IMHO the $25 extra cost for a G120(or HDR for dev, that is about 20 minutes engineering cost at my company) is not really a barrier (if you look at all the advantages of the premium devices) especially if you talk about proto types or small production quantities.

@ Gus and @ David. Could not agree more. Has nothing to do with cost!. The Cerb has a faster processor so it might be better suited for some tasks. Can’t wait for the 400MHz processor to come out of beta (with CAN implemented). Already have plans for it!! Hurry up please! :slight_smile:

Hi Aron,

I am working on a CAN network with robust and light weight devices.

The robust units are G120 with premium libraries for CAN while the light weight units should be low cost ones with cerberus boards to make the project numbers affordable.

Right now the G120 units work as expected, they send and receive CAN messages without problem. I have validated the messages using an ELM327 controller in listening mode to validate G120 messages going out of the units.

The Cerberus units with your managed CAN drivers work well for sending CAN messages every 2 seconds, but I cannot make the cerberus units receive valid CAN messages. I always receive the same message with all data values equal to 0. The arbID is always 346, even if the cerberus unit is disconnected from the CAN bus.
I am validating the CAN messages every 3 seconds within a timer. The code that I use to test for incomming messages is:


                uint arbID; bool EID; bool RTR; byte[] dataMsg = new byte[7];
                if (can_dw.GetMessage(out arbID, out EID, out RTR, dataMsg))
                   Debug.Print("message CAN received: arbID -> " + arbID + ". EID -> " + EID + ". RTR -> " + RTR);
 

The result shows:

message CAN received: arbID -> 346. EID -> False. RTR -> False

Aron, can you share with us a code snippet on how to use the reception functionality on the Cerberus managed CAN drivers?

Thank you!!

Hello Aron

I am running your code on a Cerb40 II device and I experience following problems:

I succeed in transmitting messages but there seems to be something wrong with the checking of the transmitter ready condition. The code FreeToTransmit always seems to return true. On the other hand following code lines
wait_ack = 0;
while (((CAN_MSR.Read() & 2) != 2) && (wait_ack != INAK_TIMEOUT))
wait_ack++;

in PostMessage always cause a fixed pause (1e condition is never true and the loop always exits when wait_ack reaches INAK_TIMEOUT). Because of this fixed pause the test program runs ok but the code lines could as well be replaced by a Sleep.

I did not succeed on receiving messages on the CERB40. I have exactly the same behavior as mentioned by Ninja. MessageReceived always returns true a fixed message even when there is no activity on the canbus. Has anybody ever succeeded in receiving a single message?

Remarks

  • Tests have been done on canbus with an old FEZ-Rhino board (unmanaged driver) and PIC24F (ECAN native C code).
  • I know (now) that I had better selected the G120 with extended lib support. However my hardware is ready and the managed driver should do the job at a low bitrate.

Any help appreciated
Luc

I know this is an old topic but it has some good information and I recently made some updates to Aaron’s driver and I just uploaded them to codeshare here: https://www.ghielectronics.com/community/codeshare/entry/1001

I also put an example of how to set up a CAN channel and the Arbitration ID filters to be able to read CAN messages.

In response to Luc (LGOR), CAN_MSR has a SLEEP bit. That line you pasted in just had a bug in it. It should have been checking if bit 2 was set to see if the CAN device was asleep, not checking if it is NOT asleep. I also JUST realized that you posted a cerb CAN driver like a year and a half ago (I wish I would have noticed when I started trying to use my cerberus for CAN, haha). To anyone looking for it, it is in codeshare here: https://www.ghielectronics.com/community/codeshare/entry/792

Anyway, the main update I made for this was to add a way to set up the CAN filters. Just pass a uint array of Arbitration IDs, whether or not they are extended IDs, how many Arbitration IDs you want to see, and a boolean to tell if you’d rather just allow all traffic through (not recommended on a bus with a lot of traffic).

Hopefully this post helps someone else who is looking for cerb-CAN information.

1 Like