Hi
I just checked out the CAN driver progress and have 2 items.
1. Freescale recommends using the crystal clock source rather than the peripheral clock since it has lower jitter.
2. I have posted my code below which calculates the settings based on required CAN bus speed (working out the time quanta for PROP_SEG and PSEG1 to achieve compliant settings in each case). It requires a bit more code and the calculation to be performed but allows for more flexibility that a few fixed speeds.
The return value from fnOptimalCAN_clock(usMode, ulSpeed) can be written directly to the CAN_CTRL1 register. As can be seen the mode allows the clock source to be specified and also the caluclation to be overwridden if the user prefers specifying the CAN_CTRL1 register value directly.
Regards
Mark
// 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 can not 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 complient 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;
if (CAN_USER_SETTINGS & usMode) {
return ulSpeed; // the user is passing optimal configuration settings directly
}
if (CAN_PLL_CLOCK & usMode) { // use the bus clock rather than crystal input directly
ulClockSpeed = (BUS_CLOCK); // the clock speed for calculation use is the bus speed
ulClockSourceFlag = CLK_SRC_PERIPH_CLK; // peripheral clock will be used as clock source
}
else {
ulClockSpeed = _EXTERNAL_CLOCK; // the clock speed for calculation use is the external/crystal clock speed
}
while (iTimeQuanta >= 8) { // 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
}
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--;
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) { // 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
}
I just checked out the CAN driver progress and have 2 items.
1. Freescale recommends using the crystal clock source rather than the peripheral clock since it has lower jitter.
2. I have posted my code below which calculates the settings based on required CAN bus speed (working out the time quanta for PROP_SEG and PSEG1 to achieve compliant settings in each case). It requires a bit more code and the calculation to be performed but allows for more flexibility that a few fixed speeds.
The return value from fnOptimalCAN_clock(usMode, ulSpeed) can be written directly to the CAN_CTRL1 register. As can be seen the mode allows the clock source to be specified and also the caluclation to be overwridden if the user prefers specifying the CAN_CTRL1 register value directly.
Regards
Mark
// 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 can not 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 complient 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;
if (CAN_USER_SETTINGS & usMode) {
return ulSpeed; // the user is passing optimal configuration settings directly
}
if (CAN_PLL_CLOCK & usMode) { // use the bus clock rather than crystal input directly
ulClockSpeed = (BUS_CLOCK); // the clock speed for calculation use is the bus speed
ulClockSourceFlag = CLK_SRC_PERIPH_CLK; // peripheral clock will be used as clock source
}
else {
ulClockSpeed = _EXTERNAL_CLOCK; // the clock speed for calculation use is the external/crystal clock speed
}
while (iTimeQuanta >= 8) { // 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
}
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--;
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) { // 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
}