Main Site Documentation

G400 CAN bitrate


#1

I have a G400 Beta kit + CAN DW module (bus termination is ok because if I connect the system to EMX everything is working just fine). I want to configure CAN for 1Mbps operation, but don’t exactly understand how to do it. If I look at the CAN constructor:

CAN(GHI.Premium.Hardware.CAN.Channel channel, uint bitrate, int receiveBufferSize)

I guess [em]bitrate[/em] is directly written to CAN_BR register of the Atmel AT91SAM9 chip. Am I right?

Assuming I am, I then try to follow an example in the AT91SAM9x25 manual and initialize CAN with the following values:

var brp = 24;
var sjw = 3;
var propag = 2;
var phase1 = 5;
var phase2 = 5;

_can = new CAN(CAN.Channel.Channel_2, (uint)((brp << 16) + (sjw << 12) + (propag << 8) + (phase1 << 4) + (phase2 << 0)), 1000);

However, I only get lots of BusOff errors. What am I doing wrong?..


#2

@ Simon from Vilnius -
Here is an example for config CAN on G400


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

namespace G400_TestCAN
{
    public class Program
    {
        static InputPort button = new InputPort((Cpu.Pin)(1 * 32 + 14), false, Port.ResistorMode.PullUp); // G400 socket 8, pin3, PB14
        static OutputPort led = new OutputPort((Cpu.Pin)(3 * 32 + 3), true); // led pd3

        //static InputPort button = new InputPort((Cpu.Pin)(30), false, Port.ResistorMode.PullUp); // G400 socket 8, pin3, PB14
        //static OutputPort led = new OutputPort((Cpu.Pin)(47), true); // led pd3
        static CAN.Message[] msgList;
        public static void Main()
        {            

            // 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();
            Utility.SetLocalTime(new DateTime(2013, 7, 3, 12, 1, 0));
            while (button.Read())
           
            {
                led.Write(true);
                Thread.Sleep(50);
                led.Write(false);
                Thread.Sleep(50);
            }
            // Use channel 1 - 125K
            uint phase2 = 6;
            uint phase1 = 6;
            uint prog = 0;
            uint sjw = 3;
            uint br = 65;
            uint baudrate = phase2 | (phase1 << 4) | (prog << 8) | (sjw << 12) | (br << 16); // 125Kb/s            
            CAN can = new CAN(CAN.Channel.Channel_1, baudrate);

            // Subscribe to events
            can.DataReceivedEvent += new CANDataReceivedEventHandler(can_DataReceivedEvent);
            can.ErrorReceivedEvent += new CANErrorReceivedEventHandler(can_ErrorReceivedEvent);
            
            

            //// msg ID
            msgList[0].ArbID = 0x1;

            // Send the 8 bytes for example
            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;

            msgList[0].DLC = 8;
            msgList[0].IsEID = false;
            msgList[0].IsRTR = false;
            int numberOfMessagesPosted;

            int cnt = 0;
            while (true)
            {
               
                Thread.Sleep(500);
                if (button.Read() == false)
                {
                //    // Send one message
                    msgList[0].ArbID = (byte)(cnt+1);

                    // Send the 8 bytes for example
                    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;

                    msgList[0].DLC = 8;
                    msgList[0].IsEID = false;
                    msgList[0].IsRTR = false;
                    numberOfMessagesPosted = can.PostMessages(msgList, 0, 1);
                    cnt++;
                }
            }
            // 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 + " len = " + msgList[i].DLC + " data= "
                    + msgList[i].Data[0] + "-"
                    + msgList[i].Data[1] + "-"
                    + msgList[i].Data[2] + "-"
                    + msgList[i].Data[3] + "-"
                    + msgList[i].Data[4] + "-"
                    + msgList[i].Data[5] + "-"
                    + msgList[i].Data[6] + "-"
                    + msgList[i].Data[7] + ", 29 bits = " + msgList[i].IsEID + ", RTR =" + msgList[i].IsRTR + ", 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;
            }
        }

    }
}


