CAN Support

Which modules currently fully support CAN (provide software libraries)? The information on http://www.ghielectronics.com/catalog/compare/ indicates all but Hydra, then http://www.ghielectronics.com/downloads/NETMF/Library%20Documentation/html/d2f107a4-a6fb-58bf-f847-4ec15aa14496.htm indicates CAN is only supported on EMX and USBizi and http://www.tinyclr.com/forum/topic?id=7457 seems to imply that V4.2 does not have CAN support.

Hello Orest and welcome to the community.

At the bottom of the page http://www.ghielectronics.com/catalog/compare/, you will see links to premium library and to OSHW library. And the top of the page also shows the offer type, premium vs open source.

The documentation you linked to is for premium not open source and yes CAN is in USBizi and on EMX. Now, for the open source side, CAN hardware is available on Cerberus and its cousins but the code is not there yet. This maybe available in near future. There is no CAN on hydra.

Thank you Gus.

If I offered to do the work would you provide the documentation I need to add CAN support on the M4 product?

Is there a CAN module for the Panda II?

There is CAN support in the Panda II. I’m using it for NMEA 2000 work. It can be a bit tricky, but it works.
I’m still trying to figure out CAN group filters :slight_smile:

So if I understand correctly, to Use CAN_DW on the Spider, I need the July 23 release of 4.2. When I install it (after uninstalling any previous versions) I find that 4.2 is not installed on the Spider, the previous version 4.1 is there.

So when I attempt to install 4.2 using the files that were installed by .NET Gadgeteer Package (Beta 7-23-2012)\Beta 7-23\Installation Files. specifically C:\Program Files (x86)\GHI Electronics\GHI Premium NETMF v4.2 SDK\EMX\Firmware folder I get the following error:

“Firmware has 3 files. Please check again”.

since there are only2 files in the folder: Config.hex and Firmware.hex.

In the C:\Program Files (x86)\GHI Electronics\GHI NETMF v4.1 SDK\EMX\Firmware folder there are 3: CLR.HEX, CLR2.HEX and Config.HEX. I can install V4.1 OK but I need 4.2 for CAN_DW support.

What steps should I follow to install V4.2 on a SPider?

Did you run this updater? C:\Program Files (x86)\GHI Electronics\GHI Premium NETMF v4.2 SDK\Firmware Update\FEZSpiderMainboardUpdater.exe

Thank you Gus. That updater works great. I was using the one that is automatically launched when you first install.

Then we are launching the old one, thanks for pointing this out. We will update.

I am running Windows 7 64 bit version on a laptop connected to a power adapter deploying to a Spider running 4.2 firmware. The Spider has both the USB as well as en external 12 volt supplies connected. The following program will behave as expected provided you do not have the PostMessages line in it. When I add this line, I can deploy from VS by pressing F5 once and the message does go out on the bus, however, the text display does not appear. The first time I can halt debugging. I then try F5 again to debug. This time VS delays a very long attempting to deploy. It times out eventually indicating

Error 1 Device not found or cannot be opened - USB:Gadgeteer

If I press the reset button on the Spider while waiting for the timeout, my Laptop immediately shuts down. I have found that if I run the updater I can debug applications on the Spider again. Cycling power on the Spider shows that the program was flashed since the CAN message is sent but the display does not show the expected text.

What should I do to avoid this behavior?

using System;
using System.Collections;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Presentation;
using Microsoft.SPOT.Presentation.Controls;
using Microsoft.SPOT.Presentation.Media;
using Microsoft.SPOT.Touch;

using Gadgeteer.Networking;
using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;
using Gadgeteer.Modules.GHIElectronics;
using GHI.Premium.Hardware;

namespace Test_CAN
{
public partial class Program
{
// This method is run when the mainboard is powered up or reset.
void ProgramStarted()
{

        display_T35.SimpleGraphics.DisplayText("CAN please work", Resources.GetFont(Resources.FontResources.NinaB),
            GT.Color.Blue, 20, 20);
        Test_CAN();

    }


