cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F413: Use all 3 CAN interfaces simultaneously, but independently?

Dazai
Associate III

We are developing a product that needs the ability to run 3 separate CAN interfaces connected to 3 separate CAN buses.  I have the NUCLEO-F413ZH and I can successfully initialize and start CAN1, CAN2, and CAN3 and transmit from each of them in a single application, but I only get RX interrupts on CAN3 when all 3 interfaces are initialized and started.  Additionally, if I only initialize and start CAN1 or CAN3 in my application, I can transmit and receive from them, but not CAN2.

Pages 1076-1077 of the part datasheet/reference manual (RM0430) lists dual and single CAN peripheral configurations:

Dazai_0-1756413366817.png

Dazai_1-1756413396799.png

First question: is it possible to run all three CAN interfaces simultaneously and receive messages from each of them?

CAN2 doesn't have direct access to SRAM, so I think if I want to use CAN2 for receiving, I also need to enable CAN1.  Is that correct?

I don't understand what is meant by the master/slave relationship between CAN1 and CAN2.  It sounds like messages received on CAN2 need to "route" through CAN1 to get to SRAM, but I'm not sure. How should CAN1 and CAN 2 be configured so that I can receive messages on either interface?

1 ACCEPTED SOLUTION

Accepted Solutions
Karl Yamashita
Principal

When you configure the filters, you'd typically split the filters (28) in half and assign to accordingly to CAN1 and CAN2.

 

void CAN_SetFilter(CAN_MsgStruct *msg)
{
	static CAN_FilterTypeDef sFilterConfig;

	if(msg->hcan == &hcan1)
	{
		sFilterConfig.FilterBank = 0;
#if defined(CAN2)
		sFilterConfig.SlaveStartFilterBank = 14;
#endif
	}
#if defined(CAN2)
	else if(msg->hcan == &hcan2)
	{
		sFilterConfig.FilterBank = 14;
		sFilterConfig.SlaveStartFilterBank = 14;
	}
#endif
#if defined(CAN3)
	else if(msg->hcan == &hcan3)
	{
		sFilterConfig.FilterBank = 0;
	}
#endif

	sFilterConfig.FilterMode             = CAN_FILTERMODE_IDMASK;
	sFilterConfig.FilterScale            = CAN_FILTERSCALE_32BIT;
	sFilterConfig.FilterIdHigh           = 0x0000;
	sFilterConfig.FilterIdLow            = 0x0000;
	sFilterConfig.FilterMaskIdHigh       = 0x0000;
	sFilterConfig.FilterMaskIdLow        = 0x0000;
	sFilterConfig.FilterFIFOAssignment   = CAN_FILTER_FIFO0;

	if(HAL_CAN_ConfigFilter(msg->hcan, &sFilterConfig) != HAL_OK)
	{
		Error_Handler(); // Error_Handler should never be called, so we won't worry about handling these errors.
	}

	if(HAL_CAN_Start(msg->hcan) != HAL_OK)
	{
		Error_Handler();
	}

	if (HAL_CAN_ActivateNotification(msg->hcan, CAN_IT_RX_FIFO0_MSG_PENDING | CAN_IT_TX_MAILBOX_EMPTY) != HAL_OK)
	{
		Error_Handler();
	}
}

 

If a reply has proven helpful, click on Accept as Solution so that it'll show at top of the post.

View solution in original post

3 REPLIES 3
Karl Yamashita
Principal

When you configure the filters, you'd typically split the filters (28) in half and assign to accordingly to CAN1 and CAN2.

 

void CAN_SetFilter(CAN_MsgStruct *msg)
{
	static CAN_FilterTypeDef sFilterConfig;

	if(msg->hcan == &hcan1)
	{
		sFilterConfig.FilterBank = 0;
#if defined(CAN2)
		sFilterConfig.SlaveStartFilterBank = 14;
#endif
	}
#if defined(CAN2)
	else if(msg->hcan == &hcan2)
	{
		sFilterConfig.FilterBank = 14;
		sFilterConfig.SlaveStartFilterBank = 14;
	}
#endif
#if defined(CAN3)
	else if(msg->hcan == &hcan3)
	{
		sFilterConfig.FilterBank = 0;
	}
#endif

	sFilterConfig.FilterMode             = CAN_FILTERMODE_IDMASK;
	sFilterConfig.FilterScale            = CAN_FILTERSCALE_32BIT;
	sFilterConfig.FilterIdHigh           = 0x0000;
	sFilterConfig.FilterIdLow            = 0x0000;
	sFilterConfig.FilterMaskIdHigh       = 0x0000;
	sFilterConfig.FilterMaskIdLow        = 0x0000;
	sFilterConfig.FilterFIFOAssignment   = CAN_FILTER_FIFO0;

	if(HAL_CAN_ConfigFilter(msg->hcan, &sFilterConfig) != HAL_OK)
	{
		Error_Handler(); // Error_Handler should never be called, so we won't worry about handling these errors.
	}

	if(HAL_CAN_Start(msg->hcan) != HAL_OK)
	{
		Error_Handler();
	}

	if (HAL_CAN_ActivateNotification(msg->hcan, CAN_IT_RX_FIFO0_MSG_PENDING | CAN_IT_TX_MAILBOX_EMPTY) != HAL_OK)
	{
		Error_Handler();
	}
}

 

If a reply has proven helpful, click on Accept as Solution so that it'll show at top of the post.
mƎALLEm
ST Employee

Hello,

Please read this article: STM32 in dual CAN configuration: bxCAN Filter bank explanation and relation with CAN2 Start Bank parameter

You can use all the CAN instances at the same time and indepedently. But you need to enable the APB clock of CAN1 when you need to use CAN2.

CAN3 is independent from CAN1/CAN2 from architecture standpoint.

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

Thank you, I got it working after reviewing your code.  I was incorrectly setting the FilterBank to 0 for the CAN2 filter, and it should have instead been set to the SlaveStartFilterBank value for CAN1's filter (or higher).  After fixing that I can now transmit and receive from all 3 CAN interfaces within the same application.