cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F413 dual CAN receive on slave CAN issue

Ed Maynard
Associate II
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
1 ACCEPTED SOLUTION

Accepted Solutions
valentin
Senior
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.

View solution in original post

5 REPLIES 5
Ed Maynard
Associate II
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
Senior
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.

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.

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?

Posted on July 12, 2017 at 21:51

For single CAN1-only use, I have actually built myself a library that handles all the filter settings by providing a simple interface as following:

HAL_StatusTypeDef can_whitelist_add_single(CAN_HandleTypeDef* canhandle, unsigned long can_id, can_lib_filter_idtype ide_bit, uint8_t assign_fifo);
HAL_StatusTypeDef can_whitelist_add_range(CAN_HandleTypeDef* canhandle, unsigned long can_id_low, unsigned long can_mask, can_lib_filter_idtype ide_bit, uint8_t assign_fifo);
HAL_StatusTypeDef can_whitelist_remove_single(CAN_HandleTypeDef* canhandle, uint32_t can_id, can_lib_filter_idtype ide_bit, uint8_t assign_fifo);
HAL_StatusTypeDef can_whitelist_remove_range(CAN_HandleTypeDef* canhandle, uint32_t can_id_low, uint32_t can_id_high, can_lib_filter_idtype ide_bit, uint8_t assign_fifo);
uint32_t can_calc_range_mask(uint32_t id_min, uint32_t id_max);
uint32_t can_calc_range_ID(uint32_t id_min, uint32_t id_max);�?�?�?�?�?�?�?�?�?�?�?�?

As the copyright is with my company though, I'm not sure whether I may release it. I'll ask around and if so, upload it to github.

That library makes setting can filters really easy for me.

I will have to extend it for CAN1 and CAN2 dual-use as my current project uses both anyway. After that, I might release it.