Skip to main content
RNews.1
Associate
Mar 29, 2020 4:39 PM UTC
Question

Unable to receive CAN messages between two STM32FI-Discovery Boards

I'm trying to communicate over CAN using the HAL_CAN library between two STM32F boards. Specifically the issue seems to be in receiving messages. Following the documentation:

==============================================================================
 ##### How to use this driver #####
[..]
 
 (#) Initialize the CAN low level resources by implementing the HAL_CAN_MspInit():
 (++) Enable the CAN interface clock using __HAL_RCC_CANx_CLK_ENABLE()
 (++) Configure CAN pins
 (+++) Enable the clock for the CAN GPIOs
 (+++) Configure CAN pins as alternate function open-drain
 (++) In case of using interrupts (e.g. HAL_CAN_ActivateNotification())
 (+++) Configure the CAN interrupt priority using
 HAL_NVIC_SetPriority()
 (+++) Enable the CAN IRQ handler using HAL_NVIC_EnableIRQ()
 (+++) In CAN IRQ handler, call HAL_CAN_IRQHandler()
 (#) Initialize the CAN peripheral using HAL_CAN_Init() function. This
 function resorts to HAL_CAN_MspInit() for low-level initialization.
 (#) Configure the reception filters using the following configuration
 functions:
 (++) HAL_CAN_ConfigFilter()
 (#) Start the CAN module using HAL_CAN_Start() function. At this level
 the node is active on the bus: it receive messages, and can send
 messages.
 (#) To manage messages transmission, the following Tx control functions
 can be used:
 (++) HAL_CAN_AddTxMessage() to request transmission of a new
 message.
 (++) HAL_CAN_AbortTxRequest() to abort transmission of a pending
 message.
 (++) HAL_CAN_GetTxMailboxesFreeLevel() to get the number of free Tx
 mailboxes.
 (++) HAL_CAN_IsTxMessagePending() to check if a message is pending
 in a Tx mailbox.
 (++) HAL_CAN_GetTxTimestamp() to get the timestamp of Tx message
 sent, if time triggered communication mode is enabled.
 (#) When a message is received into the CAN Rx FIFOs, it can be retrieved
 using the HAL_CAN_GetRxMessage() function. The function
 HAL_CAN_GetRxFifoFillLevel() allows to know how many Rx message are
 stored in the Rx Fifo.
 (#) Calling the HAL_CAN_Stop() function stops the CAN module.
 (#) The deinitialization is achieved with HAL_CAN_DeInit() function.
 
 *** Polling mode operation ***
 ==============================
[..]
 (#) Reception:
 (++) Monitor reception of message using HAL_CAN_GetRxFifoFillLevel()
 until at least one message is received.
 (++) Then get the message using HAL_CAN_GetRxMessage().
 (#) Transmission:
 (++) Monitor the Tx mailboxes availability until at least one Tx
 mailbox is free, using HAL_CAN_GetTxMailboxesFreeLevel().
 (++) Then request transmission of a message using
 HAL_CAN_AddTxMessage().
 *** Interrupt mode operation ***
 ================================
[..]
 
 (#) Notifications are activated using HAL_CAN_ActivateNotification()
 function. Then, the process can be controlled through the
 available user callbacks: HAL_CAN_xxxCallback(), using same APIs
 HAL_CAN_GetRxMessage() and HAL_CAN_AddTxMessage().
 (#) Notifications can be deactivated using
 HAL_CAN_DeactivateNotification() function.
 (#) Special care should be taken for CAN_IT_RX_FIFO0_MSG_PENDING and
 CAN_IT_RX_FIFO1_MSG_PENDING notifications. These notifications trig
 the callbacks HAL_CAN_RxFIFO0MsgPendingCallback() and
 HAL_CAN_RxFIFO1MsgPendingCallback(). User has two possible options
 here.
 (++) Directly get the Rx message in the callback, using
 HAL_CAN_GetRxMessage().
 (++) Or deactivate the notification in the callback without
 getting the Rx message. The Rx message can then be got later
 using HAL_CAN_GetRxMessage(). Once the Rx message have been
 read, the notification can be activated again.

  1. I'm calling HAL_CAN_Init, which in turns calls HAL_CAN_MspInit setting the clock, enabling the gpios and configuring the can pins as alternate function open drain. As I'm using interrupts it also sets the receive interrupt as:
 HAL_NVIC_SetPriority(CAN1_RX0_IRQn, 0, 0);
 HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn);

2. Reception filters are being set as follows using HAL_CAN_ConfigFilter(), and no error is returned:

sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
 sFilterConfig.FilterIdHigh = 0;
 sFilterConfig.FilterIdLow = 0;
 sFilterConfig.FilterMaskIdHigh = 0;
 sFilterConfig.FilterMaskIdLow = 0;
 sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
 sFilterConfig.FilterActivation = ENABLE;
 sFilterConfig.FilterBank = 0;
 sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
 sFilterConfig.SlaveStartFilterBank = 14;
 HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig)

3. HAL_CAN_Start is called and no error is returned:

HAL_CAN_Start(&hcan1)

4. Using an interrupt triggered by pressing the blue pushbutton a message is sent:

void EXTI0_IRQHandler(void)
{
 /* USER CODE BEGIN EXTI0_IRQn 0 */
for(int n=0;n<1000000;n++);
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET) {
 a++;
 if(HAL_CAN_GetTxMailboxesFreeLevel(&hcan1)){
 if(HAL_CAN_AddTxMessage(&hcan1, &pHeader, &a, &TxMailbox)==HAL_OK){
 if(HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_6) == GPIO_PIN_SET){
 HAL_GPIO_WritePin(GPIOG, GPIO_PIN_6, GPIO_PIN_RESET);
 } else{
 HAL_GPIO_WritePin(GPIOG, GPIO_PIN_6, GPIO_PIN_SET);
 }
 }
 }
}

5. I've verified the message is pending as the following returns a positive value:

HAL_CAN_IsTxMessagePending(&hcan1, TxMailbox)

6. However the following interrupt that should be triggered when a messaged is available to be received is never triggered:

void CAN1_RX0_IRQHandler(void)
{
 /* USER CODE BEGIN CAN1_RX0_IRQn 0 */
 /* USER CODE END CAN1_RX0_IRQn 0 */
 HAL_CAN_IRQHandler(&hcan1);
 /* USER CODE BEGIN CAN1_RX0_IRQn 1 */
 HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &pRxHeader, &r);
 HAL_GPIO_WritePin(GPIOK, GPIO_PIN_3, GPIO_PIN_RESET);
 /* USER CODE END CAN1_RX0_IRQn 1 */
}

Other notes:

- Have verified the transceivers being used are both receiving 3.3V

Any help would be greatly appreciated, Rus

This topic has been closed for replies.

3 replies

Tesla DeLorean
Guru
Mar 29, 2020 7:38 PM UTC

Probably wouldn't be doing a whole lot of block operations in an interrupt/callback that might exclude other things in the system from running.

Check NVIC group settings and preempt priority levels.

Won't the HAL_CAN_IRQHandler() run callbacks, clear interrupt, etc?

Might want to look at the HAL EVAL board CAN examples rather than CubeMX output.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
RNews.1
RNews.1Author
Associate
Mar 29, 2020 7:54 PM UTC

Hi Clive1,

Thanks for the response. Looking at the HAL Eval Board CAN examples:

https://github.com/STMicroelectronics/STM32CubeF4/tree/master/Projects/STM324xG_EVAL/Examples/CAN/CAN_Networking

https://github.com/STMicroelectronics/STM32CubeF4/tree/master/Projects/STM324x9I_EVAL/Examples/CAN/CAN_Networking

They initiate their `HAL_CAN_AddTxMessage` within their main loop, is that what you're suggesting when you say not to "do whole lot of block operations in an interrupt/callback that might exclude other things in the system from running" ?

In regards to your second point "Won't the HAL_CAN_IRQHandler() run callbacks, clear interrupt, etc?". The documentation states:

 (#) Special care should be taken for CAN_IT_RX_FIFO0_MSG_PENDING and
 CAN_IT_RX_FIFO1_MSG_PENDING notifications. These notifications trig
 the callbacks HAL_CAN_RxFIFO0MsgPendingCallback() and
 HAL_CAN_RxFIFO1MsgPendingCallback(). User has two possible options
 here.
 (++) Directly get the Rx message in the callback, using
 HAL_CAN_GetRxMessage().
 (++) Or deactivate the notification in the callback without
 getting the Rx message. The Rx message can then be got later
 using HAL_CAN_GetRxMessage(). Once the Rx message have been
 read, the notification can be activated again.

Again looking at the HAL EVAL Board CAN examples within stm32f4xx_it.c, they have the following interrupt:

/******************************************************************************/
/* STM32F4xx Peripherals Interrupt Handlers */
/* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */
/* available peripheral interrupt handler's name please refer to the startup */
/* file (startup_stm32f4xx.s). */
/******************************************************************************/
 
/**
* @brief This function handles CAN1 RX0 interrupt request.
* @param None
* @retval None
*/
void CANx_RX_IRQHandler(void)
{
 HAL_CAN_IRQHandler(&CanHandle);
}

While as the function description states looking at startup_stm32f4xx.s yields the following options for possible interrupts:

 DCD CAN1_TX_IRQHandler ; CAN1 TX
 DCD CAN1_RX0_IRQHandler ; CAN1 RX0
 DCD CAN1_RX1_IRQHandler ; CAN1 RX1
 DCD CAN1_SCE_IRQHandler ; CAN1 SCE

Which makes sense as in the main.h they are stating:

#define CANx_RX_IRQHandler CAN1_RX0_IRQHandler

Therefore their receive interrupt is the same as mine, while the main difference is that they are sending in their main loop. I can test this and provide further results.