HCS12 MSCAN on-the-fly change bit rate

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

HCS12 MSCAN on-the-fly change bit rate

Jump to solution
2,341 Views
HenryL
Contributor III

In my application, the user can configure the bit rate of the CAN bus.

On startup, CAN peripheral is configured to a default bit rate.

During operation, a command is given to change the bit rate to a handful of available options, in which I call a function that handles this change. Place the peripheral into initialization mode (INITRQ), assign the appropriate values to CANBTR1 & CANBTR0, then takes it out of initialization mode.

 

Using the same come to set bitrate on startup works as it should. However, I get inconsistant results when used during normal operation to change bitrate on the fly. Sometimes it works perfectly, sometimes it would stay at the previously assigned bitrate. The interface is not the issue, it definitely has something to do with the registers. Am I missing something?

 

Here's is my code, I've shortened it for simplicity:

 

CAN0CTL0 |= INITRQ;        //request init mode
while (!(CAN0CTL1 & INITAK));    //wait for acknowledge

//set bit timing registers

//set to 500Kbps
CAN0BTR0 = 0;
CAN0BTR1 = TSEG12 | TSEG20;

CAN0CTL0 &= ~INITRQ;        //request exit init mode
while (CAN0CTL1 & INITAK);    //wait for acknowledge

Labels (1)
0 Kudos
Reply
1 Solution
1,089 Views
HenryL
Contributor III

problem solved. It was a problem in another part of the code that is affected by having the CAN periph stopped.


Thanks for the help.

View solution in original post

0 Kudos
Reply
6 Replies
1,089 Views
Lundin
Senior Contributor IV

Feel free to use the MSCAN code I'm using myself (tested & in production on several S08 and S12).

 

/* h file */

 

#define CAN0 (&CAN0CTL0)
#define CAN1 (&CAN1CTL0)
#define CAN2 (&CAN2CTL0)
#define CAN3 (&CAN3CTL0)
#define CAN4 (&CAN4CTL0)

#define reg_CANCTL0(x) (*((CAN_port)x + 0x00)) /* Control Register 0 */
#define reg_CANCTL1(x) (*((CAN_port)x + 0x01)) /* Control Register 1 */
#define reg_CANBTR0(x) (*((CAN_port)x + 0x02)) /* Bus Timing Register 0 */
#define reg_CANBTR1(x) (*((CAN_port)x + 0x03)) /* Bus Timing Register 1 */
#define reg_CANRFLG(x) (*((CAN_port)x + 0x04)) /* Receiver Flag Register */
#define reg_CANRIER(x) (*((CAN_port)x + 0x05)) /* Receiver Interrupt Enable Register */
#define reg_CANTFLG(x) (*((CAN_port)x + 0x06)) /* Transmitter Flag Register */
#define reg_CANTIER(x) (*((CAN_port)x + 0x07)) /* Transmitter Interrupt Enable Register */
#define reg_CANTARQ(x) (*((CAN_port)x + 0x08)) /* Transmitter Message Abort Control */
#define reg_CANTAAK(x) (*((CAN_port)x + 0x09)) /* Transmitter Message Abort Control */
#define reg_CANTBSEL(x) (*((CAN_port)x + 0x0A)) /* Transmit Buffer Selection */
#define reg_CANIDAC(x) (*((CAN_port)x + 0x0B)) /* Identifier Acceptance Control Register */
#define reg_CANRXERR(x) (*((CAN_port)x + 0x0E)) /* Receive Error Counter Register */
#define reg_CANTXERR(x) (*((CAN_port)x + 0x0F)) /* Transmit Error Counter Register */
#define reg_CANIDAR0(x) (*((CAN_port)x + 0x10)) /* Identifier Acceptance Register 0 */
#define reg_CANIDAR1(x) (*((CAN_port)x + 0x11)) /* Identifier Acceptance Register 1 */
#define reg_CANIDAR2(x) (*((CAN_port)x + 0x12)) /* Identifier Acceptance Register 2 */
#define reg_CANIDAR3(x) (*((CAN_port)x + 0x13)) /* Identifier Acceptance Register 3 */
#define reg_CANIDMR0(x) (*((CAN_port)x + 0x14)) /* Identifier Mask Register 0 */
#define reg_CANIDMR1(x) (*((CAN_port)x + 0x15)) /* Identifier Mask Register 1 */
#define reg_CANIDMR2(x) (*((CAN_port)x + 0x16)) /* Identifier Mask Register 2 */
#define reg_CANIDMR3(x) (*((CAN_port)x + 0x17)) /* Identifier Mask Register 3 */
#define reg_CANIDAR4(x) (*((CAN_port)x + 0x18)) /* Identifier Acceptance Register 4 */
#define reg_CANIDAR5(x) (*((CAN_port)x + 0x19)) /* Identifier Acceptance Register 5 */
#define reg_CANIDAR6(x) (*((CAN_port)x + 0x1A)) /* Identifier Acceptance Register 6 */
#define reg_CANIDAR7(x) (*((CAN_port)x + 0x1B)) /* Identifier Acceptance Register 7 */
#define reg_CANIDMR4(x) (*((CAN_port)x + 0x1C)) /* Identifier Mask Register 4 */
#define reg_CANIDMR5(x) (*((CAN_port)x + 0x1D)) /* Identifier Mask Register 5 */
#define reg_CANIDMR6(x) (*((CAN_port)x + 0x1E)) /* Identifier Mask Register 6 */
#define reg_CANIDMR7(x) (*((CAN_port)x + 0x1F)) /* Identifier Mask Register 7 */
#define reg_CANRXFG(x) ( (CAN_port)x + 0x20 ) /* Foreground Receive Buffer */
#define reg_CANTXFG(x) ( (CAN_port)x + 0x30 ) /* Foreground Transmit Buffer */

 

