2018-05-24 06:52 AM
Hi All,
I am currently developing an application using CAN1 with CMSIS driver on a STM32F413 controller. As the reception of CAN messages is not so time critical like other parts in the application, I wanted to poll manually for new messages by calling MessageRead(). The Callback functions are NULL.
Now, after the third reception of my message, the CAN controller does not stop 'receiving' the message until I entirely power off my hardware and restart.
When I register an ObjectEvent callback and do a MessageRead() in there, everything works as expected, but I wanted to avoid having interrupts in my program flow. I get, that obviously it has to do with the RFOM register, but don't see, what is the difference between trying to read a message cyclic or read it after I have been informed about a new reception.
In the CMSIS documentation there is written the callbacks may be NULL. But is it intended at all to receive messages when no callbacks are registered? Or am I 'forced' to use the callbacks when I don't want to dismiss incoming messages?
Many thanks in advance,
Timo
2018-05-24 05:26 PM
I guess you are over running the buffers and going into an error state.
I made a table of 64 entries to catch all the frames.
char canRxString[1024];
uint16_t canRxMsgID [64];// to catch any size
uint8_t canRxMsgLength [64];
uint32_t canRxMsgBottomWord [64];
uint32_t canRxMsgTopWord[64];
char canRxHaveSegmentID [64];
char canTxString[1024];
uint16_t canTxMsgID[64];
uint8_t canTxMsgLength[64];
uint32_t canTxMsgBottomWord [64];
uint32_t canTxMsgTopWord[64];
in the HAL CAN CALLBACK;
I use this code to steal the frame before HAL can see it, thereby leaving HAL enabled.
/**
* @brief This function handles CAN1 RX0 interrupts.
*/
void CAN1_RX0_IRQHandler(void)
{
/* USER CODE BEGIN CAN1_RX0_IRQn 0 */
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 */
}
/**
* @brief This function handles CAN1 RX1 interrupt.
*/
void CAN1_RX1_IRQHandler(void)
{
/* USER CODE BEGIN CAN1_RX1_IRQn 0 */
checkCanRxFifos();
/* USER CODE END CAN1_RX1_IRQn 0 */
HAL_CAN_IRQHandler(&hcan1);
/* USER CODE BEGIN CAN1_RX1_IRQn 1 */
/* USER CODE END CAN1_RX1_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; // load all eight bytes in 2 cycles
canRxMsgTopWord [canRxMsgIN] = CAN1->sFIFOMailBox[1].RDHR;
canRxMsgID[canRxMsgIN] = CAN1->sFIFOMailBox[1].RIR >> 21;
CAN1->RF1R |= CAN_RF1R_RFOM1; // release FIFO
canRxMsgLength[canRxMsgIN] = readCanBytecount;
++canRxMsgIN &= 0x3F; // 64 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) {
{
readCanBytecount = (CAN1->sFIFOMailBox[0].RDTR & 0x0f);
canRxMsgBottomWord[canRxMsgIN] = CAN1->sFIFOMailBox[0].RDLR;
canRxMsgTopWord[canRxMsgIN] = 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;
++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);
}
�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?
2018-05-27 11:37 PM
Hi and many thanks for the detailed answer.
I will take a closer look on it asap and see where it brings me. Nevertheless, it is still utilizing interrupts which I wanted to avoid. I thought, there maybe would be a way to poll the messages manually on a regular time base. But maybe the drivers simply aren't intended to be used this way.
2018-05-28 04:14 AM
Yes, this code under interrupt, fills a Can-frame-buffer[64], that's 64 frames before you must service the buffer, to be sure that you never miss a frame.
In a different process, you can poll the buffer full/empty/length, at any time.