G120 with CAN_DW modules

I have asked this question before, but my problem is not yet solved. I have to bother you professional guys again. My situation is that:

I need to build an interface of CAN bus using G120 and CAN_DW modules, the structure is like the picture shows. I read the instructions and write some codes. But, I still can not transmit or receive messages. When I debug the codes, I use Voltage meter to test the related CPU pins, they have no voltage changing. I think it means that the codes does not work. But, since there are very few example on internet, I do not know what to do. I have struggled with it for two weeks, but no improvement.

the codes:

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.Presentation.Shapes;

using Microsoft.SPOT.Hardware;
using GHI.Premium.Hardware;

using Gadgeteer.Networking;
using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;
using Gadgeteer.Modules.GHIElectronics;

namespace CAN_DW
{
    public partial class Program
    {

        void ProgramStarted()
        {
            //initialization CAN
            Utility.SetLocalTime(new DateTime(2011, 2, 14, 0, 0, 0));
            can_dw2.InitializeCAN(15, 8, 20);

            //possible events
            can_dw2.DataReceived += new GTM.GHIElectronics.CAN_DW.DataReceivedEventHandler(can_dw2_DataReceived);
            can_dw2.ErrorReceived += new GTM.GHIElectronics.CAN_DW.ErrorReceivedEventHandler(can_dw2_ErrorReceived);
            can_dw2.PostDone += new GTM.GHIElectronics.CAN_DW.PostMessagesDoneEventHandler(can_dw2_PostDone);

            //creat ten CAN messages
            Debug.Print("All created CAN messages are:");
            can_dw2.msgList = new CAN.Message[10];
                       
            for (int i = 0; i < can_dw2.msgList.Length; i++)
            {
                can_dw2.msgList[i] = new CAN.Message();
                can_dw2.msgList[i].ArbID = 0x14;
                can_dw2.msgList[i].DLC = 0x01;
                can_dw2.msgList[i].Data[0] = (byte)i;
                can_dw2.msgList[i].IsEID = false;
                can_dw2.msgList[i].IsRTR = false;
                
                Debug.Print("the number "+ (i+1).ToString()+" message is: "+"ID is 0X"+ can_dw2.msgList[i].ArbID.ToString("X") + "  DLC is 0X"+ can_dw2.msgList[i].DLC.ToString("X") +"   DATA 0 is 0X"+ can_dw2.msgList[i].Data[0].ToString("X"));
                Thread.Sleep(500);

            }

            //Send all of the messages
            int numberOfMsgSent = 0;
            
            while (true)
            {
                // Post messages 
                can_dw2.PostMessages(0, can_dw2.msgList.Length - numberOfMsgSent);

                // Record how many were sent.
                numberOfMsgSent += can_dw2.NumMessagesSent;
                Debug.Print("number of messages posted "+numberOfMsgSent.ToString());

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

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

            Thread.Sleep(Timeout.Infinite);

        }



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

        }

        void can_dw2_ErrorReceived(GHI.Premium.Hardware.CAN sender, GHI.Premium.Hardware.CANErrorReceivedEventArgs args)
        {
            Debug.Print("CAN error received: " + args.Error.ToString());

        }

        void can_dw2_DataReceived(GHI.Premium.Hardware.CAN sender, GHI.Premium.Hardware.CANDataReceivedEventArgs args)
        {
            Debug.Print("nice");

        }
    }
}

Sorry, but using a voltmeter to detect changes on signal lines is very unlikely to work with any level of accuracy.

I know little about CAN networks, but here’s a few suggestions.

Do you have proper terminations on the bus?

You currently have the ProgramStarted() method as a blocked method (while true loop), but you cannot do that. You MUST let ProgramStarted complete. Move your testing code to a new method and start that in a thread.

To start with, it might be worth focussing on the DataReceived event if you can push data from your CAN analyser. That should test the fundamentals of your wiring.

What G120 system do you have? Is it the G120HDR and is it a Rev2? I don’t know if that’s relevant or not but it’s something else to share here.