    public void Test_CAN()
    {
        int i;
        Debug.Print("Starting CAN test");
        var can_dw = new CAN_DW(6);
        can_dw.msgList = new CAN.Message[100];
        can_dw.ErrorRecieved += new CAN_DW.ErrorRecievedEventHandler(can_dw_ErrorRecieved);

        can_dw.InitializeCAN(15, 8, 6, 100);  // 500 Kb

        i = 0;
        can_dw.msgList[i] = new CAN.Message();
        can_dw.msgList[i].ArbID = (uint)5;
        can_dw.msgList[i].Data[0] = (byte)0x5A;
        can_dw.msgList[i].Data[1] = (byte)0x11;
        can_dw.msgList[i].Data[2] = (byte)0x22;
        can_dw.msgList[i].Data[3] = (byte)0x33;
        can_dw.msgList[i].Data[4] = (byte)0x44;
        can_dw.msgList[i].Data[5] = (byte)0x55;
        can_dw.msgList[i].Data[6] = (byte)0x66;
        can_dw.msgList[i].Data[7] = (byte)0x77;
        can_dw.msgList[i].DLC = 8;
        can_dw.msgList[i].IsEID = false;
        can_dw.msgList[i].IsRTR = false;

        can_dw.PostMessages(0, 1);


    }

    void can_dw_ErrorRecieved(CAN sender, CANErrorReceivedEventArgs args)
    {
        Debug.Print("CAN error received: " + args.Error.ToString());
    }

}

}

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)

After a lot of scientifical mumbo-jumbo I used my Doctoral edumication to uncovered the conspiracy that the CAN DW driver should not be fed more than 15 transmit buffers (the FEZ monkey gets indigestion). The following code has various number of transmit buffers that can be uncommented to see if the afore-mentioned behavior can be replicated elsewhere (maybe the cosmic rays and the alignment of the celestial bodies at this geographic location and time are just not auspicious - or I am feeding Fez the wrong kind of bananas).

 using System;
using System.Collections;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Presentation;
using Microsoft.SPOT.Presentation.Controls;
using Microsoft.SPOT.Presentation.Media;
using Microsoft.SPOT.Touch;

using Gadgeteer.Networking;
using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;
using Gadgeteer.Modules.GHIElectronics;
using GHI.Premium.Hardware;

namespace Test_CAN
{
    public partial class Program
    {
        static GT.Timer transmitTimer;
        
        // This method is run when the mainboard is powered up or reset.   
        void ProgramStarted()
        {
            Debug.Print("Program Starting");
            can_dw.InitializeCAN(15, 8, 6, 100);  // 500 Kb
            can_dw.DataRecieved += new CAN_DW.DataRecievedEventHandler(can_dw_DataRecieved);
            can_dw.ErrorRecieved += new CAN_DW.ErrorRecievedEventHandler(can_dw_ErrorRecieved);
            can_dw.PostDone += new CAN_DW.PostMessagesDoneEventHandler(can_dw_PostDone);
            // Create a new message list to fill out and send.
            //can_dw.msgList = new CAN.Message[1];  // this one works
            can_dw.msgList = new CAN.Message[15];  // this one works
            //can_dw.msgList = new CAN.Message[16];  // this one enters Satori (deep meditative ecstatic state)
            //can_dw.msgList = new CAN.Message[100];  // this one enters Satori (deep meditative ecstatic state)
            transmitTimer = new GT.Timer(new TimeSpan(0, 0, 0, 0, 1500));
            transmitTimer.Tick += new GT.Timer.TickEventHandler(transmitTimer_Tick);
            transmitTimer.Start();
            Debug.Print("Program Started");

            
        }
        void can_dw_PostDone(int numPosted)
        {
            Debug.Print(numPosted.ToString() + " messages were posted");
        }

        void can_dw_ErrorRecieved(CAN sender, CANErrorReceivedEventArgs args)
        {
            Debug.Print("CAN error received: " + args.Error.ToString());
        }
        
        void can_dw_DataRecieved(CAN sender, CANDataReceivedEventArgs args)
        {
            Debug.Print(">>> can_DataReceivedEvent <<<");

            CAN.Message[] incMsg = new CAN.Message[25];

            for (int i = 0; i < incMsg.Length; i++)
            {
                incMsg[i] = new CAN.Message();
            }

            int numMessages = sender.GetMessages(incMsg, 0, incMsg.Length);

            // Process messages here
        }

