CAN

From TinyCLR Wiki

Revision as of 07:58, 25 September 2011 by SonOfTux (Talk | contribs)


Start with this tutorial first
CAN Bus
Difficulty
Advanced
Related Reading
None
Assemblies Needed
Not known
Hardware Requirements
Any NETMF hardware
Downloads & Tutorials Page

Controller Area Network is a very common interface in industrial control and automotive. CAN is very robust and works very well in noisy environments at high speeds. All error checking and recovery methods are done automatically on the hardware. TD (Transmit Data) and RD (Receive Date) are the only two pins needed. These pins carry out the digital signal that need to be converted to analog before it is on the actual wires using the physical layer. Physical layers are sometimes called transceivers.

On CAN, you must have at least 2 nodes on the bus. Having only one will not work at all.

There are many kinds of physical layers but the most commonly used is high-speed-dual-wire that uses twisted pair for noise immunity. This transceiver can run at up to 1Mbps and can transfer data on very long wires if low bit-rate is used. Data can be transferred between nodes on the bus where any node can transfer at any time and all other nodes are required to successfully receive the data. There is no master/slave in CAN. Also, all nodes must have a predefined bit timing criteria. This is much more complicated that calculating a simple baud rate for UART. For this reason, many CAN bit rate calculators are available.

This kind of transceiver require 120 ohm resistor to be added on the wires, CANh and CANL, otherwise it will not work.

This image shows a diagram of 2 CAN transceivers with twisted pair and termination resistors.

File:CAN phy.gif

The CAN peripheral of EMX is same as the popular SJA1000. A quick Internet search for SJA1000 should result in more than one free calculator.

In short, this is a simple way to calculate the bit timing:

  1. Divide the system clock (72Mhz) to get an appropriate clock for the CAN peripheral (this is NOT the baud rate) This is called the BRP.
  2. Figure out how many clocks you need to make up one bit. Usually this is 24 or 16. This is called TQ.
  3. Assign values to T1 and T2 where T1+T2+1=TQ

Let us assume we need 250Kbps.

  1. From 72Mhz system clock, I want the CAN clock to be 6Mhz so I need to divide by 12 (BRP=12).
  2. 6Mhz/250kbps = 24 TQ (we usually want 16 or 24).
  3. T1 = 15, T2 = 8 will give us 15 + 8 + 1 = 24 and this is what we need.

I got the T1 and T2 values from: http://www.kvaser.com/can/protocol/index.htm I picked the first value and subtracted 1 from T1 because the calculator included the sync bit

Here is the code with detailed comments

using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.Hardware;
 
public class Program
{
    // Messages list
    static CAN.Message[] msgList;
 
    public static void Main()
    {
        // Set the system time. CAN messages will have a time stamp
        Utility.SetLocalTime(new DateTime(2011, 2, 14, 0, 0, 0));
 
        int T1, T2, BRP;
 
        // These numbers were calculated using the calculator on this link:
        // http://www.kvaser.com/can/protocol/index.htm
        // We used the very first value from the calculator output
 
        /////////////////////////////////////////////////////////////////////////////////////////////
        // Bitrate 250Kbps
        // CLK = 72 Mhz, with BRP = 12 -> 6Mhz CAN clock
        // 6Mhz/250Kbps = 24 TQ
        // T1 = 16 minus 1 for sync = 15
        // T2 = 8
        // 15 + 1 + 8 = 24 TQs which is what we need
        /////////////////////////////////////////////////////////////////////////////////////////////
        // uncomment to use this bit timing
        //BRP = 12;
        //T1 = 15;
        //T2 = 8;
 
        /////////////////////////////////////////////////////////////////////////////////////////////
        // Bitrate 125Kbps
        // CLK = 72 Mhz, with BRP = 24 -> 3Mhz CAN clock
        // 3Mhz/125Kbps = 24 TQ
        // T1 = 16 minus 1 for sync = 15
        // T2 = 8
        // 15 + 1 + 8 = 24 TQs which is what we need
        /////////////////////////////////////////////////////////////////////////////////////////////
        // uncomment to use this bit timing
        BRP = 24;
        T1 = 15;
        T2 = 8;
 
        // For 500Kbps you can use BRP=6 and for 1Mbps you can use BRP=3 ...and so on
 
        // Use channel 1
        CAN can = new CAN(CAN.Channel.Channel_1, (uint)(((T2 - 1) << 20) | ((T1 - 1) << 16) | ((BRP - 1) << 0)));
 
        // create a message list of 100 messages
        msgList = new CAN.Message[100];
        for (int i = 0; i < msgList.Length; i++)
            msgList[i] = new CAN.Message();
 
        /*
        // example for sending one message
        // msg ID
        msgList[0].ArbID = 0x55;
        msgList[0].Data[0] = 1;
        msgList[0].Data[1] = 2;
        msgList[0].Data[2] = 3;
        msgList[0].Data[3] = 4;
        msgList[0].Data[4] = 5;
        msgList[0].Data[5] = 6;
        msgList[0].Data[6] = 7;
        msgList[0].Data[7] = 8;
        // Send the 8 bytes for example
        msgList[0].DLC = 8;
        msgList[0].IsEID = false;
        msgList[0].IsRTR = false;
        // Send one messages
        int numberOfMessagesPosted = can.PostMessages(msgList, 0, 1);
        */
 
        // subscribe to events
        can.DataReceivedEvent += new CANDataReceivedEventHandler(can_DataReceivedEvent);
        can.ErrorReceivedEvent += new CANErrorReceivedEventHandler(can_ErrorReceivedEvent);
 
        // sleep forever
        Thread.Sleep(Timeout.Infinite);
    }
 
    static void can_DataReceivedEvent(CAN sender, CANDataReceivedEventArgs args)
    {
        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++)
        {
            Debug.Print("MSG: ID = " + msgList[i].ArbID + " at time = " + msgList[i].TimeStamp);
        }
    }
 
    static void can_ErrorReceivedEvent(CAN sender, CANErrorReceivedEventArgs args)
    {
        Debug.Print(">>> can_ErrorReceivedEvent <<<");
 
        switch (args.Error)
        {
            case CAN.Error.Overrun:
                Debug.Print("Overrun error. Message lost");
                break;
 
            case CAN.Error.RXOver:
                Debug.Print("RXOver error. Internal buffer is full. Message lost");
                break;
 
            case CAN.Error.BusOff:
                Debug.Print("BusOff error. Reset CAN controller.");
                sender.Reset();
                break;
        }
    }
}