MPC5643L FlexCAN pre-scaler

cancel
Showing results for 
Search instead for 
Did you mean: 

MPC5643L FlexCAN pre-scaler

1,690 Views
Lundin
Senior Contributor IV

I'm using MPC5643L with Codewarrior 2.10.

 

I am trying to correctly configure the pre-scaler clock for FlexCAN. According to the manual, f_canclk / (bitrate * tq_n) = PRESDIV-1, where f_canclk is the frequency of the CAN clock (CPI lock), bitrate is the desire CAN baudrate, tq_n is the desired number of time quanta per byte and PRESDIV is the register value.

 

If I follow the above formula from manual, I get exactly twice the desired baudrate.

 

My clock source is the oscillator clock of 8MHz. I want to setup the baudrate to 250kbps, with 16tq per byte. So my formula calculates 8000khz / (250khz * 16) = PRESDIV-1,  --> 2 = PRESDIV-1, --> PRESDIV=1.

 

This gives me a baudrate of 500kbps, measured with scope and analyser software both. Twice as large as expected. What am I missing?

 

The oscillator clock is measured to 8MHz with oscilloscope. Other MCU peripherals on the same board behave correctly, with correctly pre-scale values.

 

16 tq gives me: prop_seg = 11tq, phase_seg1 = 2tq, phase_seg 2 = 2tq, rjw = 2tq. This gives a sample point at 87.5% which is the recommendated sample point location by CANopen DS301 vers4.2, §5.4.

 

Here is the baudrate calculation code:

 