For 10K speed, I think
// Use channel 1 - 10Kb
uint phase2 = 6;
uint phase1 = 6;
uint prog = 0;
uint sjw = 3;
uint br = 832;
For 25K speed, I think
// Use channel 1 - 25Kb
uint phase2 = 6;
uint phase1 = 6;
uint prog = 0;
uint sjw = 3;
uint br = 132;
For 50K speed, I think
// Use channel 1 - 50Kb
uint phase2 = 6;
uint phase1 = 6;
uint prog = 0;
uint sjw = 3;
uint br = 165;
For 250K speed, I think
// Use channel 1 - 250Kb
uint phase2 = 6;
uint phase1 = 6;
uint prog = 0;
uint sjw = 3;
uint br = 32;
For 500Kspeed, I think
// Use channel 1 - 500Kb
uint phase2 = 5;
uint phase1 = 5;
uint prog = 2;
uint sjw = 3;
uint br = 15;
For 800Kspeed, I think
// Use channel 1 - 800Kb
uint phase2 = 5;
uint phase1 = 4;
uint prog = 3;
uint sjw = 3;
uint br = 9;
For 100Mb speed, I think
// Use channel 1 - 1Mb
uint phase2 = 1;
uint phase1 = 1;
uint prog = 2;
uint sjw = 1;
uint br = 15;

If you want more details about it, I think you need to refer AT91SAM9X35 Document.


#3

Thanks! Now I can receive messages! Two problems, however, still remain:

  1. When I send a message, I still get a BusOff error (but the message is actually sent).

  2. Also, I don’t fully understand your calculations. If I look in the manual page 876, I see that

T_bit=(BRP+1)/MCK+1+(PROPAG+1)+(PHASE1+1)+(PHASE2+1),

which simplifies to

T_bitMCK=(BRP+1)(4+PROPAG+PHASE1+PHASE2).

Initially I thought MCK is 400MHz. But know I see you are more likely using 128MHz, or otherwise I cannot get the numbers you are showing. For example, in your code bit rate is 125kbps, so:

MCK/125k=(65+1)(4+0+6+6) => MCK=6616*125k=132MHz.

So… What is G400 clock frequency then?.. Or is there another aspect I do not know?


#4

The G400 has a few frequencies that are used. There is the Main Processor, which is 400 MHz, the Peripheral Clock, which is about 133 MHz, and the Main Oscillator, which is 12 MHz. Calculating the Bitrate can be tricky. You could try to calculate on these three clocks and see what results you get.


#5

Alright, assuming CAN clock is 133MHz, I finally found some settings for 1Mbps that do not produce errors:


var brp = 6;
var sjw = 1;
var propag = 1;
var phase1 = 7;
var phase2 = 7;

_can = new CAN(CAN.Channel.Channel_1, (uint)((brp << 16) + (sjw << 12) + (propag << 8) + (phase1 << 4) + (phase2 << 0)), 1000);

Will connect it to our monster system tommorow. Hopefully G400 will be able to deal with 2000 CAN messages per second :slight_smile:


#6

I’m finishing a short essay of How I Discovered CAN In G400. Will post it here today. Unfortunately, there’s no user editable wiki left…


#7

So, after spending a few hours reading manuals, this is what I found about CAN bitrate calculation for G400.

First, a few assumptions, that are not obvious and were not written anywhere — until now:

[ol]
Peripheral clock for G400 is set to 133MHz.
Parameter [em]bitrate [/em]in CAN constructor

CAN(GHI.Premium.Hardware.CAN.Channel channel, uint bitrate, int receiveBufferSize)

is directly written to AT91SAM9 register CAN_BR (manual section 41.9.6)[/ol]

There are a few fields we have to set inside that register: BRP, SJW, PROPAG, PHASE1 and PHASE2. After spending some time with the manual, I’ve simplified things to the following formula:

T_bit*MCK=(BRP+1)*(4+PROPAG+PHASE1+PHASE2)

