Hi
Yes, the address is just pas the end of the CAN message buffer and I am pretty sure that what happened is that the error loop was traversed more than once, but the message pointer left after the end of the memory the fist time.
In the following I have added a pointer to the start of the message buffers and set ptrMessageBuffer back to this each time that it goes around the error loop. This should allow multiple queued errors to be handled.
Thanks for the report!
Regards
Mark
static void fnCAN_error(int iChannel)
{
unsigned char can_error_int_message[HEADER_LENGTH];
KINETIS_CAN_CONTROL *ptrCAN_control;
KINETIS_CAN_BUF *ptrMessageBuffer;
KINETIS_CAN_BUF *ptrMessageBufferStart;
volatile unsigned long ulError; // read the error status register, clearing error bits
can_error_int_message[MSG_DESTINATION_NODE] = INTERNAL_ROUTE;
can_error_int_message[MSG_SOURCE_NODE] = INTERNAL_ROUTE;
can_error_int_message[MSG_DESTINATION_TASK] = CAN_ERROR_TASK;
can_error_int_message[MSG_SOURCE_TASK] = INTERRUPT_EVENT;
switch (iChannel) {
case 0:
ptrCAN_control = (KINETIS_CAN_CONTROL *)CAN0_BASE_ADD;
ptrMessageBufferStart = MBUFF0_ADD_0;
break;
#if NUMBER_OF_CAN_INTERFACES > 1
case 1:
ptrCAN_control = (KINETIS_CAN_CONTROL *)CAN1_BASE_ADD;
ptrMessageBufferStart = MBUFF0_ADD_1;
break;
#endif
#if NUMBER_OF_CAN_INTERFACES > 2
case 2:
ptrCAN_control = (KINETIS_CAN_CONTROL *)CAN2_BASE_ADD;
ptrMessageBufferStart = MBUFF0_ADD_2;
break;
#endif
}
while (((ulError = ptrCAN_control->CAN_ESR1) & (BIT1ERROR | BIT0ERROR | CAN_CRC_ERR | CAN_ACK_ERR | CAN_FRM_ERR | CAN_STF_ERR)) != 0) { // read the error status register, clearing error bits
#if defined _WINDOWS
ptrCAN_control->CAN_ESR1 &= ~(BIT1ERROR | BIT0ERROR | CAN_CRC_ERR | CAN_ACK_ERR | CAN_FRM_ERR | CAN_STF_ERR);
#endif
ptrMessageBuffer = ptrMessageBufferStart;
if ((ulError & CAN_ACK_ERR) != 0) { // a transmission received no ack
CANQUE *ptrCanQue = can_queue[iChannel]; // we need to search for buffers which are transmitting
int i = NUMBER_CAN_MESSAGE_BUFFERS;
can_error_int_message[MSG_INTERRUPT_EVENT] = 0;
while (i-- != 0) {
if ((ptrCanQue->ucMode & CAN_TX_BUF_ACTIVE) != 0) { // this buffer is presently transmitting a message
if (++(ptrCanQue->ucErrors) >= MAX_TX_CAN_TRIES) { // we allow a few attempts before quitting (it also filters counting normal active buffers)
ptrMessageBuffer->ulCode_Len_TimeStamp = ((ptrMessageBuffer->ulCode_Len_TimeStamp & ~CAN_CODE_FIELD) | MB_TX_INACTIVE); // stop transmission
can_error_int_message[MSG_DESTINATION_TASK] = ptrCanQue->TaskToWake;
if ((ptrCanQue->ucMode & CAN_TX_BUF_REMOTE) != 0) {
can_error_int_message[MSG_INTERRUPT_EVENT] = CAN_TX_REMOTE_ERROR;
ptrCanQue->ucMode = (CAN_TX_BUF | CAN_RX_BUF_FULL | CAN_TX_BUF_REMOTE); // mark that it is an errored transmission buffer
}
else {
can_error_int_message[MSG_INTERRUPT_EVENT] = CAN_TX_ERROR;
ptrCanQue->ucMode = (CAN_TX_BUF | CAN_RX_BUF_FULL); // mark that it is an errored transmission buffer
}
break;
}
}
ptrCanQue++;
ptrMessageBuffer++;
}
}
else {
ptrMessageBuffer->ulCode_Len_TimeStamp = (MB_TX_INACTIVE | (ptrMessageBuffer->ulCode_Len_TimeStamp & CAN_KEEP_CONTENTS)); // free the buffer
can_error_int_message[MSG_INTERRUPT_EVENT] = CAN_OTHER_ERROR;
}
ptrCAN_control->CAN_ESR1 = ERRINT; // clear the error interrupt
#if defined _WINDOWS
ptrCAN_control->CAN_ESR1 &= ~(ERRINT);
#endif
if (can_error_int_message[MSG_INTERRUPT_EVENT] != 0) {
uDisable_Interrupt(); // ensure interrupts remain blocked when putting message to queue
fnWrite(INTERNAL_ROUTE, can_error_int_message, HEADER_LENGTH); // inform the handling task of event
uEnable_Interrupt();
}
}
}