Skip to main content
Ed Maynard
Associate II
July 11, 2017
Solved

STM32F413 dual CAN receive on slave CAN issue

  • July 11, 2017
  • 5 replies
  • 1576 views
Posted on July 11, 2017 at 17:16

I am using the STM32F413 and am trying to use CAN1 and CAN2 in a ring topology (CAN1 sends and if CAN2 doesn't get the message then I know I have a network connectivity failure). I use the latest CubeMX to generate the configuration code and CAN1 appears to send messages just fine and CAN2 asserts the ACK bit just fine. CAN1 in loopback mode receives its own message but CAN2 using the same filter configuration as CAN1 in loopback mode always returns HAL_TIMEOUT. When I look at the hardware registers for CAN2, the flags for the receive FIFOs show that no message has been recorded. Here's the filter configuration for CAN2:

sFilterConfig.FilterNumber = 0;

sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;

sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;

sFilterConfig.FilterIdHigh = 0x0000;

sFilterConfig.FilterIdLow = 0x0000;

sFilterConfig.FilterMaskIdHigh = 0x0000;

sFilterConfig.FilterMaskIdLow = 0x0000;

sFilterConfig.FilterFIFOAssignment = 0;

sFilterConfig.FilterActivation = ENABLE;

sFilterConfig.BankNumber = 14;

HAL_CAN_ConfigFilter(&hcan2, &sFilterConfig);

Here are the initialization code for the two CAN:

/* CAN1 init function */

void MX_CAN1_Init(void)

{

hcan1.Instance = CAN1;

hcan1.Init.Prescaler = 5;

hcan1.Init.Mode = CAN_MODE_LOOPBACK;

hcan1.Init.SJW = CAN_SJW_1TQ;

hcan1.Init.BS1 = CAN_BS1_6TQ;

hcan1.Init.BS2 = CAN_BS2_3TQ;

hcan1.Init.TTCM = DISABLE;

hcan1.Init.ABOM = DISABLE;

hcan1.Init.AWUM = DISABLE;

hcan1.Init.NART = DISABLE;

hcan1.Init.RFLM = DISABLE;

hcan1.Init.TXFP = DISABLE;

if (HAL_CAN_Init(&hcan1) != HAL_OK)

{

_Error_Handler(__FILE__, __LINE__);

}

}

/* CAN2 init function */

void MX_CAN2_Init(void)

{

hcan2.Instance = CAN2;

hcan2.Init.Prescaler = 5;

hcan2.Init.Mode = CAN_MODE_NORMAL;

hcan2.Init.SJW = CAN_SJW_1TQ;

hcan2.Init.BS1 = CAN_BS1_6TQ;

hcan2.Init.BS2 = CAN_BS2_3TQ;

hcan2.Init.TTCM = DISABLE;

hcan2.Init.ABOM = DISABLE;

hcan2.Init.AWUM = DISABLE;

hcan2.Init.NART = DISABLE;

hcan2.Init.RFLM = DISABLE;

hcan2.Init.TXFP = DISABLE;

if (HAL_CAN_Init(&hcan2) != HAL_OK)

{

_Error_Handler(__FILE__, __LINE__);

}

}

void HAL_CAN_MspInit(CAN_HandleTypeDef* canHandle)

{

GPIO_InitTypeDef GPIO_InitStruct;

if(canHandle->Instance==CAN1)

{

/* USER CODE BEGIN CAN1_MspInit 0 */

/* USER CODE END CAN1_MspInit 0 */

/* Peripheral clock enable */

__HAL_RCC_CAN1_CLK_ENABLE();

/**CAN1 GPIO Configuration

PG0 ------> CAN1_RX

PG1 ------> CAN1_TX

*/

GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;

GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

GPIO_InitStruct.Pull = GPIO_NOPULL;

GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

GPIO_InitStruct.Alternate = GPIO_AF9_CAN1;

HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);

/* USER CODE BEGIN CAN1_MspInit 1 */

HAL_GPIO_WritePin(GPIOE, GPIO_PIN_0, GPIO_PIN_RESET); // Set CAN1 transceiver to high speed

HAL_GPIO_WritePin(GPIOE, GPIO_PIN_2, GPIO_PIN_SET); // This puts CAN2 transceiver in 'silent' mode

/* USER CODE END CAN1_MspInit 1 */

}

else if(canHandle->Instance==CAN2)

{

/* USER CODE BEGIN CAN2_MspInit 0 */

/* USER CODE END CAN2_MspInit 0 */

/* Peripheral clock enable */

__HAL_RCC_CAN2_CLK_ENABLE();

/**CAN2 GPIO Configuration

PB12 ------> CAN2_RX

PB13 ------> CAN2_TX

*/

GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13;

GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

GPIO_InitStruct.Pull = GPIO_NOPULL;

GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

GPIO_InitStruct.Alternate = GPIO_AF9_CAN2;

HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

/* USER CODE BEGIN CAN2_MspInit 1 */

HAL_GPIO_WritePin(GPIOE, GPIO_PIN_2, GPIO_PIN_RESET);

/* USER CODE END CAN2_MspInit 1 */

}

}