        public void Test_CAN_Tx()
        {
            int i;
            Debug.Print("Starting Orest CAN test");
            i = 0;
            can_dw.msgList[i] = new CAN.Message();
            can_dw.msgList[i].ArbID = (uint)0x12345;
            can_dw.msgList[i].Data[0] = (byte)0x5A;
            can_dw.msgList[i].Data[1] = (byte)0x11;
            can_dw.msgList[i].Data[2] = (byte)0x22;
            can_dw.msgList[i].Data[3] = (byte)0x33;
            can_dw.msgList[i].Data[4] = (byte)0x44;
            can_dw.msgList[i].Data[5] = (byte)0x55;
            can_dw.msgList[i].Data[6] = (byte)0x66;
            can_dw.msgList[i].Data[7] = (byte)0x77;
            can_dw.msgList[i].DLC = 8;
            can_dw.msgList[i].IsEID = true;
            can_dw.msgList[i].IsRTR = false;

            can_dw.PostMessages(0, 1);
            // Sleep to allow the messages time to transmit.
            System.Threading.Thread.Sleep(1);
           
        }

        void transmitTimer_Tick(GT.Timer timer)
        {
            Gus_Test_CAN();
            Thread.Sleep(100);
            Test_CAN_Tx();
        }
      public  void Gus_Test_CAN()
      {
            Debug.Print("Starting Gus CAN test");
          int  length = 0;
          if (can_dw.msgList.Length > 15) 
              length = 15;
          else
              length = can_dw.msgList.Length;
            // Loop through the messages and fill them out.
          for (int i = 0; i < length; i++)
            {
                can_dw.msgList[i] = new CAN.Message();
                can_dw.msgList[i].ArbID = (uint)5;
                can_dw.msgList[i].Data[0] = (byte)i;
                can_dw.msgList[i].Data[1] = (byte)(i+1);
                can_dw.msgList[i].Data[2] = (byte)(i + 2);
                can_dw.msgList[i].Data[3] = (byte)(i + 3);
                can_dw.msgList[i].Data[4] = (byte)(i + 4);
                can_dw.msgList[i].Data[5] = (byte)(i + 5);
                can_dw.msgList[i].Data[6] = (byte)(i + 6);
                can_dw.msgList[i].Data[7] = (byte)(i + 7);
                can_dw.msgList[i].DLC = 8;
                can_dw.msgList[i].IsEID = false;
                can_dw.msgList[i].IsRTR = false;
            }

            int numberOfMsgSent = 0;

            //Send all of the messages
            while (true)
            {
                // Post as many messages as possible.
                can_dw.PostMessages(0, length - numberOfMsgSent);
                //can_dw.PostMessages(0, 1);

                // Record how many were sent.
                numberOfMsgSent += can_dw.NumMessagesSent;

                // If we have sent all of the messgaes, break out of the loop.
                if (numberOfMsgSent == can_dw.msgList.Length)
                    break;

                // Sleep to allow the messages time to transmit.
                System.Threading.Thread.Sleep(1);
            }
        }

    }
}  

@ Architect - Thank you for the suggestion. I attempted to use the code tags in my next post. Could you please look at it to see why it does not behave the way one would expect? (Having the mechanism to expand and collapse)

I’ve looked at the PostMessages and it looks like the parameters you pass to that method change nothing it will start a thread and will send all messages in the list.
The thread function will fire PostDone event at the end. While thread is running any additional calls to PostMessages do nothing and just return CAN_PostState.Fail.

This code needs some cleaning. I would try not to call PostMessages over and over until PostDone is received.

The calling of post over and over again was what Gus recommended in his tutorial. I have rewritten the code and found the following that validates your statement:

PostMessages and it looks like the parameters you pass to that method change nothing it will start a thread and will send all messages in the list.

Is the source code available and if so where do I find it? Having it would have saved me many hours of frustration as I am trying to convince my colleges to change from a Linux based system to this system and I am running out of time and patience.

So in keeping with the FEX Monkey here is what I think happens:

The FEZ CAN monkey anticipates what I am going to do. If I create a bag that can hold 15 bananas and only put one in it, the monkey expects there to be 15. So I always put as many bananas as there is space for them (when you declare the size of can_dw.msgList you must instantiate every element even if you plan to use only one).

The next mystery: I tell the monkey to take only the first banana of the 15 that are in the bag, wait a bit, replace the first banana and tell the monkey to take the first one again, it takes all of them. Kind of opportunistic I would say.

