Hi all,
I am currently trying to get the CAN2 controller to work on the RT1062 with a CAN clock speed of 80MHz. However, when connecting the CAN bus to a CAN-USB converter I am getting errors.
I have a feeling that the prescaler doesn't work. To confirm, is this prescaler (see section 44.7.9.4 Protocol Timing in the IMXRT1060 reference manual) the same as the CAN_CLK_ROOT prescaler CSCMR2[CAN_CLK_PODF] (Figure 14-3. Clock Tree - Part 2 in the IMXRT1060 RM)?
Below my code for the clock settings:
#define FLEXCAN_CLOCK_SOURCE_SELECT (2U)
#define FLEXCAN_CLOCK_SOURCE_DIVIDER (0U)
/* Get frequency of flexcan clock */
#if FLEXCAN_CLOCK_SOURCE_SELECT==(0U)
#define CAN_CLK_FREQ ((CLOCK_GetFreq(kCLOCK_Usb1PllClk) / 8U) / (FLEXCAN_CLOCK_SOURCE_DIVIDER + 1U))
#elif FLEXCAN_CLOCK_SOURCE_SELECT==(1U)
#define CAN_CLK_FREQ (CLOCK_GetFreq(kCLOCK_OscClk))
#elif FLEXCAN_CLOCK_SOURCE_SELECT==(2U)
#define CAN_CLK_FREQ ((CLOCK_GetFreq(kCLOCK_Usb1PllClk) / 6U) / (FLEXCAN_CLOCK_SOURCE_DIVIDER + 1U))
#else
#error "FLEXCAN_CLOCK_SOURCE_SELECT, should be (0U) for /8 or (2U) for /6, see page 1060 of the RT.1060 reference manual"
#endif
CLOCK_SetMux(kCLOCK_CanMux, FLEXCAN_CLOCK_SOURCE_SELECT);
CLOCK_SetDiv(kCLOCK_CanDiv, FLEXCAN_CLOCK_SOURCE_DIVIDER);
if (FLEXCAN_CalculateImprovedTimingValues(flexcanConfig.baudRate, CAN_CLK_FREQ, &timing_config))
{
/* Update the improved timing configuration*/
memcpy(&(flexcanConfig.timingConfig), &timing_config, sizeof(flexcan_timing_config_t));
}
printf("Chosen settings\n");
printf("PROPSEG: %d\n", timing_config.propSeg);
printf("Phase seg 1: %d\n", timing_config.phaseSeg1);
printf("Phase seg 2: %d\n", timing_config.phaseSeg2);
printf("RJW: %d\n", timing_config.rJumpwidth);
printf("preDivider: %d\n", timing_config.preDivider);
printf("CAN clock freq: %d\n", CAN_CLK_FREQ);
Output of the above code:
Chosen settings
PROPSEG: 7
Phase seg 1: 7
Phase seg 2: 7
RJW: 3
preDivider: 4
CAN clock freq: 80000000
As you can see it has a preDivider of 4, which should result in an effective SClock of 20MHz, however I am getting the errors as showed in the screenshot above.
However, when I change the CAN clock settings to 80MHz/4=20MHz:
#define FLEXCAN_CLOCK_SOURCE_SELECT (2U)
#define FLEXCAN_CLOCK_SOURCE_DIVIDER (3U)
Output:
Chosen settings
PROPSEG: 6
Phase seg 1: 7
Phase seg 2: 3
RJW: 3
preDivider: 0
CAN clock freq: 20000000
Now it does work correctly with the CAN-USB controller:
So using a 20MHz CAN_CLK with a preDivider of 0 does work while a 80MHz CAN_CLK with a predivider of 4 which should result in a SClock of 20MHz does not work.
So somehow the predivider does not work or am I misunderstanding something about the predivider?
Solved! Go to Solution.
After updating to the newest fsl libraries (from SDK 2.8.6) everything worked correctly. So the old libraries probably used faulty bit timing calculations.
After updating to the newest fsl libraries (from SDK 2.8.6) everything worked correctly. So the old libraries probably used faulty bit timing calculations.
Hi
1. The maximum CAN_CLK_ROOT frequency is 80MHz in most operating modes but is restricted to 24MHz in low power run and low power idle modes. Therefore make sure that the mode of operation is not causing frequency issues with a higher CAN clock source.
2. The setting for CAN_CTRL1 for 80MHZ CAN clock root and 1MHz CAN bus speed is 0x03a70005
For 20MHz CAN clock root it is 0x13bf0007
Check these with the ones that you calculate to verify that the setting is optimal.
The calculations are made using the uTasker FlexCAN driver's clock calculation code shown below.
Regards
Mark
uTasker project developer for Kinetis and i.MX RT]
Contact me by personal message or on the uTasker web site to discuss professional training or product development requirements
// The best choice of clock input is from the external crystal (lowest jitter), however this may not always enable the best settings to achieve the required speed.
// The choice of clock source is user-defined but this routine tries to achieve best settings using highest time quanta resolution.
//
// There are up to 25 time quanta in a CAN bit time and the bit frequency is equal to the clock frequency divided by the quanta number (8..25 time quanta range)
// There is always a single time quanta at the start of a bit period called the SYNC_SEG which cannot be changed (transitions are expected to occur on the bus during this period)
// The sampling occurs after time segment 1, which is made up of a propagation segment (1..8 time quanta) plus a phase buffer segment 1 (1..8 time quanta),
// followed by time segment 2, made up of phase buffer segment 2 (2..8 time quanta)
//
// CAN standard compliant bit segment settings give the following ranges (re-synchronisation jump width of 2 is used since it is compliant with all)
// Time segment 1 should be 5..10 when time segment 2 is 2 (min/max time quanta per bit is 8/13)
// Time segment 1 should be 4..11 when time segment 2 is 3 (min/max time quanta per bit is 8/15)
// Time segment 1 should be 5..12 when time segment 2 is 4 (min/max time quanta per bit is 10/17)
// Time segment 1 should be 6..13 when time segment 2 is 5 (min/max time quanta per bit is 12/19)
// Time segment 1 should be 7..14 when time segment 2 is 6 (min/max time quanta per bit is 14/21)
// Time segment 1 should be 8..15 when time segment 2 is 7 (min/max time quanta per bit is 16/23)
// Time segment 1 should be 9..16 when time segment 2 is 8 (min/max time quanta per bit is 18/25)
//
static unsigned long fnOptimalCAN_clock(unsigned short usMode, unsigned long ulSpeed)
{
unsigned long ulClockSourceFlag = EXTAL_CLK_SOURCE;
unsigned long ulClockSpeed;
unsigned long ulLowestError = 0xffffffff;
unsigned long ulCanSpeed;
unsigned long ulError;
unsigned long ulPrescaler;
int iTimeQuanta = 25; // highest value for highest control resolution
int iBestTimeQuanta = 25;
unsigned long ulBestPrescaler = 0;
#if defined ERR050235 && defined CAN_CLK_ROOT_FROM_PLL3_SW_CLK_6
// When selecting the CCM CAN clock source with CAN_CLK_SEL set to 2, the UART clock gate
// will not open and CAN_CLK_ROOT will be off. Therefore we workaround this by opening any LPUART clock gate
//
POWER_UP_ATOMIC(5, LPUART1_CLOCK);
#endif
ulClockSpeed = CAN_CLK_ROOT_FREQUENCY;
while (iTimeQuanta >= { // test for best time quanta
ulCanSpeed = (ulClockSpeed/iTimeQuanta); // speed without prescaler
ulPrescaler = ((ulCanSpeed + (ulSpeed/2))/ulSpeed); // best prescale value
if (ulPrescaler > 256) {
ulPrescaler = 256; // maximum possible prescale divider
}
else if (ulPrescaler == 0) {
ulPrescaler = 1;
}
ulCanSpeed /= ulPrescaler;
if (ulCanSpeed >= ulSpeed) { // determine the absolute error value with this quanta setting
ulError = (ulCanSpeed - ulSpeed);
}
else {
ulError = (ulSpeed - ulCanSpeed);
}
if (ulError < ulLowestError) { // if this is an improvement
ulLowestError = ulError;
iBestTimeQuanta = iTimeQuanta; // best time quanta value
ulBestPrescaler = ulPrescaler;
}
iTimeQuanta--;
}
ulBestPrescaler--; // convert to register setting value
ulBestPrescaler <<= 24; // move the prescale value into position
if (iBestTimeQuanta >= 18) { // determine the phase buffer length value
ulBestPrescaler |= PHASE_BUF_SEG2_LEN8;
iBestTimeQuanta -= (8 + 1); // remaining time quanta (time segment 1) after removal of the time segment 2 and the SYN_SEG
}
else if (iBestTimeQuanta >= 16) {
ulBestPrescaler |= PHASE_BUF_SEG2_LEN7;
iBestTimeQuanta -= (7 + 1);
}
else if (iBestTimeQuanta >= 14) {
ulBestPrescaler |= PHASE_BUF_SEG2_LEN6;
iBestTimeQuanta -= (6 + 1);
}
else if (iBestTimeQuanta >= 12) {
ulBestPrescaler |= PHASE_BUF_SEG2_LEN5;
iBestTimeQuanta -= (5 + 1);
}
else if (iBestTimeQuanta >= 10) {
ulBestPrescaler |= PHASE_BUF_SEG2_LEN4;
iBestTimeQuanta -= (4 + 1);
}
else {
ulBestPrescaler |= PHASE_BUF_SEG2_LEN3;
iBestTimeQuanta -= (3 + 1);
}
if ((iBestTimeQuanta & 0x1) != 0) { // odd
iBestTimeQuanta /= 2; // PROP_SEG and PSEG1 to achieve time segment 1
ulBestPrescaler |= iBestTimeQuanta; // set propogation bit time (1 more than phase buffer segment 1)
iBestTimeQuanta--;
ulBestPrescaler |= (iBestTimeQuanta << 19); // set phase buffer segment 1
}
else { // even
iBestTimeQuanta /= 2; // PROP_SEG and PSEG1 to achieve time segment 1 and phase buffer segment 1
iBestTimeQuanta--;
ulBestPrescaler |= ((iBestTimeQuanta << 19) | (iBestTimeQuanta));// set equal propogation bit times
}
return (RJW_2 | ulClockSourceFlag | ulBestPrescaler); // initialise the CAN controller with the required speed and parameters
}
Hi,
Thank you for your interest in NXP Semiconductor products and for the opportunity to serve you.
Firstly, the above errors are caused by the unmatched rate clock instead of the Serial Clock, the rate clock formula is below.
Next, the number of Time Quanta is the sum of 1 + (PSEG1 + 1) + (PSEG2 + 1) + (PROPSEG + 1).
I think this information can explain your question.
In further, you can learn the information about the protocol timing in the section: 44.7.9.4 Protocol Timing in i.MX RT1060's RM.
Have a great day,