Skip to main content
RNews.1
Associate
March 29, 2020
Question

Unable to receive CAN messages between two STM32FI-Discovery Boards

  • March 29, 2020
  • 1 reply
  • 2799 views

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.

1 reply

Tesla DeLorean
Guru
March 29, 2020

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 VenmoUp vote any posts that you find helpful, it shows what's working..
RNews.1
RNews.1Author
Associate
March 29, 2020

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.