@ Brett - Thank you very much for your reply.

  1. Using voltmeter is not accurate, tomorrow, I will go to lab and try to use oscilloscope to monitor the signal. After that, I will report my results to you.

  2. the CAN DW modules is default terminated and for CAN analyser I set it as termination on.

  3. Since in the while(true), there is a “break” command, I think it will not block the method? And, I do not know how to code in a new method?

  4. I am using G120HDR 1.1

As you checked, is there any other mistake in the codes that I have posted? Because I am new of this and there is really few example of this, So, I am not sure.

No your ProgramStarted is not terminating correctly. Even with the break (which I didn’t see earlier) you do a thread.sleep for ever.

Please restructure this outside ProgramStarted. Let ProgramStarted complete normally. If you have a button module, use the button module press to initiate the transfer, or start a timer and start it after 10 seconds, or something - just don’t try to do everything in ProgramStarted. The post here has some background - basically you have to let ProgramStarted finish before you can be sure that the Gadgeteer framework is healthy and in a state that won’t give unpredictable results. http://blogs.msdn.com/b/net_gadgeteer/archive/2011/12/19/why-not-while-true.aspx

Great news on the o-scope, that’ll definitely help prove that the module is communicating to the mainboard and whether there is data being pushed to the CAN bus

@ Brett - Thank you very much.
I will try your suggestion tomorrow and reply you soon, I hope I can make it tomorrow. I am in Italy, it is nearly middle night. I guess you are in USA?

nope, I’m in Australia and its early morning

If your budget can stretch to it, I would recommend you get one of these. The 8 bit one is more than enough for dealing with all the serial based stuff that we do on NETMF.

I got a friend of mine to get one and he has never stopped using it. He has said it is perfect for debugging serial, SPI, CAN, I2C etc.

If you want more channels for data buses etc then this one is ideal. I got this as I need to debug a 16 bit bus but the Salae one is more than enough for NETMF development.

@ Brett -
I used oscilloscope and there are no hardware problems, I mean the signal can transmit from can_high and can_low to the Can_RX. But, when I am using Can_tx to send, there is no signal on can_tx. Thus, I though it could be software part problem.

After modification of my codes(as follow), I still can not…, could you help me!


using System;
using System.Threading;
using GHI.Premium.Hardware;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;

namespace CAN_DW
{
    public partial class Program
    {
        GT.Timer timer = new GT.Timer(2000);

        void ProgramStarted()
        {
            //initialization CAN
            Utility.SetLocalTime(new DateTime(2013, 10, 05, 0, 0, 0));
            can_dw2.InitializeCAN(15, 8, 20);

            //possible events
            can_dw2.DataReceived += new GTM.GHIElectronics.CAN_DW.DataReceivedEventHandler(can_dw2_DataReceived);
            can_dw2.ErrorReceived += new GTM.GHIElectronics.CAN_DW.ErrorReceivedEventHandler(can_dw2_ErrorReceived);
            can_dw2.PostDone += new GTM.GHIElectronics.CAN_DW.PostMessagesDoneEventHandler(can_dw2_PostDone);

            //creat ten CAN messages
            Debug.Print("All created CAN messages are:");
            can_dw2.msgList = new GHI.Premium.Hardware.CAN.Message[10];
                       
            for (int i = 0; i < can_dw2.msgList.Length; i++)
            {
                can_dw2.msgList[i] = new CAN.Message();
                can_dw2.msgList[i].ArbID = 0x55;
                can_dw2.msgList[i].DLC = 0x08;
                can_dw2.msgList[i].Data[0] = (byte)i;
                can_dw2.msgList[i].Data[1] = (byte)i;
                can_dw2.msgList[i].Data[2] = (byte)i;
                can_dw2.msgList[i].Data[3] = (byte)i;
                can_dw2.msgList[i].Data[4] = (byte)i;
                can_dw2.msgList[i].Data[5] = (byte)i;
                can_dw2.msgList[i].Data[6] = (byte)i;
                can_dw2.msgList[i].Data[7] = (byte)i;
                can_dw2.msgList[i].IsEID = false;
                can_dw2.msgList[i].IsRTR = false;
                
                Debug.Print("the number "+ (i+1).ToString()+" message is: "+"ID is 0X"+ can_dw2.msgList[i].ArbID.ToString("X") + "  DLC is 0X"+ can_dw2.msgList[i].DLC.ToString("X") +"   DATA 0 is 0X"+ can_dw2.msgList[i].Data[0].ToString("X"));
                //Thread.Sleep(500);

            }

            //message sending event timer
            timer.Tick += new GT.Timer.TickEventHandler(timer_Tick);
            timer.Start();                             

        }