sorry for the paragraph spacing - can't seem to change it.

I am basically cribbing the F4xG EVAL CAN Networking example.

I figure that this has something to do with the shared hardware resourcing of CAN1/CAN2 but I cannot find a relevant example in the ST examples. Any pointers would be greatly appreciated. I realize that this is probably a simple oversight /misunderstanding on my part but I have tried a number of things and the messages just aren't getting in. Even though the SRAM is shared, there is nothing to indicate that the bxCAN cannot send on CAN1 and simultaneously receive on CAN2.

** Update **

Running Loopback mode on CAN2 has the CAN frame coming out just fine, the ACK asserted by CAN1, but NO message received on CAN2. This worked flawless on CAN1. Now I firmly suspect that I have configured something wrong for CAN2 to be able to receive.

#bxcan #stm32f413
This topic has been closed for replies.
Best answer by valentin
Posted on July 11, 2017 at 23:15

sFilterConfig.FilterNumber = 0;

sFilterConfig.BankNumber = 14;

sFilterConfig.BankNumber defines from which filter bank number onwards the filters are perceived as acting for CAN2 instead of CAN1.

So in this case you should have it like this:

sFilterConfig.FilterNumber = 14;

sFilterConfig.BankNumber = 14;

It's somewhere in the reference manual about the registers.

Note: I haven't used CAN2 yet either BUT I will very soon and test this. Might come back to you about that.

5 replies

Ed Maynard
Associate II
July 11, 2017
Posted on July 11, 2017 at 18:21

** Solved **

I am now able to transmit on CAN1 and receive on CAN2.

The problem was the filter bank number. The examples use 14 which does not appear to be a valid number for CAN2. When the bank is changed to 0, CAN2 receives messages just fine. I am not certain why this matters and the concept of filter banks is obtuse at best in the reference manual. 

valentin
Associate III
July 11, 2017
Posted on July 11, 2017 at 23:31

sFilterConfig.BankNumber = 0; is a solution but as a consequence you will not be able to define any CAN1 filters anymore.

There is an upper limit depending on chip type and you can find it in the datasheet somewhere.

So I would first define my CAN1 filters 0 ... n and then set

sFilterConfig.BankNumber = n+1;

and continue defining CAN2 filters starting from n+1.

Ed Maynard
Associate II
July 12, 2017
Posted on July 12, 2017 at 15:50

This is confirmed to work. I've re-read the Reference Guide on bxCAN and it isn't clear about the relationship between filternumber and banknumber. (Figures 372-374 only deal with a single CAN or multiplt FIFO, Figure 365 shows CAN1 and CAN2 having the same filter numbers and no mention of banks). Maybe it is just that the naming for the HAL is obtuse - perhaps CAN2FirstFilterNumber? Anyway, the current seems to allow me to transmit on CAN1 and receive on CAN2 so 'cheers!' Valentin. Since it is impossible for me to leave anything alone, I poked around a little more and I believe that there is something fishy going on with the ST HAL software. when I look at the CAN2 handle structure, the sFilterRegister structure array is uninitialized. However, the CAN1 structure sFilterRegister has the appropriate entry at filter 14 (curiously, previous filter 0 settings seems to persist across resets as well). So I get that CAN1 and CAN2 share SRAM in which case shouldn't CAN2's sFilterRegister perhaps point to NULL or at least be a copy of CAN1? Also, to save memory, maybe only one copy and add a field indicating which CAN hardware the sFilterRegister entry points to?

valentin
valentinBest answer
Associate III
July 11, 2017
Posted on July 11, 2017 at 23:15

sFilterConfig.FilterNumber = 0;

sFilterConfig.BankNumber = 14;

sFilterConfig.BankNumber defines from which filter bank number onwards the filters are perceived as acting for CAN2 instead of CAN1.

So in this case you should have it like this:

sFilterConfig.FilterNumber = 14;

sFilterConfig.BankNumber = 14;

It's somewhere in the reference manual about the registers.

Note: I haven't used CAN2 yet either BUT I will very soon and test this. Might come back to you about that.