Dear,
Could you help review below code, whether it have some config problem.
Crystal: 4MHz
CAN Baud: 250Kbps
MCU: S12G128 64pin
void CAN2_NewInit(void)
{
/* Initialise the CAN */
CANCTL1_CANE = 1; /* enable CAN module */
CANCTL0 = 0x01; /* enter init mode */
while(!(CANCTL1_INITAK)); /* wait for init mode */
CANCTL1 = 0x80; /* enable CAN module, Loopback Mode, Ext OSC */
CANBTR0 = 0xC1; /* sync jump - 4 Tq clocks, prescalar = 3 */
CANBTR1 = 0x01; /* Tseg = 3, Tseg1 = 10, 1 sample per bit */
CANIDAC = 0x10; /* four 16-bit filters */
CANIDAR0 = 0x20; /* Filter 0, ID=0x100 Standard Identifier */
CANIDMR0 = 0x00;
CANIDAR1 = 0x00;
CANIDMR1 = 0x07; /* AM[2:0] = 7 to receive standard identifiers */
CANIDAR2 = 0x00; /* Filter 1, ID=0x0000 */
CANIDMR2 = 0x00;
CANIDAR3 = 0x00;
CANIDMR3 = 0x07; /* AM[2:0] = 7 to receive standard identifiers */
CANIDAR4 = 0x00; /* Filter 2, ID=0x0000 */
CANIDMR4 = 0x00;
CANIDAR5 = 0x00;
CANIDMR5 = 0x07; /* AM[2:0] = 7 to receive standard identifiers */
CANIDAR6 = 0x00; /* Filter 3, ID=0x0000 */
CANIDMR6 = 0x00;
CANIDAR7 = 0x00;
CANIDMR7 = 0x07; /* AM[2:0] = 7 to receive standard identifiers */
CANCTL0 = 0x00; /* exit init mode */
while(CANCTL1_INITAK); /* wait until module exits init mode */
while(!(CANCTL0_SYNCH)); /* wait for CAN module to synch */
CANRFLG = 0xC3; /* reset Rx flags */
}
//byte CAN2_SendFrame(byte BufferNum,dword MessageID,byte FrameType,byte Length,const byte *Data)
void CAN2_NewSendFrame(byte Length, byte *Data)
{
byte txbuffer;
byte txCounter = 0;
while(txCounter < Length)
{
while (!CANTFLG); /* Wait for empty Tx Buffer */
CANTBSEL = CANTFLG; /* Select the empty Tx Buffer */
txbuffer = CANTBSEL; /* Save the empty buffer */
CANTXIDR0 = 0x18; /* load message id value to ID regs */ //18FF0C20
CANTXIDR1 = 0xFF;
CANTXIDR2 = 0x0C;
CANTXIDR3 = 0x20;
CANTXDSR0 = *Data; /* load data to send */
CANTXDLR = 0x01; /* set data length */
CANTXTBPR = 0x80; /* set data buffer priority */
CANTFLG = txbuffer; /* start transmission */
while(!(CANTFLG & txbuffer)); /* wait for Tx to complete */
txCounter++;
}
}
//byte CAN2_ReadFrame(dword *MessageID,byte *FrameType,byte *FrameFormat,byte *Length,byte *Data)
void CAN2_NewReceiveFrame(dword *MessageID, byte Length, byte *Data)
{
byte rxCounter = 0;
while(rxCounter < Length)
{
if(CANRFLG_RXF) /* has a message been received ? */
{
*Data = CANRXDSR0; /* Display transmitted PORTB on LEDs */
CANRFLG_RXF = 1; /* Clear RXF */
}
rxCounter++;
}
}
I have used easiest method to check it so I have compared your code with the code of mine which is designed for more messages prepared on background.
1) CAN bitrate. You can check in attached excel sheet I prepared for myself "a few" days ago. It considers more inputs to calculate the CANBTR registers. (CAN_setup5.xlsx)
2) Filters:
CANCTL1 – the loopback mode is not set but mentioned
CANBTR1, CANBTR0 you can check with attached file.
If I accept both data and remote frames the standard identifier 4x16 bit filter requires:
Just to check the first one:
IDE – filter standard frame(must be 0), RTR = 0 if we consider to accept the data frames only
So, for ID 0x100:
ID 10 9 8 7 6 5 4 3 2 1 0 RTR IDE X X X
IDAR0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 = 0x20 00
IDMR 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 = 0x 00 07
Your setup is OK if you do not want to accept remote frames.
If you want to accept the only this one then all other IDAR and IDMR should be set to the same values.
3) Initialization, comparing your and my code I can say OK
void init_CAN(UBYTE _canbtr0, UBYTE _canbtr1, UBYTE loop)
{
if(loop) loop=CANCTL1_LOOPB_MASK;
CANCTL0 = CANCTL0_INITRQ_MASK;
while(!(CANCTL1 & CANCTL1_INITAK_MASK));
CANCTL1 = 0x80 | loop; // Enables MSCAN, oscillator clock, Loop Enabled/Disabled and Normal Operation
CANBTR0 = _canbtr0; //
CANBTR1 = _canbtr1; //
CANIDMR0 = CANIDMR1 = CANIDMR2 = CANIDMR3 = 0xFF; // receive everything
CANIDMR4 = CANIDMR5 = CANIDMR6 = CANIDMR7 = 0xFF;
CANCTL0 = 0x00; // restarts MSCAN peripheral
while(CANCTL1 & CANCTL1_INITAK_MASK); // wait for Initialization Mode exit
while(!(CANCTL0 & CANCTL0_SYNCH_MASK)); // waits for MSCAN synchronization with the CAN bus
CANRFLG = 0xC3; // clear flags
}
4) Sending a message – only for inspiration
//==============================================================================
void createMessage(tCAN_MSG *msg,UINT id,BOOL RTR,UBYTE len,UBYTE prty,
UBYTE d0,UBYTE d1,UBYTE d2,UBYTE d3,UBYTE d4,UBYTE d5,UBYTE d6,UBYTE d7 )
{
msg->id = id;
msg->RTR = RTR;
msg->data[0]= d0;
msg->data[1]= d1;
msg->data[2]= d2;
msg->data[3]= d3;
msg->data[4]= d4;
msg->data[5]= d5;
msg->data[6]= d6;
msg->data[7]= d7;
msg->len =len;
msg->prty=prty;
}
//==============================================================================
//typedef struct { UINT id; BOOL RTR; UBYTE data[8]; UBYTE len; UBYTE prty;}tCAN_MSG;
//==============================================================================
BOOL MSCANSendMsg(tCAN_MSG *msg)
{
UBYTE txbuffer = 0, i;
UBYTE *can_DSR = &CANTXDSR0;
if(msg->len > 8) return(0);
if(!(CANCTL0 & CANCTL0_SYNCH_MASK)) return(0);
CANTBSEL = CANTFLG; // Select lowest empty buffer
txbuffer = CANTBSEL; // Backup selected buffer
CANTXIDR0 = (UBYTE)(msg->id>>3); // insert ID MSB
CANTXIDR1 = (UBYTE)(msg->id<<5); // insert last 3 bits of ID to the msb
if(msg->RTR) CANTXIDR1 |= 0x10;
for(i = 0; i < msg->len; i++)
can_DSR[i] = msg->data[i];
CANTXDLR = msg->len; // set message data length
CANTXTBPR = msg->prty; // set message internal priority
CANTFLG = txbuffer; // clear flag to send message
return(1);
}
5) Receiving the message – the message is split into components only for example purpose
Not sure but you will still read the same data from the first data byte of the buffer. I missing increment for reading of all valid bytes.
BOOL MSCANGetMsg(tCAN_MSG *msg)
{
UBYTE i;
UBYTE *can_DSR = &CANRXDSR0;
if(!(CANRFLG & CANRFLG_RXF_MASK)) return(0); // if no new message=>return
if(CANRXIDR1 & 0x08) return(0); // if not standard identifier=>return
msg->id = ((CANRXIDR0<<3)&0x0700) | (UBYTE)(CANRXIDR0<<3) | (UBYTE)(CANRXIDR1>>5);
if(CANRXIDR1 & 0x10) msg->RTR = 1;
else msg->RTR = 0;
msg->len = CANRXDLR;
for(i = 0; i < msg->len; i++)
msg->data[i] = can_DSR[i];
CANRFLG = CANRFLG_RXF_MASK;
return(1);
}
6) I would suggest you to use loopback mode before you will start to communicate with other nodes. This is the first step to be sure I am correctly Tx and Rx.
Best regards,
Ladislav