sending CAN-message with MC9S08DZ60

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

sending CAN-message with MC9S08DZ60

5,004 Views
ohanica
Contributor III
Hello!
 
I've got some problems with the CAN-interface. The configuration is as in  the datasheet. It's a simple example. I just try to send a message via CAN - it does not work in the Full Chip Simulation in CodeWarrior.
When executing the line:
 
//start transmit data
  CANTFLG=tx_buf;  
 
The Simulator tells me: "MSCAN Error - transmit buffer #1 not initialized", to be sure I understand he tells it four times :smileyhappy:
 
So what isn't initialized? I configured all CAN and CAN-message registers...
 
Code:
/*----------------------------------------------------------ISR CAN_TX------------------------------------------------------------------------------------------------------------ */interrupt ISR_VEC_CANTX void intCANtx(void) {LED1 ^= 1;      //toggle LED1}/*----------------------------------------------------------init CAN-------------------------------------------------------------------------------------------------------------- */void initCAN(void){UINT32 Count;UINT16 idmask;    CANCTL0_INITRQ = 1; // init-mode
  CANCTL1_CANE   = 1; // activate CAN-module  CANCTL1_CLKsrc=0; // select clk source  CANCTL1_LISTEN = 0; // normal-mode  CANBTR0        = 1; // Baud Rate Prescaler = 2  CANBTR0_SJW0   = 0; // Synchronization Jump Width = 1 Tq  CANBTR0_SJW1   = 0; // (CAN0BTR0_SJWx = SJW-1)  CANBTR1        = 4; // Time Segment1 = 5 Tq clock cycle  // (CAN0BTR1=Time Segment1-1)  CANBTR1_TSEG22 = 0; // Time Segment2 = 2 Tq clock cycle  CANBTR1_TSEG21 = 0; // (CAN0BTR1_TSEG2x=Time Segment2-1)  CANBTR1_TSEG20 = 1;  CANBTR1_SAMP   = 0; // one sample per bit
  CANIDAC_IDAM1  = 0; // 4 16-Bit acceptance filter
  CANIDAC_IDAM0  = 1;    idmask = 0x0300;  CANIDAR0 = idmask>>3; // set ID-acceptance registers
  CANIDAR1 = idmask<<5; //
  CANIDMR0 = 0xFF;      // set ID-mask registers
  CANIDMR1 = 0xFF;  CANCTL0_INITRQ  = 0;  // exit init-mode    Count=200000;
   do
   {    Count--;    if (Count==0)    {      SRS = 0xff;  //reset the MCU    }   }      while(CANCTL0_SYNCH==0); // wait for CAN-bus synchronization
  CANRIER_TSTATE1 = 1; // Interrupt, wenn sich der Transmitter-Status  CANRIER_TSTATE0 = 1; // (Error-active, Error-passive, Bus-off) ändert  CANRIER_CSCIE   = 1; // Ein Statuswechsel löst einen Interrupt aus  }/*----------------------------------------------------------send a message via CAN------------------------------------------------------------------------------------------------ */void sendCAN_message(void){  UINT8 tx_buf,data[8],dlen;  UINT16 id;    //configure data of CAN-frame  id = 0x0301;  data[0]= 0x0A;  data[1]= 0x0B;  data[2]= 0x0C;  data[3]= 0x0D;  data[4]= 0x0E;  data[5]= 0x0F;  data[6]= 0xEE;  data[7]= 0xFF;  dlen = 8;    //select background buffer  CANTBSEL=CANTFLG;     tx_buf = CANTFLG;      //set ID  CANTIDR0 = id>>3;  CANTIDR1 = id<<5; //RTR = 0; IDE = 0; ==> standard frames    //set frame-data  CANTDSR0 = data[0];  CANTDSR1 = data[1];  CANTDSR2 = data[2];  CANTDSR3 = data[3];  CANTDSR4 = data[4];  CANTDSR5 = data[5];  CANTDSR6 = data[6];  CANTDSR7 = data[7];    //set data length code  CANTDLR = dlen;   //set buffer priority    CANTTBPR = 0x01;    //start transmit data  CANTFLG=tx_buf;     }

So the main problem is: when executing the last code-line in the send-function, I get the error, and the message ist not sent, because something isn't initialized correctly. 
 
I've got some other questions too:
Where can I set the baud rate for the CAN-bus?
How do I enable CAN-transmit  interrupts? I was trying to set the CANTXEIEx bits in CANTIER to 1, but in that case the CAN-ISR is executed permanently, the code in main() never reaches the sendCAN_message()-function.
 
greetx,
Johannes
 
melancolic P.S.:
When I think back to the ATMEL-CAN I feel some nostalgy. There you have 15 Message objects (compared to 3..4 message buffers in this freescale), each has its registers for ID, ID-mask, data length and its configuration registers (rx, tx, interrupts...). For the CAN config there is a big table in the datasheet where you can selct your CPU-frequency, your desired baud rate and look up your register settings for bit timing, time segments and so on... It's a bit easier to check.  I'm sorry I'm bothering you with ATMELs...
 
Labels (1)
Tags (1)
0 Kudos
7 Replies

667 Views
ohanica
Contributor III
Hello,
 
 
MSCAN is a quite strange thing to me... I still did not manage to get things working.
 
Question: does somebody out there know how I can generate an interrupt for a frame transmission complete event (on a S08DZ60 uC)? I just want to make a LED blinking if a message has been sent?
 
any code-examples for such an easy task? any links,hints,tips?
 
mg,
Johannes
0 Kudos

667 Views
Nouchi
Senior Contributor II
Hi,

Initialization give me that :
Code:
  /* ### Init_MSCAN init code */  /* CANCTL0: INITRQ=1 */  CANCTL0 |= (unsigned char)0x01;                                 while(!CANCTL1_INITAK) {             /* Wait for init acknowledge */  }  /* CANCTL1: CANE=1,CLKsrc=0,LOOPB=0,LISTEN=0,BORM=0,WUPM=0,SLPAK=0,INITAK=1 */  CANCTL1 = 0x81;                                        /* CANBTR1: SAMP=0,TSEG22=0,TSEG21=0,TSEG20=1,TSEG13=0,TSEG12=1,TSEG11=0,TSEG10=0 */  CANBTR1 = 0x14;                                        /* CANBTR0: SJW1=0,SJW0=0,BRP5=0,BRP4=0,BRP3=0,BRP2=0,BRP1=0,BRP0=1 */  CANBTR0 = 0x01;                                        /* CANIDAC: IDAM1=0,IDAM0=1,IDHIT2=0,IDHIT1=0,IDHIT0=0 */  CANIDAC = 0x10;                                        /* CANIDAR0: AC7=0,AC6=0,AC5=0,AC4=0,AC3=0,AC2=0,AC1=0,AC0=0 */  CANIDAR0 = 0x00;                                        /* CANIDAR1: AC7=0,AC6=0,AC5=0,AC4=0,AC3=0,AC2=0,AC1=0,AC0=0 */  CANIDAR1 = 0x00;                                        /* CANIDAR2: AC7=0,AC6=0,AC5=0,AC4=0,AC3=0,AC2=0,AC1=0,AC0=0 */  CANIDAR2 = 0x00;                                        /* CANIDAR3: AC7=0,AC6=0,AC5=0,AC4=0,AC3=0,AC2=0,AC1=0,AC0=0 */  CANIDAR3 = 0x00;                                        /* CANIDAR4: AC7=0,AC6=0,AC5=0,AC4=0,AC3=0,AC2=0,AC1=0,AC0=0 */  CANIDAR4 = 0x00;                                        /* CANIDAR5: AC7=0,AC6=0,AC5=0,AC4=0,AC3=0,AC2=0,AC1=0,AC0=0 */  CANIDAR5 = 0x00;                                        /* CANIDAR6: AC7=0,AC6=0,AC5=0,AC4=0,AC3=0,AC2=0,AC1=0,AC0=0 */  CANIDAR6 = 0x00;                                        /* CANIDAR7: AC7=0,AC6=0,AC5=0,AC4=0,AC3=0,AC2=0,AC1=0,AC0=0 */  CANIDAR7 = 0x00;                                        /* CANIDMR0: AM7=0,AM6=0,AM5=0,AM4=0,AM3=0,AM2=0,AM1=0,AM0=0 */  CANIDMR0 = 0x00;                                        /* CANIDMR1: AM7=0,AM6=0,AM5=0,AM4=0,AM3=0,AM2=0,AM1=0,AM0=0 */  CANIDMR1 = 0x00;                                        /* CANIDMR2: AM7=0,AM6=0,AM5=0,AM4=0,AM3=0,AM2=0,AM1=0,AM0=0 */  CANIDMR2 = 0x00;                                        /* CANIDMR3: AM7=0,AM6=0,AM5=0,AM4=0,AM3=0,AM2=0,AM1=0,AM0=0 */  CANIDMR3 = 0x00;                                        /* CANIDMR4: AM7=0,AM6=0,AM5=0,AM4=0,AM3=0,AM2=0,AM1=0,AM0=0 */  CANIDMR4 = 0x00;                                        /* CANIDMR5: AM7=0,AM6=0,AM5=0,AM4=0,AM3=0,AM2=0,AM1=0,AM0=0 */  CANIDMR5 = 0x00;                                        /* CANIDMR6: AM7=0,AM6=0,AM5=0,AM4=0,AM3=0,AM2=0,AM1=0,AM0=0 */  CANIDMR6 = 0x00;                                        /* CANIDMR7: AM7=0,AM6=0,AM5=0,AM4=0,AM3=0,AM2=0,AM1=0,AM0=0 */  CANIDMR7 = 0x00;                                        /* CANCTL0: INITRQ=0 */  CANCTL0 &= (unsigned char)~0x01;                       while(CANCTL1_INITAK) {              /* Wait for init exit */  }  /* CANCTL0: RXFRM=0,RXACT=0,CSWAI=0,SYNCH=0,TIME=0,WUPE=0,SLPRQ=0,INITRQ=0 */  CANCTL0 = 0x00;                                        /* CANRIER: WUPIE=0,CSCIE=0,RSTATE1=0,RSTATE0=0,TSTATE1=0,TSTATE0=0,OVRIE=0,RXFIE=0 */  CANRIER = 0x00;                                        /* CANTIER: TXEIE2=0,TXEIE1=0,TXEIE0=1 */  CANTIER = 0x01;                                        /* ### */  asm CLI;                             /* Enable interrupts */

This settings should give you 500kbits/sec  with a crystal clock @ 8Mhz
You have to set the CanTx vector of course
To send message, you have to set up your message buffer (seems to be right in your code),
clearing TXEx flag in CANTFLG reg, then enable Tx interrupt channel in CANTIER.
In your interrupt routine you have to disable the corresponding Tx interrupt.


Regards,
Emmanuel




0 Kudos

667 Views
ohanica
Contributor III
Hi Emmanuel,
 
thanks for your help!
 
now I've got the following code (using a 4MHz crystal installed on the eval-board, CAN-baud = 500kbit/s) which seems to be working fine in the full-chip-simulation mode:
Code:
#include <hidef.h> /* for EnableInterrupts macro */#include "derivative.h" /* include peripheral declarations *//*----------------------------------------------------------definitions ------------------------------------------------ -----------------------------------------------------------*/typedef unsigned char   UINT8;typedef signed char     SINT8;typedef unsigned int    UINT16;typedef int             SINT16;typedef unsigned long int UINT32;typedef long int        SINT32;/*----------------------------------------------------------Interrupt Vector Numbers definitions---------------------------------------------------------------------------------- */#define ISR_VEC_TPM1OVF 11#define ISR_VEC_ADC 23#define ISR_VEC_CANTX 29/*----------------------------------------------------------define LED's --------------------------------------------------------------------------------------------------------- */#define LED2 PTBD_PTBD3#define LED1 PTCD_PTCD5/*----------------------------------------------------------globals -------------------------------------------------------------------------------------------------------------- */UINT8 tx_buf;/*----------------------------------------------------------ISR CAN_TX------------------------------------------------------------------------------------------------------------ */interrupt ISR_VEC_CANTX void intCANtx(void) {LED1 ^= 1;      //toggle LED1CANTIER_TXEIE0 = 0;}/*----------------------------------------------------------init CAN-------------------------------------------------------------------------------------------------------------- */void initCAN(void){UINT32 Count;UINT16 idmask;    /* ### Init_MSCAN init code */  /* CANCTL0: INITRQ=1 */  CANCTL0 |= (unsigned char)0x01;                                 while(!CANCTL1_INITAK) {             /* Wait for init acknowledge */  }  /* CANCTL1: CANE=1,CLKsrc=0,LOOPB=0,LISTEN=0,BORM=0,WUPM=0,SLPAK=0,INITAK=1 */  CANCTL1 = 0x91;   CANCTL1_LISTEN = 0;                                       /* CANBTR1: SAMP=0,TSEG22=0,TSEG21=0,TSEG20=0,TSEG13=0,TSEG12=0,TSEG11=0,TSEG10=1 */  CANBTR1 = 0x01;                                        /* CANBTR0: SJW1=0,SJW0=0,BRP5=0,BRP4=0,BRP3=0,BRP2=0,BRP1=0,BRP0=1 */  CANBTR0 = 0x01;                                        /* CANIDAC: IDAM1=0,IDAM0=1,IDHIT2=0,IDHIT1=0,IDHIT0=0 */  CANIDAC = 0x10;    CANIDAC_IDAM0=1;                                      /* CANIDAR0: AC7=0,AC6=0,AC5=0,AC4=0,AC3=0,AC2=0,AC1=0,AC0=0 */  CANIDAR0 = 0x00;                                        /* CANIDAR1: AC7=0,AC6=0,AC5=0,AC4=0,AC3=0,AC2=0,AC1=0,AC0=0 */  CANIDAR1 = 0x00;                                        /* CANIDAR2: AC7=0,AC6=0,AC5=0,AC4=0,AC3=0,AC2=0,AC1=0,AC0=0 */  CANIDAR2 = 0x00;                                        /* CANIDAR3: AC7=0,AC6=0,AC5=0,AC4=0,AC3=0,AC2=0,AC1=0,AC0=0 */  CANIDAR3 = 0x00;                                        /* CANIDAR4: AC7=0,AC6=0,AC5=0,AC4=0,AC3=0,AC2=0,AC1=0,AC0=0 */  CANIDAR4 = 0x00;                                        /* CANIDAR5: AC7=0,AC6=0,AC5=0,AC4=0,AC3=0,AC2=0,AC1=0,AC0=0 */  CANIDAR5 = 0x00;                                        /* CANIDAR6: AC7=0,AC6=0,AC5=0,AC4=0,AC3=0,AC2=0,AC1=0,AC0=0 */  CANIDAR6 = 0x00;                                        /* CANIDAR7: AC7=0,AC6=0,AC5=0,AC4=0,AC3=0,AC2=0,AC1=0,AC0=0 */  CANIDAR7 = 0x00;                                        /* CANIDMR0: AM7=0,AM6=0,AM5=0,AM4=0,AM3=0,AM2=0,AM1=0,AM0=0 */  CANIDMR0 = 0x00;                                        /* CANIDMR1: AM7=0,AM6=0,AM5=0,AM4=0,AM3=0,AM2=0,AM1=0,AM0=0 */  CANIDMR1 = 0x00;                                        /* CANIDMR2: AM7=0,AM6=0,AM5=0,AM4=0,AM3=0,AM2=0,AM1=0,AM0=0 */  CANIDMR2 = 0x00;                                        /* CANIDMR3: AM7=0,AM6=0,AM5=0,AM4=0,AM3=0,AM2=0,AM1=0,AM0=0 */  CANIDMR3 = 0x00;                                        /* CANIDMR4: AM7=0,AM6=0,AM5=0,AM4=0,AM3=0,AM2=0,AM1=0,AM0=0 */  CANIDMR4 = 0x00;                                        /* CANIDMR5: AM7=0,AM6=0,AM5=0,AM4=0,AM3=0,AM2=0,AM1=0,AM0=0 */  CANIDMR5 = 0x00;                                        /* CANIDMR6: AM7=0,AM6=0,AM5=0,AM4=0,AM3=0,AM2=0,AM1=0,AM0=0 */  CANIDMR6 = 0x00;                                        /* CANIDMR7: AM7=0,AM6=0,AM5=0,AM4=0,AM3=0,AM2=0,AM1=0,AM0=0 */  CANIDMR7 = 0x00;                                        /* CANCTL0: INITRQ=0 */  CANCTL0 &= (unsigned char)~0x01;                       while(CANCTL1_INITAK) {              /* Wait for init exit */  }  /* CANCTL0: RXFRM=0,RXACT=0,CSWAI=0,SYNCH=0,TIME=0,WUPE=0,SLPRQ=0,INITRQ=0 */  CANCTL0 = 0x00;                                        /* CANRIER: WUPIE=0,CSCIE=0,RSTATE1=0,RSTATE0=0,TSTATE1=0,TSTATE0=0,OVRIE=0,RXFIE=0 */  CANRIER = 0x00;                                        /* CANTIER: TXEIE2=0,TXEIE1=0,TXEIE0=1 */  CANTIER = 0x01;                                        /* ### */  } //end initCAN/*----------------------------------------------------------send a messagevia CAN------------------------------------------------------------------------------------------------- */void sendCAN_message(void){  UINT8 data[8],dlen; //tx_buf;  UINT16 id;    //configure data of CAN-frame  id = 0x0301;  data[0]= 0x0A;  data[1]= 0x0B;  data[2]= 0x0C;  data[3]= 0x0D;  data[4]= 0x0E;  data[5]= 0x0F;  data[6]= 0xEE;  data[7]= 0xFF;  dlen = 8;    //select background buffer  CANTBSEL=CANTFLG;     tx_buf = CANTBSEL;      //set ID for standard frames  CANTIDR0 = id>>3;  CANTIDR1 = id<<5; //RTR = 0; IDE = 0; ==> standard frames  CANTIDR1_IDE = 0; //standard frame  CANTIDR1_SRR = 0; //SRR = RTR for standard frames  CANTIDR2;// = 0x00;  CANTIDR3;// = 0x00;    //set frame-data  CANTDSR0 = data[0];  CANTDSR1 = data[1];  CANTDSR2 = data[2];  CANTDSR3 = data[3];  CANTDSR4 = data[4];  CANTDSR5 = data[5];  CANTDSR6 = data[6];  CANTDSR7 = data[7];    //set data length code  CANTDLR = dlen;   //set buffer priority    CANTTBPR = 0x01;    //enable TX-Interrupt for this buffer  //CANTIER |= tx_buf;                  //start transmit data by clearing TXE0 bit  CANTFLG_TXE0 = 0;    //enabling transmit interrupt 
  CANTIER_TXEIE0 = 1;}/*----------------------------------------------------------main entry point ----------------------------------------------------------------------------------------------------- */void main(void) {  UINT16 i;  UINT8 aux;  // ---------------- MCU init -------------------------------------------  /* ### MC9S08DZ60_64 "Cpu" init code ... */  /*  PE initialization code after reset */  /* Common initialization of the write once registers */  /* SOPT1: COPT=0,STOPE=0,SCI2PS=0,IICPS=0 */  SOPT1 = 0x00;                                        /* SOPT2: COPCLKS=0,COPW=0,ADHTS=0,MCSEL=0 */  SOPT2 = 0x00;                                        /* SPMSC1: LVWF=0,LVWACK=0,LVWIE=0,LVDRE=1,LVDSE=1,LVDE=1,BGBE=0 */  SPMSC1 = 0x1C;                                        /* SPMSC2: LVDV=0,LVWV=0,PPDF=0,PPDACK=0,PPDC=0 */  SPMSC2 = 0x00;                                        /*  System clock initialization */  MCGTRM = *(unsigned char*far)0xFFAF; /* Initialize MCGTRM register from a non volatile memory */  MCGSC = *(unsigned char*far)0xFFAE;  /* Initialize MCGSC register from a non volatile memory */  /* MCGC2: BDIV=3,RANGE=1,HGO=0,LP=0,EREFS=0,ERCLKEN=1,EREFSTEN=0 */  MCGC2 = 0xE2;                        /* Set MCGC2 register */  /* MCGC1: CLKS=0,RDIV=0,IREFS=1,IRCLKEN=0,IREFSTEN=0 */  MCGC1 = 0x04;                        /* Set MCGC1 register */  /* MCGC3: LOLIE=0,PLLS=0,CME=0,VDIV=1 */  MCGC3 = 0x01;                        /* Set MCGC3 register */  while(!MCGSC_LOCK) {                 /* Wait until FLL is locked */  }  // ---------------- MCU init -------------------------------------------   PTBDD_PTBDD3 = 1;    // configure Ports with green led as outputs  PTCDD_PTCDD5 = 1;    LED1 = 1;            //turn off leds  LED2 = 1;  initCAN();    EnableInterrupts; /* enable interrupts */  /* include your code here */  for(;;)   {          for (i=8000; i!=0; i--)      {      //dummy action      aux = i>>4;     }                sendCAN_message();               __RESET_WATCHDOG(); /* feeds the dog */  } /* loop forever */  /* please make sure that you never leave main */}

 
Two more questions:
 
1. In debug-mode with the P&E Multilink interface, when stepping through the code, the INITAK-bit is never cleared, so the programm is hanging up in this line of the initialization function:
 
while(CANCTL1_INITAK) {              /* Wait for init exit */
 }
Is that only because of the BDM running mode? Does it clear in normal running mode?
 
 
 
2. Does the interrupt enabled in the following line occur upon transmission complete?
//enabling transmit interrupt  
  CANTIER_TXEIE0 = 1;
or does it execute as soon as the buffer0 is empty?  Are these two events necessarily the same?
 
 
Tomorrow I will test if the uC is really sending any message on the bus (using the CANalyzer). With the above code the simulation works. Let's see what the hardware is doing...
 
best,
Johannes
 
 

 
0 Kudos

667 Views
Nouchi
Senior Contributor II
Hi,

small trick:
*Create dummy project with the right target, and select "Device Initialization" at Processor Expert stage.
*Configure the CPU (clock options, etc....)
*Configure MSCAN module
*generate code
*grab the generated code onto your application.

Baud rate depends on CAN clock source, time segments length and baud rate prescaler.
In the initialization tool, you can see the baud rate selected when you adjust parameters.

If you need more message buffers, you can have look to Coldfire devices with FlexCAN module (16 messages buffers), or  MPC devices with TouCAN  module (32 messages buffers)


Emmanuel


0 Kudos

667 Views
Alban
Senior Contributor II
Hello,

There is no real need for more buffers.
Application software can always do what is needed, and I have never been shown otherwise so far.

The reason msCAN is used in smaller MCUs is because it is simpler, smaller in silicon space and very versatile.

For instance, on the S12XDP512, there is an Application Note with a FULL CAN mailboxing system based on the msCAN.
The msCAN module used on the S08DZ60 is derived from the S12XDP512.

Also, there is a mention I did not see: There is a need for a Receiver as all packets need to be acknowledged.

Alban.
0 Kudos

667 Views
ohanica
Contributor III
Hi Alban,
 
thanks to yuo too. I'll have a depp look into the AN too.
But as far as I saw at the first sight theres no C-Code example inside and the register-names are quite different. It's exactly what I said before: the principles of the MSCAN are explained, but the implementation in C-Code and the small details newcomers never know are not shown.
 
In general: it's clear that from the silicon point of view the MSCAN is more performant than with the ATMELs... If you do very good programming you can manage every CAN node with 3 buffers. But whithout a good documentation (step-by-step) it's difficult for newcomers to get started and used to prefessional uC! I'm not prefessional enough apparently :smileyhappy:  The documentation and support I can access for the S08DZ60 is not as good as the uC itself - as far as I realised up to now.
 
mg,
Johannes
0 Kudos

667 Views
Unknown
Contributor I
Hello,
 
I am working on DEMO9S08DZ60. I want to know how to set the baud rate for this controller.
One more thing is my code is not exiting from the init mode .... and not entering into normal mode.what is the reason? what change shud i do?
 
while((CANCTL1 & 0x01) != 0);  ---- infinite loop
 
plz reply ASAP.
 
Thanks & Regards
XXX. 
0 Kudos