        void timer_Tick(GT.Timer timer)
        {
            
            
            //Send all of the messages
            int numberOfMsgSent = 0;
            
            while (true)
            {
                // Post messages 
                can_dw2.PostMessages(0, can_dw2.msgList.Length - numberOfMsgSent);

                // Record how many were sent.
                numberOfMsgSent++; // += can_dw2.NumMessagesSent;
                Debug.Print("number of messages posted " + numberOfMsgSent.ToString());

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

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



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

        }

        void can_dw2_ErrorReceived(GHI.Premium.Hardware.CAN sender, GHI.Premium.Hardware.CANErrorReceivedEventArgs args)
        {
            Debug.Print("CAN error received: " + args.Error.ToString());

        }

        void can_dw2_DataReceived(GHI.Premium.Hardware.CAN sender, GHI.Premium.Hardware.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);
         
        }
    }
}

I think you are going to sleep now…

@ Dave McLaughlin -
I am sorry, but I have no budget…

@ Brett -
I found that the voltages of my can_h and can_l and CAN_RX are very low, could it be the reason that I can not receive messages?

the picture shows can_h is 100mV and CAN_RX is 500mV.

waiting for you my friend

Sorry, I hate to let you down but I don’t have CAN module and don’t know the first thing about CAN ( :slight_smile: ) But I think we’re helping and you’re making progress! I suspect that those voltage levels are not sufficient to register as received messages.

Here’s the next tests I’d suggest you do. Disconnect from the CAN analyser. When SENDING from the G120, you should check the logic levels on the Gadgeteer socket pin CAN_TD used by the CAN module. That will prove to you that those logic signals DO change as expected (you’d expect 3v3 logic level high). Then, I’d check the same test, on the OUTPUT of the Gadgeteer CAN module, check CANH and CANL signals. You should see the transceiver output change.

Now what you can test to compare against is to do the same test on your canalyser, and then compare the two to again see where issues might be coming from.

What do you have on the other end?
Do you have a termination resistor or make sure the jumper is there on the module.

Brett’s idea might be a good test for now and I would take it one step further. Instead of using the CAN controller, setup the system so that can CAN1 is connected to CAN2 and control the TX and RX as GPIO lines.

Use this GPIO control of the TX and RX pins and enable the TX as an output (initial state should be HIGH) and the RX pin as input. Do this for both CAN connections.

Now, because the TJA1050 has dominant mode timeout, you can’t simply set the TX line low and read this back at the RX input. It will be detected as initially LOW but it will go HIGH again a few ms later as the dominant timeout detection disables the TX input on the TJA1050. You need to pulse this TX output ON and OFF. ON being in the LOW state.

Setup a Thread to do this.

You should then be able to read the RX line on both the CAN1 and CAN2 devices as the transmit is detected on the receive input of the sender.

You can read this in another thread and or connect the scope and see the pulses.

Doing it this way tests the electronics and the drivers and avoid the issue of the CAN controller going bus off etc.

Hope this makes sense?

And also, see this Can we use Linux or a Mac for development? – GHI Electronics

@ Brett - @ Gus @ Dave McLaughlin @ andre.m

Thank you all! Finally, I found the problem. I was using socket 6 for can_dw2 and there are no signal. But, all signals are transmitting on socket 4 for can_dw, even though in the codes I wrote can_dw2. I mean now I can transmit and receive on socket 4, no matter I define can_dw or can_dw2.

(ps: the picture got from oscilloscope that posted before is correct, because the value should be multiplied by 10, so the can_RX voltage is 5V, It is correct.)

I am thinking it could because that only one CAN channel works? It seems that G120 can not distinguish can_dw and can_dw2 modules.

I found that there is a way to define a can channel

// Use channel 1
      CAN can = new CAN(CAN.Channel.Channel_1, (uint)(((T2 - 1) << 20) | ((T1 - 1) << 16) | ((BRP - 1) << 0)));

