CAN
From TinyCLR Wiki
| Start with this tutorial first |
|---|
| 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.
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:
- 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.
- Figure out how many clocks you need to make up one bit. Usually this is 24 or 16. This is called TQ.
- Assign values to T1 and T2 where T1+T2+1=TQ
Let us assume we need 250Kbps.
- From 72Mhz system clock, I want the CAN clock to be 6Mhz so I need to divide by 12 (BRP=12).
- 6Mhz/250kbps = 24 TQ (we usually want 16 or 24).
- 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; } } }