Now, if we express MCK in MHz, and T_bit (that is, bit time) in microseconds, we get:
[b]

T_bit*133=(BRP+1)*(4+PROPAG+PHASE1+PHASE2)

[/b]
Two important things here:
ul is called Time Quantum (TQ) and must be between 8 and 25, preferably 16;
both sides of the equation is a product.[/ul]

Formal part is done, lets move to examples!

=== Example 1 — 1 Mbps ===
For 1Mbps speed, bit time is 1 μs, so we have:

(BRP+1)*(4+PROP+PHASE1+PHASE2)=1*133=133

We need to split 133 into a product of two round numbers, and one part of the product shoulb be as close to 16 (TQ restriction!) as possible. There aren‘t many options: 133=7*19.
Since (4+PROP+PHASE1+PHASE2) has to be between 8 and 25 (preferably 16), we have only one option:

(BRP+1)=7
(4+PROP+PHASE1+PHASE2)=19

From there,

BRP=6
PROP+PHASE1+PHASE2=15

Weve got BRP already, now its time to deal with PROP. It depends on bus speed and length and has to be calculated (see the manual, section 41.7.4.1), but its a number between 0 and 8. For higher speeds and short lines it may be set to 1 or 2, and it may be 0 for lower speeds. Ive chosen 1 for 1Mbit, although it may not be entirely correct (2 would be closer to correct value), but since its working totally fine, I don’t care much. PROP is a relaxed parameter, it seems. So PROP=1. Then its easy:

PHASE1+PHASE2=14.

PHASE1 and PHASE2 should be kept equal, so we choose 7 and 7.
If one decides to be entirely correct, PROP may be set to 2. Then we choose PH1=6 and PH2=7 (PHASE2 has to be greater or equal to PHASE1).
SJW is something between 0 and 3. It cannot be greater that PH1, so in this case we choose 3.
Calling CAN constructor is all that’s left:


_can = new CAN(CAN.Channel.Channel_1, (uint)((brp << 16) + (sjw << 12) + (propag << 8) + (phase1 << 4) + (phase2 << 0)));

=== Example 2 — 300 kbps ===
In this case, we have


(BRP+1)*(4+PROP+PHASE1+PHASE2)=1/0.3 *133~443.

Unfortunately, 443 is a prime number, so we cannot split it. But we can make a little error and use 444. 444 is 22337=1237. In this case TQ=12 (37 is too much). A bit low. But what if we try 442? 442=21317=26*17. Better! We choose TQ=17. Then we have:


(BRP+1)=26
(4+PROP+PHASE1+PHASE2)=17

Bit rate is lower, so we can safely assume PROP=1. Then PHASE1=PHASE2=6.
SJW is, again, 3.
And, of course, we apply those settings:


_can = new CAN(CAN.Channel.Channel_1, (uint)((brp << 16) + (sjw << 12) + (propag << 8) + (phase1 << 4) + (phase2 << 0)));


#8

Dat never came back to explain how he made his calculation, but I believe I now know that. He tries to fix TQ to 16 in all cases, but that produces additional errors in rounding. I don’t know how important that is.

Concerning his 1 Mbps example, I think he simply switched numbers, fixing TQ accidentaly to 8 instead of 16 (8*16=128). That’s why it resulted in BusOff errors for me. Since those values are on documents section, I think they should be corrected.


#9

@ Simon from Vilnius -

Hello all

Simon from Vilnius’s values are better than my values. We will correct the document.


#10

I’m not very competent in this low level field, but I believe figure 41.4 from the manual answers your question…


#11

If I understand figure 41.4 correctly, PROP should also be included in sampling point calculation. It that case it is (1+PROP+1+PHASE1+1)/TQ, which is ~60% in my case. The example provided in the manual gives ~63% also…


#12

hi, all

in pdf we can find br can be bigger that 127 so values 832, 132, 165 not correct i think
i have problem to reach baud rates less that 50kbps

i.e. i need to set 33.3kbps
have someone tested values less that 50kbps and what about br > 127?

regards


#13

