Hardware CAN initialization fails

Working libraries, libraries being ported and related hardware
Phono
Posts: 68
Joined: Thu Mar 19, 2020 9:32 am

Hardware CAN initialization fails

Post by Phono »

Hi,
I need the CAN in my project, so I decided to start and use the HAL_CAN layer. So far, it is just quick and dirty.
I have cooperated to the development of the HardwareCAN library that was meant to be included in Roger's package. Now that another direction is taken, I have to move on with different means.
I have read the user manual at the top of the core's source file STM32f1xx_hal_can.c. I tried to implement what they say, and I ended up in the following code. I only give here the Init() function, since execution fails here. The code is :

Code: Select all

CAN_HandleTypeDef hCAN;

........

void CANSetup(void)
{
  hCAN.State = HAL_CAN_STATE_RESET ;
  SERIAL.println("Initialisation CAN0") ;
  if ( Serial )
    Serial.end();
  can_rx_head = can_rx_tail = can_rx_lost = 0;
  SERIAL.println("Initialisation CAN1") ;
  CAN_FilterTypeDef sFilterConfig; //declare CAN filter structure
  SERIAL.println("Initialisation CAN2") ;
  GPIO_InitTypeDef GPIO_InitStruct;
  SERIAL.println("Initialisation CAN3") ;
  
  __HAL_RCC_CAN1_CLK_ENABLE() ;

  __HAL_RCC_GPIOB_CLK_ENABLE();

  // Configuration des pins PB8 (RX) et PB9 (TX)
  GPIO_InitStruct.Pin = GPIO_PIN_8;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
  SERIAL.println("Initialisation CAN4") ;

  GPIO_InitStruct.Pin = GPIO_PIN_9;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
  SERIAL.println("Initialisation CAN5") ;

  hCAN.Instance = CAN1;
  hCAN.Init.Prescaler = 16;    // 125 000 b/s
  hCAN.Init.Mode = CAN_MODE_NORMAL;
  hCAN.Init.SyncJumpWidth = CAN_SJW_4TQ;
  hCAN.Init.TimeSeg1 = CAN_BS1_12TQ;
  hCAN.Init.TimeSeg2 = CAN_BS2_5TQ;
  hCAN.Init.TimeTriggeredMode = DISABLE;
  hCAN.Init.AutoBusOff = DISABLE;
  hCAN.Init.AutoWakeUp = DISABLE;
  hCAN.Init.AutoRetransmission = ENABLE;
  hCAN.Init.ReceiveFifoLocked = DISABLE;
  hCAN.Init.TransmitFifoPriority = DISABLE;
  SERIAL.println("Initialisation CAN6") ;
    
  if (HAL_CAN_Init(&hCAN) != HAL_OK)
  {
  SERIAL.print("Etat CAN : ") ;
  SERIAL.println(hCAN.State) ;
     Error( 2 ) ;
  }

  SERIAL.println("Initialisation CAN7") ;
  sFilterConfig.FilterFIFOAssignment=CAN_FILTER_FIFO0; //set fifo assignment
  sFilterConfig.FilterIdHigh=0x245<<5; //the ID that the filter looks for (switch this for the other microcontroller)
  sFilterConfig.FilterIdLow=0;
  sFilterConfig.FilterMaskIdHigh=0;
  sFilterConfig.FilterMaskIdLow=0;
  sFilterConfig.FilterScale=CAN_FILTERSCALE_32BIT; //set filter scale
  sFilterConfig.FilterActivation=ENABLE;
  
  HAL_CAN_ConfigFilter(&hCAN, &sFilterConfig); //configure CAN filter
  SERIAL.println("Initialisation CAN8") ;

  
  HAL_CAN_Start(&hCAN); //start CAN
  SERIAL.println("Initialisation CAN9") ;
  HAL_CAN_ActivateNotification(&hCAN, CAN_IT_RX_FIFO0_MSG_PENDING); //enable interrupts
  SERIAL.println("Initialisation CAN10") ;
}
I did not implement the function HAL_CAN_MspInit() so far. What it is supposed to do is included in the code above. The default weak function HAL_CAN_MspInit() does nothing when called from HAL_CAN_Init(). I have inserted a set of println to see where it fails (I do not have a debugger). The initialization fails in the call of HAL_CAN_Init() which returns with a value HAL_ERROR and the state field of the hCAN variable is 5 = HAL_CAN_STATE_ERROR.
In the HAL_CAN_Init code this means a timeout that happens either if the hardware does not enter the initialization state, or if it does not leave the sleep state.
Could it be a missing clock initialization? According to the manual, it is required to call

Code: Select all

__HAL_RCC_CAN1_CLK_ENABLE() ;
and nothing else.
In the previous library that works today with Roger's core, the clock initialization is somewhat complicated and involves more actions, including stopping the USB to leave room to the CAN (on the F1 they cannot be used at the same time).
I tried to find examples of code, but I only found two for the F4, and it is not obvious that they work, since those who published them did so to claim for help...
User avatar
fpiSTM
Posts: 1723
Joined: Wed Dec 11, 2019 7:11 pm
Answers: 91
Location: Le Mans
Contact:

Re: Hardware CAN initialization fails

Post by fpiSTM »

You should have a look to the cube FW example.
Phono
Posts: 68
Joined: Thu Mar 19, 2020 9:32 am

Re: Hardware CAN initialization fails

Post by Phono »

Thank you, I found there lots of information.
However there is something I cannot master yet.
The manual at the top of the stm32f1xx_hal_can.c says:

Code: Select all