static inline can_status_t can_init_baudrate (uint32_t*          ctrl_presdiv,                                               const baudrate_t*  selected_baudrate,                                              uint32_t           clock_khz){  /***** Calculate baudrate *****/  uint32_t freq_tq;                              // time quanta frequency in khz  int32_t  s_presdiv;                            // signed temporary presdiv                     freq_tq   = selected_baudrate->tq_total *               selected_baudrate->baudrate_khz;  s_presdiv = (int32_t)(clock_khz / freq_tq)-1;  // calculate clock and compensate with -1 for register format    if(s_presdiv < 0)                              // insufficient oscillator clock etc  {    return CAN_ERR_PRESCALING;  }    /***** Convert to FlexCAN register format *****/  *ctrl_presdiv = (uint32_t)s_presdiv;  *ctrl_presdiv <<= 24;    return CAN_OK;}

 

 

If I simply change the formula to

 

s_presdiv = (int32_t)(clock_khz / freq_tq)*2-1;

 

then everything works correctly. I don't understand why.

Tags (1)
0 Kudos
6 Replies

243 Views
Lundin
Senior Contributor IV

Alright, so it seems like the problem is not in my software nor hardware, but in FlexCAN. I isolated the problem to how the tq segments are set. Apparently FlexCAN either cannot handle a too small phase2 segment, or it makes strange assumptions over how the tq segments should be. Whatever is the case, it is seemingly not documented anywhere.

 

I just fiddled around with the tq settings and got very strange results. With one tq setting, everything works just fine. With another, FlexCAN runs amok and sets the baudrate to a rubbish value. I don't know why this happens.

 

The values in the table below work, tested with trial & error. If I cange the size of one segment or the other, FlexCAN might apparently run amok. Min & Max is the allowed range for the location of the sample point, in CANopen DS301. This is part of a larger spread sheet where I also check if it is possible to use a certain amount of tq with the given oscillator clock, 8MHz in this case, and within the 1% inaccuracy tolerance.

 

Baudrate kHz    tq_tot    tq_sync tq_prop  tq_pseg1 tq_pseg2 rjw sample_point    Min    Max

 

1000    8    1    3    2    2    2    75,0%    75,0%    90,0%
800    10    1    3    4    2    2    80,0%    75,0%    90,0%
500    16    1    8    5    2    2    87,5%    85,0%    90,0%
250    16    1    8    5    2    2    87,5%    85,0%    90,0%
125    16    1    8    5    2    2    87,5%    85,0%    90,0%
50      16    1    8    5    2    2    87,5%    85,0%    90,0%
20      16    1    8    5    2    2    87,5%    85,0%    90,0%
10      16    1    8    5    2    2    87,5%    85,0%    90,0%


For example, I tried to use fewer tq. I tried 250kbps, 8tq, where prop=4, phase1=2, phase2=1, rjw=2. This gives a sample point at exactly 87.5%. Prescaler = 8000kHz / (250kbps * 8) = 4. PRESDIV=3.

 

Based on this, my algorithm writes 0348 0003 hex to the CTRL register. This causes FlexCAN to go berserk on the CAN bus, picking a completely wrong baudrate of around 40 kbps and ignoring bus arbitration, killing the bus.

0 Kudos

243 Views
Lundin
Senior Contributor IV

The issue is resolved: FlexCAN cannot have a phase2 segment smaller than 1. This is mentioned in a note in the manual:

 

"For bit time calculations, use an IPT (Information Processing Time) of 2, which is the value implemented in the FlexCAN
module. The Information Processing Time (IPT) is the time required for the logic to determine the bit level of a sampled bit. The IPT begins at the sample point, is measured in TQ and is fixed at 2TQ for the FlexCAN module."

0 Kudos

243 Views
TomE
Specialist I

Congratulations on finding your problem.

 

You might want to read up on all the other limitations and restrictions in case you manage another "unsupported setting".

 

When CAN is used in a car, someone has to have worked out all the timing restrictions and delay parameters and come up with an optimal set of parameters, working from detailed rules that I wouldn't expect Freescale to have to detail in their manuals. The expert is meant to be working from other "master dource documents". Otherwise, if you're building a part for a major supplier, then they provide detailed CAN timing settings for the particular vehicle/application and the programmer simply copies the settings they provide.

 

The "Old Testament" for CAN is the followingt:

 

http://www.semiconductors.bosch.de/media/pdf/canliteratur/can2spec.pdf

 

The "New Testament" is ISO 11898-1.

 

I had problems with a badly documented microchip part and detailed theinvestigations here:

 

http://www.microchip.com/forums/tm.aspx?m=619182

 

Here's an extract of all the relevant timing rules - watch out for the RJW limitations too (what gave me problems);

 

10 BIT TIMING REQUIREMENTS
...
- SYNCHRONIZATION SEGMENT (SYNC_SEG)
- PROPAGATION TIME SEGMENT (PROP_SEG)
- PHASE BUFFER SEGMENT1 (PHASE_SEG1)
- PHASE BUFFER SEGMENT2 (PHASE_SEG2)
...
Length of Time Segments
- SYNC_SEG is 1 TIME QUANTUM long.
- PROP_SEG is programmable to be 1,2,...,8 TIME QUANTA long.
- PHASE_SEG1 is programmable to be 1,2,...,8 TIME QUANTA long.
- PHASE_SEG2 is the maximum of PHASE_SEG1 and the

  INFORMATION PROCESSING TIME
- The INFORMATION PROCESSING TIME is less than or equal

  to 2 TIME QUANTA long.
...
RESYNCHRONIZATION JUMP WIDTH
As a result of RESYNCHRONIZATION PHASE_SEG1 may be lengthened or
PHASE_SEG2 may be shortened. The amount of lengthening or shortening of the
PHASE BUFFER SEGMENTs has an upper bound given by the
RESYNCHRONIZATION JUMP WIDTH. The RESYNCHRONIZATION JUMP WIDTH
shall be programmable between 1 and min(4, PHASE_SEG1).

 

Tom


0 Kudos

243 Views
TomE
Specialist I

That's a mystery.

 

This doesn't explain your problem, but I'd change it for a start:

 

  /***** Convert to FlexCAN register format *****/  *ctrl_presdiv = (uint32_t)s_presdiv;  *ctrl_presdiv <<= 24;

It is not clear that "*ctrl_presdiv" is pointing to the hardware control register, but if it is it could be dangerous. That control register doesn't have 32 read-write bits in it, and the compiler might be doing something strange with it on the assumption that is is fully read-write. I'd check the disassembly to see if it is doing anything strange, and would change it to something more like "*ctrl_presdiv = ((uint32_t)s_presdiv) << 24).

 

It would be cleaner to do all the maths unsigned and subtract the one at the end during the "convert to register format" part as well. You might also want to check that PRESDIV isn't too large as well as being too small.

 

That function doesn't just set the presdiv field in the ctrl register - it wipes out all the other settings in that register. It might be safer to rewrite the function so it only changes the presdiv bits, or returns the value and lets the caller write to that register in one place rather than having the hardware register written in multiple places.

 

Have you tried running it from the other clock to see if the factor-of-two problem remains, or if it is only happening with the oscillator as the source? Read the "NOTE" in the section "CLK_SRC — CAN Engine Clock Source" in case your CPU only has one clock source. That chapter is written for the "generic controller" and not the controller "as built into that chip". There should be another section clarifying the "installation" of that part and answering the uncertainties in that note, but I doubt if there is.

 

Tom

 

 

 

 

0 Kudos

243 Views
Lundin
Senior Contributor IV

Thanks for your reply.

 

ctrl_presdiv is pointing at a local variable. can_init_baudrate() is one of several functions doing pre-calculations for the CTRL register. I have a similar one for calculating tq segments etc. When everything is done, I merely bitwise OR the results of every function and write that to CTRL with a single, atomic write.

 

(Had ctrl_presdiv been pointing directly at the hardware register, it would have to be declared volatile, or one would get warnings for typecasting away "volatile-correctness". And perhaps various optimizer bugs on top of it.)

 

I'm trying to write portable code, so I can't do the calculations on unsigned. If the result is less than zero, there would be integer wrap-around, which is undefined behavior in C. I can't write code relying on undefined behavior. It is a good idea to check that PRESDIV isn't too large, though - I'll implement that.

 

I haven't tried running it from the internal PLL yet, it only seemed more complicated. Plus there are various app note concerns about accuracy when using the PLL, CAN only tolerates 1% inaccuracy. I can give it a shot I guess, but that doesn't explain why the osc clock isn't divided as expected.

0 Kudos

243 Views
TomE
Specialist I

I meant something like this, using unsigned arithmetic and subtracting the one later.

 

  u_presdiv = (int32_t)(clock_khz / freq_tq);    if ((u_presdiv == 0) || (u_presdiv >= 255))    return CAN_ERR_PRESCALING;  }    /***** Convert to FlexCAN register format *****/  *ctrl_presdiv = (u_presdiv- 1) << 24;

Otherwise I think you'll need to do some more testing with other peripherals scaling from the oscillator.

 

> CAN only tolerates 1% inaccuracy.

 

With the right CAN parameters, a low baud rate and a short bus it can be 1.58%. Do you have a spec for the PLL stability? Since it should be locked to the crystal it shouldn't be able to get too far out of phase with the crystal. The high-frequency jitter might be a lot, but at CAN frequencies it should be OK.

 

Tom

 

0 Kudos