2017-09-13 06:31 AM
Hi Community,
i have a question regarding to the nested interrupt function of the F105.
My Situation:
So, what happens if the CAN bus callback is stopped because a interrupt with a higher priority is active and while this a new message arrives via the CAN Hardware ?
Is the controller clever enough that, when the controller jumps back into the CAN callback (number 1) it works with the first can message ?
And then a CAN callback (number 2) is called and the second message is on the gun ?
Or is this a bad situation ? Would be great if one of the interrupt specialist could give a hint about this situation...
Thanks in advance,
Mathias
Solved! Go to Solution.
2017-09-13 11:43 AM
Well, the hardware is going to behave the same regardless of your callback, if you don't services things sufficiently quickly data will overrun. You should review thoroughly the CAN peripheral documentation, and consider the arrival of packets at wire speeds.
The callback is not going to reenter, and it is probably highly undesirable to let that occur from both a serialization and race perspective.
After each IRQ Handler completes the NVIC makes a new choice about if to call again or not, based on priority. Preemption will cause a new interrupt context to open, but it's not going to be for those at the same level. So don't expect another CAN FIFO interrupt to punch through. If your callback meanders or blocks this will become a problem.
As the processor has far more resources than the CAN peripheral, it is important to remove content from the peripheral as promptly as possible, and then process it at a level which can be interrupted. So unless you can parse the data significantly more quickly than it can potentially arrive then you'd best not do that parsing/processing within callback/interrupt context.
2017-09-13 07:49 AM
The CAN hardware has FIFOs of limited depth, three as I recall. The callbacks run under interrupt context, you should do the minimum to service these and leave immediately. You should queue data to be processed/parsed by a worker task. The worker task could be triggered by an unused interrupt of a lower priority/preemption level so as to be called as the IRQ stack unwinds and tail-chains, and be interruptible.
Don't confuse priority with preemption, the NVIC is not going to interrupt an interrupt.
2017-09-13 10:02 AM
@Clive One, thank you for your fast reply.
So if i understand you correctly, then the uC is jumping back into the CAN-Callback and then working still with the first message (FIFO).
When the first CAN-callback has finished, the second CAN-callback is called and the second message is working ?
But this only works for a maximum buffer of three messages (because of the hardware buffer of the CAN module).
I agree with you to source out the parsing into a worker task, but for me it was not clear if the FIFO pricipe is still working in the described constellation.
2017-09-13 11:43 AM
Well, the hardware is going to behave the same regardless of your callback, if you don't services things sufficiently quickly data will overrun. You should review thoroughly the CAN peripheral documentation, and consider the arrival of packets at wire speeds.
The callback is not going to reenter, and it is probably highly undesirable to let that occur from both a serialization and race perspective.
After each IRQ Handler completes the NVIC makes a new choice about if to call again or not, based on priority. Preemption will cause a new interrupt context to open, but it's not going to be for those at the same level. So don't expect another CAN FIFO interrupt to punch through. If your callback meanders or blocks this will become a problem.
As the processor has far more resources than the CAN peripheral, it is important to remove content from the peripheral as promptly as possible, and then process it at a level which can be interrupted. So unless you can parse the data significantly more quickly than it can potentially arrive then you'd best not do that parsing/processing within callback/interrupt context.
2017-09-13 06:45 PM
Using Cube as the starting point;
This is how I get the data from the hardware before it is processed by HAL.
This way, HAL is happy, and I don't have to re-initialize the interrupts.
I have a message table where the data s stored DURING the interrupt. available after the interrupt.
It is usually under 10uSec for the interrupt to complete this process,
helped in part by using two 32bit transfers for all 8 bytes of the payload.
in stm32f7xx_it.c
/**
* @brief This function handles CAN1 RX0 interrupts.
*/
void CAN1_RX0_IRQHandler(void)
{
/* USER CODE BEGIN CAN1_RX0_IRQn 0 */
//CAN_Rx0_IRQFlag = true;
//CAN_IRQFlag = true;
checkCanRxFifos();
/* USER CODE END CAN1_RX0_IRQn 0 */
HAL_CAN_IRQHandler(&hcan1);
/* USER CODE BEGIN CAN1_RX0_IRQn 1 */
/* USER CODE END CAN1_RX0_IRQn 1 */
}
void checkCanRxFifos(void) {
int readCanBytecount;
char canFifo1FullFlag = CAN1->RF1R & CAN_RF1R_FMP1;
if (canFifo1FullFlag) {
{
readCanBytecount = (CAN1->sFIFOMailBox[1].RDTR & 0x0f);
canRxMsgBottomWord[canRxMsgIN]= CAN1->sFIFOMailBox[1].RDLR;
canRxMsgTopWord[canRxMsgIN]= CAN1->sFIFOMailBox[1].RDHR;
canRxMsgID[canRxMsgIN] = CAN1->sFIFOMailBox[1].RIR >> 21;
CAN1->RF1R |= CAN_RF1R_RFOM1; // release FIFO
canRxMsgLength[canRxMsgIN] =readCanBytecount;// was 0x10+ to signify FIFO1
++canRxMsgIN &= 0x3F;// 16 entries only
canRxMsgTableEMPTY = false;
if (canRxMsgIN == canRxMsgOUT) canRxMsgTableFULL = true;
}
CAN1->IER |= CAN_IER_FMPIE1; // (11)Set FIFO1 message pending IT enable
}
char canFifo0FullFlag = CAN1->RF0R & CAN_RF0R_FMP0;
if (canFifo0FullFlag) {
//while ( canFifo0FullFlag !=0)
//while((CAN1->RF0R & CAN_RF0R_FMP0)!=0)
{
readCanBytecount = (CAN1->sFIFOMailBox[0].RDTR & 0x0f);
canRxMsgBottomWord[canRxMsgIN]= CAN1->sFIFOMailBox[0].RDLR;
canRxMsgTopWord[canRxMsgIN]= CAN1->sFIFOMailBox[0].RDHR;
//bkcanFifoBuf.d32[0] = CAN1->sFIFOMailBox[0].RDLR;
//bkcanFifoBuf.d32[1] = CAN1->sFIFOMailBox[0].RDHR;
uint32_t canRxmsgID = CAN1->sFIFOMailBox[0].RIR >> 21;
CAN1->RF0R |= CAN_RF0R_RFOM0; // release FIFO
if (canRxMsgTableFULL) {
canRxMsgTableOverflow = true; // now dump new frame...
}
else {
canRxMsgID[canRxMsgIN] = canRxmsgID;
canRxMsgLength[canRxMsgIN] = readCanBytecount;// to signify FIFO0
//canRxMsgBottomWord[canRxMsgIN] = bkcanFifoBuf.d32[0];
//canRxMsgTopWord [canRxMsgIN] = bkcanFifoBuf.d32[1];
++canRxMsgIN &= 0x3F;// 16 entries only
canRxMsgTableEMPTY = false;
if (canRxMsgIN == canRxMsgOUT)
canRxMsgTableFULL = true;
}
//length = sprintf(string + length,'%08X, %08X :W',canFifoBuf.d32[0],canFifoBuf.d32[1]);
//for( int i = 0; i < readCanBytecount; i++){
//
//canRxBuffer[canRxpointerIN++] = canFifoBuf.d8[i];
//canRxpointerIN &= 0xFF;
//if (canRxpointerIN == canRxpointerOUT )CanRxbufferOverrun = true;
////length += sprintf(string + length,'%02X, ',canFifoBuf.d8[i]);
//}
//sprintf(string + length -2,'
');// remove 2 bytes, the last comma and space
//canFifo0FullFlag = CAN1->RF0R & CAN_RF0R_FMP0;
}
CAN1->IER |= CAN_IER_FMPIE0; // (11)Set FIFO1 message pending IT enable
}
//if (length >0) puts(string);
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?
2017-09-14 02:38 AM
I fully aggree with you. Thank you for your input !
Best regards,
Mathias