In CAN IRQ handler, call HAL_CAN_IRQHandler()
I understood that I must write an IRQ handler, that must call the HAL_CAN_IRQHandler function that exists it this file. So I did as follows:

Code: Select all

void USB_LP_CAN1_RX0_IRQHandler (void)
{
  HAL_CAN_IRQHandler(&hCAN) ;
}
And I wrote a callback function as follows:

Code: Select all

void HAL_CAN_RxFifo0MsgPendingCallback (CAN_HandleTypeDef *hcan0)
{
  // envoie la trame reçue dans la file d'attente
  can_rx_read(hcan0) ;
}
Where can_rx_read transfers the received frame to my buffer.
Apparently the IRQ handler is never called, but when a frame arrives, the application crashes; this means that the vector points to somewhere wrong.
Who can explain me the handlng of vectors?
stevestrong
Posts: 502
Joined: Fri Dec 27, 2019 4:53 pm
Answers: 8
Location: Munich, Germany
Contact:

Re: Hardware CAN initialization fails

Post by stevestrong »

Maybe an extern "C" before the ISR helps.
Phono
Posts: 68
Joined: Thu Mar 19, 2020 9:32 am

Re: Hardware CAN initialization fails

Post by Phono »

I tried but I could not see, because the Arduino IDE reworks the source files to aggregate them and the extern "C" keyword confused it. I could not have it compile to see whether it would have worrked.
stas2z
Posts: 131
Joined: Mon Feb 24, 2020 8:17 pm
Answers: 8

Re: Hardware CAN initialization fails

Post by stas2z »

yes, as HAL is written on C, not C++, you need to use extern "C" {} for redefining irq handlers etc
Phono
Posts: 68
Joined: Thu Mar 19, 2020 9:32 am

Re: Hardware CAN initialization fails

Post by Phono »

Thank you, you found the point.
I had to declare the ISR as follows to have the Arduino IDE handle it correctly:

Code: Select all

extern "C" void USB_LP_CAN1_RX0_IRQHandler (void) ;

extern "C" void USB_LP_CAN1_RX0_IRQHandler (void)
{
  HAL_CAN_IRQHandler(&hCAN) ;
}
Because the IDE gathers all function prototypes through the whole source and puts this collection at the top of the global source file it makes by merging all tabs.
Phono
Posts: 68
Joined: Thu Mar 19, 2020 9:32 am

Re: Hardware CAN initialization fails

Post by Phono »

Now I am facing a curious behaviour.
After applying the changes before, my project worked for a while. I then continued the porting of other parts of the project I had first commented out.
At a certain point, I started having lots of errors at link time mentioning "undefined reference to ..." for a bunch of identifiers. Then (after some study) I found the following :

- my own identifiers, that were to be called back by the HAL library, produced this error IF I USE THE EXTERN "C" DECLARATION. I removed the extern "C" declaration, and the "undefined reference" error was gone.

- The HAL functions that I am calling, produce the "undefined reference" at link time. ALL OF THEM do so for those defined by STM32f1xx_hal_can.h. Strangely, the function HAL_GPIO_Init DOES NOT produce this error, though I did not include stm32f1xx_hal_gpio.h ! I did not forget to #include STM32f1xx_hal_can.h, though.

I thoroughly checked the compile log, and I ensured that both STM32f1xx_hal_can.c and stm32f1xx_hal_gpio.c have been compiled and their object file is in the temp directory the compiler created for the session.
I reinstalled both the Arduino IDE and the STM32 library (using the board manager, to ensure a "lawful" installation. The errors remained.

I am puzzled.
User avatar
fpiSTM
Posts: 1723
Joined: Wed Dec 11, 2019 7:11 pm
Answers: 91
Location: Le Mans
Contact:

Re: Hardware CAN initialization fails

Post by fpiSTM »

Do you use LTO ? If yes then I advise to not use it.
Phono
Posts: 68
Joined: Thu Mar 19, 2020 9:32 am

Re: Hardware CAN initialization fails

Post by Phono »

I do not use it. However, I also tried with LTO enabled, but with exactly the same result.
Strangely, the function calls to gpio and nvic pose no problem. I checked the source files of these three, but did not notice any difference that could explain this different behaviour.
On thing though, is that all functions that my code calls are :
HAL_CAN_Init()
HAL_CAN_Config_Filter()
HAL_CAN_ActivateNotification()
HAL_CAN_Start()
HAL_CAN_AddTxMessage()
and
HAL_CAN_IRQHandler()

The error occurs for the first five, but not for the last one. Actually, there is a slight difference in the way they are called ; for example :

Code: Select all

void CANsend(CanMsg *pmsg)
{
CAN_TxHeaderTypeDef TxMsgHeader;

  // Recopie du paramètre d'entrée dans la structure de type HAL
  TxMsgHeader.StdId = pmsg->ID ;
  TxMsgHeader.ExtId = pmsg->ID ;
  TxMsgHeader.IDE = pmsg->IDE ;
  TxMsgHeader.RTR = pmsg->RTR ;
  TxMsgHeader.DLC = pmsg->DLC ;
  HAL_CAN_AddTxMessage(&hCAN, &TxMsgHeader, pmsg->Data, &pTxMailbox) ;
  delay( 1 ) ; 
}
This one fails, but

Code: Select all

void USB_LP_CAN1_RX0_IRQHandler (void)
{
  HAL_CAN_IRQHandler(&hCAN) ;
}
This last function does not pose the problem, and the difference is that it is a callback function, which is itself called by the HAL library.
Post Reply

Return to “Libraries & Hardware”