public CAN_DW.CAN_PostState PostMessages(int offset, int count);
ignores count

     public partial class Program
    {
        static GT.Timer transmitTimer;
        // This method is run when the mainboard is powered up or reset.   
        void ProgramStarted()
        {
            Debug.Print("Program Starting");
            can_dw.InitializeCAN(15, 8, 6, 100);  // 500 Kb
            can_dw.DataRecieved += new CAN_DW.DataRecievedEventHandler(can_dw_DataRecieved);
            can_dw.ErrorRecieved += new CAN_DW.ErrorRecievedEventHandler(can_dw_ErrorRecieved);
            can_dw.PostDone += new CAN_DW.PostMessagesDoneEventHandler(can_dw_PostDone);
            // Create a new message list to fill out
            can_dw.msgList = new CAN.Message[15];  
           for (int i = 0; i < can_dw.msgList.Length; i++)
            {
                can_dw.msgList[i] = new CAN.Message();
                can_dw.msgList[i] = new CAN.Message();
                can_dw.msgList[i].ArbID = (uint)(0x70 + i);
                can_dw.msgList[i].Data[0] = (byte)i;
                can_dw.msgList[i].Data[1] = (byte)(i + 1);
                can_dw.msgList[i].Data[2] = (byte)(i + 2);
                can_dw.msgList[i].Data[3] = (byte)(i + 3);
                can_dw.msgList[i].Data[4] = (byte)(i + 4);
                can_dw.msgList[i].Data[5] = (byte)(i + 5);
                can_dw.msgList[i].Data[6] = (byte)(i + 6);
                can_dw.msgList[i].Data[7] = (byte)(i + 7);
                can_dw.msgList[i].DLC = 8;
                can_dw.msgList[i].IsEID = false;
                can_dw.msgList[i].IsRTR = false;
            }
            transmitTimer = new GT.Timer(new TimeSpan(0, 0, 0, 0, 1500));
            transmitTimer.Tick += new GT.Timer.TickEventHandler(transmitTimer_Tick);
            transmitTimer.Start();
            Debug.Print("Program Started");
        }

        void transmitTimer_Tick(GT.Timer timer)
        {
            Thread.Sleep(100);
            Test_CAN_Tx();
        }
        void can_dw_PostDone(int numPosted)
        {
            Debug.Print(numPosted.ToString() + " messages were posted");
            // the monkey eats all available bananas- don't care how many you offered
        }

        void can_dw_DataRecieved(CAN sender, CANDataReceivedEventArgs args)
        {
            Debug.Print(">>> can_DataReceivedEvent <<<");

            CAN.Message[] incMsg = new CAN.Message[25];

            for (int i = 0; i < incMsg.Length; i++)
            {
                incMsg[i] = new CAN.Message();
            }

            int numMessages = sender.GetMessages(incMsg, 0, incMsg.Length);

            // Process messages here
        }

        void can_dw_ErrorRecieved(CAN sender, CANErrorReceivedEventArgs args)
        {
            Debug.Print("CAN error received: " + args.Error.ToString());
        }


        public void Test_CAN_Tx()
        {
            int i;
            Debug.Print("Starting CAN test");


            Debug.Print("Starting Orest CAN test");
            i = 0;
            can_dw.msgList[i].ArbID = (uint)0x12345;
            can_dw.msgList[i].Data[0] = (byte)0x5A;
            can_dw.msgList[i].Data[1] = (byte)0x11;
            can_dw.msgList[i].Data[2] = (byte)0x22;
            can_dw.msgList[i].Data[3] = (byte)0x33;
            can_dw.msgList[i].Data[4] = (byte)0x44;
            can_dw.msgList[i].Data[5] = (byte)0x55;
            can_dw.msgList[i].Data[6] = (byte)0x66;
            can_dw.msgList[i].Data[7] = (byte)0x77;
            can_dw.msgList[i].DLC = 8;
            can_dw.msgList[i].IsEID = true;
            can_dw.msgList[i].IsRTR = false;

            can_dw.PostMessages(0, 2);  // give FEZ only the first 2 bananas
            // Sleep to allow the messages time to transmit.
            System.Threading.Thread.Sleep(1);
        }
    }

Your banana math matches what I see in the source code:

http://gadgeteer.codeplex.com/SourceControl/changeset/view/20977#256621

:slight_smile:

@ Architect - Thank you very much for your help. I am now making good progress.

The link to the source is very useful.

What protocol do I use to report the opportunistic FEZ CAN transmit monkey so someone teaches it how to count?

Glad to hear!

Forum is good or email address from the “contact us” page.