but how can I define can_dw as channel1 and can_dw as channel2?

You don’t. They are just CAN bus drivers. There is no logic on them. It is down to the sockets you connect to that determines which CAN is used.

Can you show us the wiring you have used for the 2 sockets please?

Are you sure they are wired correctly? Is your G120HDR the old type with the 2 unwired sockets?

My G120HDR has SPI on one of them and only 1 of them is now user selectable.

@ Dave McLaughlin -
I am exactly sure they are correctly wired. But my G120HDR is a little different from yours, it is G120HDR 1.1 and the socket 4 and socket 6 are both “user”, rather than socket 6 as SPI. I don’t know if this is the reason that my socket 6 can not support CAN communication?

#region Socket 4
 
            socket = GT.Socket.SocketInterfaces.CreateNumberedSocket(4);
            socket.SupportedTypes = new[] {'C'};
            socket.CpuPins[3] = Pin.GPIO_NONE;
            socket.CpuPins[4] = Pin.P0_1;
            socket.CpuPins[5] = Pin.P0_0;
            socket.CpuPins[6] = Pin.GPIO_NONE;
            socket.CpuPins[7] = Pin.GPIO_NONE;
            socket.CpuPins[8] = Pin.GPIO_NONE;
            socket.CpuPins[9] = Pin.GPIO_NONE;
 
            //// A
            //GT.Socket.SocketInterfaces.SetAnalogInputFactors(socket, 3.3, 0, 12);
            //socket.AnalogInput3 = Cpu.AnalogChannel.ANALOG_2;
            //socket.AnalogInput4 = Cpu.AnalogChannel.ANALOG_1;
            //socket.AnalogInput5 = Cpu.AnalogChannel.ANALOG_0;
 
            //// I
            //// N/A
 
            //// T
            //// N/A
 
            //// X
            //socket.NativeI2CWriteRead = nativeI2C;
 
            GT.Socket.SocketInterfaces.RegisterSocket(socket);
 
            #endregion Socket 4
 
            #region Socket 5
 
            socket = GT.Socket.SocketInterfaces.CreateNumberedSocket(5);
            socket.SupportedTypes = new[] {'D'};
            socket.CpuPins[3] = Pin.GPIO_NONE;
            socket.CpuPins[4] = (Cpu.Pin) 14; // USB_A_N
            socket.CpuPins[5] = (Cpu.Pin) 31; // USB_A_P        
            socket.CpuPins[6] = Pin.GPIO_NONE;
            socket.CpuPins[7] = Pin.GPIO_NONE;
            socket.CpuPins[8] = Pin.GPIO_NONE;
            socket.CpuPins[9] = Pin.GPIO_NONE;
 
            //// U
            //socket.SerialPortName = "COM1";
 
            //// X
            //socket.NativeI2CWriteRead = nativeI2C;
 
            GT.Socket.SocketInterfaces.RegisterSocket(socket);
 
            #endregion Socket 5
 
            #region Socket 6
 
            socket = GT.Socket.SocketInterfaces.CreateNumberedSocket(6);
            socket.SupportedTypes = new[] {'C'};
            socket.CpuPins[3] = Pin.GPIO_NONE;
            socket.CpuPins[4] = Pin.P0_5;
            socket.CpuPins[5] = Pin.P0_4;
            socket.CpuPins[6] = Pin.GPIO_NONE;
            socket.CpuPins[7] = Pin.GPIO_NONE;
            socket.CpuPins[8] = Pin.GPIO_NONE;
            socket.CpuPins[9] = Pin.GPIO_NONE;
 
            // S
            socket.SPIModule = SPI.SPI_module.SPI2;
 
            // X
            socket.NativeI2CWriteRead = nativeI2C;
 
            GT.Socket.SocketInterfaces.RegisterSocket(socket);
 
            #endregion Socket 6
 
            #endregion Socket Setup

OK, that takes care of the software.

What out the physical wiring on the board? Can you show this?

The sockets on your board are unconnected so as long as you have wired them to the main headers it should work.

@ Dave McLaughlin -
I wired it like this way in the picture.