Indeed that’s a good point! According to manual and my calculations, the lowest bitrate you can get is ~41kbps.

I guess the only way to make it work at lower bitrates would be lowering the peripheral clock? But then other things may stop working…


#14

so max ~300Mhz for master clock to reach this 33.3kbps


#15

here is code provided by atmel for IAR examples

uint8_t CAN_CalcBaudrate(Can *pCan, uint32_t dwBaudrate, uint32_t dwMck)
{
uint32_t BRP, PROPAG, PHASE1, PHASE2, SJW;
uint8_t TQ;
uint32_t t1t2;
if (dwBaudrate >= 1000) TQ = 8;
else TQ = 16;
BRP = (dwMck / (dwBaudrate * 1000 * TQ)) - 1;
if (BRP == 0) {
return 0;
}

/* Timing delay:
   Delay Bus Driver     - 50ns
   Delay Receiver       - 30ns
   Delay Bus Line (20m) - 110ns */
if ( (TQ * dwBaudrate * 2 * (50+30+110)/1000000) >= 1 )
    PROPAG = (TQ * dwBaudrate * 2 * (50+30+110)/1000000) - 1;
else
    PROPAG = 0;
t1t2 = TQ - 1 - (PROPAG + 1);

if ( (t1t2 & 0x01) == 0x01 ) {
    PHASE1 = ((t1t2 - 1) / 2) - 1;
    PHASE2 = PHASE1 + 1;
}
else {
    PHASE1 = ((t1t2) / 2) - 1;
    PHASE2 = PHASE1;
}

if ( 1 > (4/(PHASE1 + 1)) ) SJW = 3;
else                        SJW = PHASE1;

if ( (PROPAG + PHASE1 + PHASE2) != (TQ - 4) ) {
    return 0;
}

pCan->CAN_BR = CAN_BR_PHASE2(PHASE2)
             | CAN_BR_PHASE1(PHASE1)
             | CAN_BR_PROPAG(PROPAG)
             | CAN_BR_SJW(SJW)
             | CAN_BR_BRP(BRP)
             | CAN_BR_SMP_ONCE;
return 1;

}

codded in C but easy can be converted to C#


#16

ok I found solution but not sure this can be done in NETMF on the fly

all we need is set clock divider for CAN peripheral this not effects any other peripherals or MCU master clock by writing new value to PMC_PCR register

by default there is no divider set
PMC_PCR - register address 0xFFFFFD0C

*(0xFFFFFD0C) = (1 << 28) | (div << 16) | (1 << 12) | 29

29 for CAN0
30 for CAN1

div = 0 PERIPH_DIV_MCK Peripheral clock is MCK
div = 1 PERIPH_DIV2_MCK Peripheral clock is MCK/2
div = 2 PERIPH_DIV4_MCK Peripheral clock is MCK/4
div = 3 PERIPH_DIV8_MCK Peripheral clock is MCK/8

so we can easy get bitrate less that 40kbps


#17

@ Simon from Vilnius -

hi Simon

i see you working a lot with G400 board and RLP stuff

have you managed to solve your RLP problems?
you working with Keil MDK right
I have found similar problems with IAR too
there is no problem with RLPLite because is posible to load plain bin file but G400 not supports RLPLite

is there some tricks to load plain binary dump using RLP maybe?

regards Raimis


#18

@ Raimis - yeah we kind of solved our problems. We do not use Keil anymore, we switched to emIde/EmBlocks.

As far as I remember, you can load plain compiled binary file exactly the same way with RLP (using AddressSpace class to load the file, and then passing address to the procedure constructor).


#19

thanks for reply

one more thing i`m interesting too

do NETMF uses interrups when processing CAN messages

i would like to use me plain native CAN funcs with NETMF together
problem is that managed code not fast enough to receive block of messages but sending speed is good for me


#20

What’s your target? Even with GHI CAN impementation your can easily receive 2000-3000 messages per second. Our problem was that some of them disappear, though…

And as far as I understand, NETMF code does not interrupt RLP code.