/* init function in C file */

 

/* port will have value CAN0, CAN1, CAN2 etc upon entering the function, to allow the same code to be used for multiple CAN ports. */

 

 

 

  reg_CANCTL1(port) = CANE; /* can enable (write once), no special modes */
  
  /* Note! CANE must be set before sleep mode can be entered */
  
 
  reg_CANCTL0(port) |= SLPRQ; /* sleep mode */
  reg_CANCTL0(port) |= INITRQ; /* init mode */

 

  while((reg_CANCTL1(port) & SLPAK)==0) /* wait until CPU enters sleep mode. */
  {
  ;
  }
   
   
  reg_CANCTL1(port) |= CLKSRC; /* clksrc=bus */

  *(uint16*)&reg_CANBTR0(port) = baudrate;

  reg_CANCTL0(port) &= (uint8)~SLPRQ; /* leave sleep mode */
  reg_CANCTL0(port) &= (uint8)~INITRQ; /* leave init mode */

  if(useRxInterrupt)
  {
  reg_CANRIER(port) = RXFIE;
  }


  while ((reg_CANCTL1(port) & (SLPAK|INITAK)) > 0) /* wait until CAN is running */
  {
  ;
  }

0 Kudos
Reply
1,089 Views
kef
Specialist I

From the documentation, setting INITRQ effects:

 

"The following registers enter their hard reset state and restore their default values: CANCTL0, CANRFLG, CANRIER, CANTFLG, CANTIER, CANTARQ, CANTAAK, CANTBSEL."

 

Do you reenable interrupts after changing bitrate?

Another quote regarding recommendation to enter sleep mode before setting INITRQ:

 

 

"In order to protect from accidentally violating the CAN protocol the TXCAN pin is immediately forced to a recessive state when the Initialization Mode is requested by the CPU. Thus the recommended procedure is to bring the MSCAN into Sleep Mode (SLPRQ=1 and SLPAK=1) before."

 

As I understand it, sleep is recommended to prevent sending incomplete message. Though this can be controlled by software, "just don't send anything if you are going to init mode", but you can't control easily acknowledgement of messages sent by other nodes. Switching from dominant to recessive in the middle of ack bit is not something very nice. But I don't think you can't enter init mode without intermediate sleep mode.

0 Kudos
Reply
1,089 Views
HenryL
Contributor III

I've tried different combinations of putting into sleep & init. Same results. Yes I do re-enable interrupts.

 

 

//my init codeCAN0CTL1 |= CANE;                            //CAN0 is enabled and is using OSCCLK as CANCLKCAN0CTL1 &= ~LISTEN;                        //Taking CAN module out of Listen only modeCAN0BTR0 |= 0;                                  //Setting the prescaler correctlyCAN0BTR1 |= TSEG12 | TSEG20;   //Setting baud rate to the specified rate; default = 500KCAN0IDAC = IDAM1;                            //Setting the acceptance filters for 8, 8-bit filtersCAN0CTL0 &= ~INITRQ;        //request exit init modewhile (CAN0CTL1 & INITAK);    //wait for acknowledge

CAN0CTL0 |= TIME;                            //Enable the can free running timer and timestampCAN0RIER |= OVRIE | RXFIE;                    //Enable the RX buffer full and the buffer overrun error interrupt flags

//configure acceptance filters.
//......shortened, irrelevent to this issue.
//============================================================

//during execution when change bitrate command is issued.
CAN0TIER &= 0x00;                                        //disable interruptCAN0TARQ = 0x07;                                        //request to abort all transmit bufferswhile ((CAN0TFLG & 0x07) != 0x07);        //wait for the abort to be completed.

CAN0CTL0 |= SLPRQ;       //request sleep modewhile (!(CAN0CTL1 & SLPAK));    //wait for acknowledge
CAN0CTL0 |= INITRQ;        //request init modewhile (!(CAN0CTL1 & INITAK));    //wait for acknowledge//set bit timing registers//ex: set to 250KbpsCAN0BTR0 = 0;CAN0BTR1 = TSEG10 | TSEG13 | TSEG22;

CAN0CTL0 &= ~SLPRQ;        //request exit sleep modewhile (CAN0CTL1 & SLPAK);    //wait for acknowledge
CAN0CTL0 &= ~INITRQ;        //request exit init modewhile (CAN0CTL1 & INITAK);    //wait for acknowledge//re-init anything that were reset.CAN0CTL0 |= TIME;                            //Enable the can free running timer and timestampCAN0RIER |= OVRIE | RXFIE;                    //Enable the RX buffer full and the buffer overrun error interrupt flags

 

there are other nodes on the bus, so kef has a point in that I won't be able to control acknowldge of messages.

 

 

0 Kudos
Reply
1,089 Views
Lundin
Senior Contributor IV

Note the following section of the manual:

 

INITRQ — Initialization Mode Request
...

The following registers enter their hard reset state and restore their default values: CANCTL01,
CANRFLG2, CANRIER3, CANTFLG, CANTIER, CANTARQ, CANTAAK, CANTBSEL.

 

All interrupts and filters are cleared, you need to set up the filters again. Apart from that, I cannot find anything wrong with your code.

0 Kudos
Reply
1,090 Views
HenryL
Contributor III

problem solved. It was a problem in another part of the code that is affected by having the CAN periph stopped.


Thanks for the help.

0 Kudos
Reply
1,089 Views
Lundin
Senior Contributor IV

I recall some Freescale doc stating that you can get strange result when running init code in the middle of execution. To prevent this from happening, the MSCAN module should be put into sleep mode (SLPRQ) at the same as it is put into init mode. Perhaps this could be related to the problem.

0 Kudos
Reply