Hi Tom,
Thank you for your help.
You are right, my problem comes from the following line:
CanSerFlag &= ~FULL_RX_BUF;
I post here the solution and the whole story, maybe it will save some time for a guy like me who spent days to figure out what was going on!
It is not a mistake, as CanSerFlag is not a #define for the register CANRFLG.
This is a flag that is defined outside of the function like this:
static volatile byte CanSerFlag;
In order to receive data from the can-bus, I understand it is mandatory to have the RX Full interrupt enabled, by setting the corresponding flag in CANRIER register:
CANRIER = 0x01;
This is set after the can module has been enabled.
CanSerFlag is used in the ISR code (that runs every time when front RX buffer is full):
ISR(CAN1_InterruptRx)
{
if (CanSerFlag & FULL_RX_BUF) { /* Is any char already present in the receive buffer? */
CanSerFlag |= CAN_STATUS_OVERRUN_MASK; /* If yes then set internal flag OVERRUN */
}
CanSerFlag |= FULL_RX_BUF; /* Set flag "full RX buffer" */
ErrFlag |= (CanSerFlag & 0x83); /* Add new error flags into the ErrorFlag status variable */
if (CAN1_EnEvent) /* Are events enabled? */
CAN1_OnFullRxBuffer(); /* If yes then invoke user event */
//CANRFLG = CANRFLG_RXF_MASK; /* Reset the reception complete flag and release the RX buffer */
}
In my implementation CAN1_OnFullRxBuffer() was empty, as I do not want to read all the data from the can and not have so many events generated, I only want to have the flag set and at certain point in the main cycle to check for any new can packet (CANRFLG_RXF flag set).
But doing this at the and of the ISR code:
CANRFLG = CANRFLG_RXF_MASK;
was clearing the flag in the register, but not the variable CanSerFlag that I was checking in CAN1_ReadFrame function.
So the solution was to comment the above mentioned line in the ISR and add it in CAN1_ReadFrame just before return.
I have also updated the code in order to handle the situation of receiving a non data frame and also cleaned it up a little:
byte CAN1_ReadFrame(dword *MessageID,byte *FrameType,byte *FrameFormat,byte *Length,byte *Data)
{
byte i,j;
dword tmpId = 0;
if (!EnUser) { /* Is the device disabled by user? */
return ERR_DISABLED; /* If yes then error */
}
if (!(CanSerFlag & FULL_RX_BUF)) { /* Is the receive buffer empty? */
return ERR_RXEMPTY; /* If yes then error */
}
((DwordSwap*)&tmpId)->b.b0 = CANRIDR0;
((DwordSwap*)&tmpId)->b.b1 = CANRIDR1;
((DwordSwap*)&tmpId)->b.b2 = CANRIDR2;
((DwordSwap*)&tmpId)->b.b3 = CANRIDR3;
if (tmpId & MB_ID_IDE) {
*MessageID = ((tmpId >> 1) & 0x3FFFFUL) | ((tmpId >> 3) & 0x1FFC0000UL) | CAN_EXTENDED_FRAME_ID; /* Extended frame */
}
else {
*MessageID = tmpId >> 21; /* Standard frame */
}
if (*MessageID & CAN_EXTENDED_FRAME_ID) {
*FrameFormat = EXTENDED_FORMAT;
*FrameType = (byte)((CANRIDR3 & 0x01)? (byte)REMOTE_FRAME : (byte)DATA_FRAME); /* Result the frame type */
*MessageID &= ~CAN_EXTENDED_FRAME_ID; /* Remove EXTENDED_FRAME indicator, frame type will be returned in FrameType parameter */
}
else {
*FrameFormat = STANDARD_FORMAT;
*FrameType = (byte)((CANRIDR1 & 0x10)? (byte)REMOTE_FRAME : (byte)DATA_FRAME); /* Result the frame type */
}
*Length = (byte)(CANRDLR & 0x0F); /* Result length of the message */
if (*FrameType == DATA_FRAME) { /* Is it "data frame"? */
for (i=0; i<*Length; i++)
Data[i] = *((byte *)&CANRDSR0 + i); /* Return received data */
CanSerFlag &= ~FULL_RX_BUF; /* Clear flag "full RX buffer" */
CANRFLG = CANRFLG_RXF_MASK;
return ERR_OK;
}
CanSerFlag &= ~FULL_RX_BUF; /* Clear flag "full RX buffer" */
CANRFLG = CANRFLG_RXF_MASK;
return ERR_VALUE; // If we are here we have got no data frame.
}
Now I read correct values, no more junk, as the full rx flag is cleared in CAN1_ReadFrame only and not any more by the ISR!
Thanks Tom for pinpointing the problem that helped me solving this annoying issue.