2
\$\begingroup\$

I am using an STM32F446ZET6U Nucleo Board (programmed with CubeMx and Keil uVision 5) and I try to use some of the ST's examples in order to learn about its peripherals. I am stuck with the CAN peripheral. The problem is that when the code enters the

HAL_StatusTypeDef HAL_CAN_Init(CAN_HandleTypeDef* hcan)

it returns a HAL_TIMEOUT so the CAN can't be initialized. I want to use CAN in the LOOPBACK mode (without an external transceiver connected) in order to test the functions. As I traced the bug of the program with the KEIL Debugger the code seems to be stuck in the

/* Wait the acknowledge */
while((hcan->Instance->MSR & CAN_MSR_INAK) == CAN_MSR_INAK)
{
 if((HAL_GetTick() - tickstart ) > CAN_TIMEOUT_VALUE)
  {
    hcan->State= HAL_CAN_STATE_TIMEOUT;
    /* Process unlocked */
    __HAL_UNLOCK(hcan);
    return HAL_TIMEOUT;
  }
}

Which is in the stm32f4xx_hal_can.c file.

So I searched the datasheet and I found this

30.4.1 Initialization mode The software initialization can be done while the hardware is in Initialization mode. To enter this mode the software sets the INRQ bit in the CAN_MCR register and waits until the hardware has confirmed the request by setting the INAK bit in the CAN_MSR register. To leave Initialization mode, the software clears the INQR bit. bxCAN has left Initialization mode once the INAK bit has been cleared by hardware.

and also because it is the 0 bit of the CAN_MSR register it also states

Bit 0 INRQ: Initialization request The software clears this bit to switch the hardware into normal mode. Once 11 consecutive recessive bits have been monitored on the Rx signal the CAN hardware is synchronized and ready for transmission and reception. Hardware signals this event by clearing the INAK bit in the CAN_MSR register. Software sets this bit to request the CAN hardware to enter initialization mode. Once the software has set the INRQ bit, the CAN hardware waits until the current CAN activity (transmission or reception) is completed before entering the initialization mode. Hardware signals this event by setting the INAK bit in the CAN_MSR register.

So after this, I can understand that the problem is that the CAN_RX doesn't receive the 11 recessive bits so the Hardware does not clear the INAK Bit in the CAN_MSR Register so the CAN cannot be initialized. I feel that the problem might be the fact that I don't use a transceiver so somehow the CAN_RX can't receive the 11 recessive bits that it needs but if it is not this then I don't know how to fix it. (I have already ordered some transceivers and I am going to test it when they arrive.)This is also the code implementation:

The clock is set to the internal HSI at 16 MHz and APB1 Prescaler to 1 so the CAN gets 16MHz clock.

void SystemClock_Config(void)
{

  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;

    /**Configure the main internal regulator output voltage 
    */
  __HAL_RCC_PWR_CLK_ENABLE();

  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);

    /**Initializes the CPU, AHB and APB busses clocks 
    */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = 16;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

    /**Initializes the CPU, AHB and APB busses clocks 
    */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

    /**Configure the Systick interrupt time 
    */
  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

    /**Configure the Systick 
    */
  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

  /* SysTick_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}

Here is the CAN Initialization Procedure. With 16MHz clock and a prescaler of 2 then the SJW = 1, BS1 = 11, BS2 = 4 gives you a baudrate of 500kbps with the sample point in 75%.

static void MX_CAN1_Init(void)
{
    CAN_FilterConfTypeDef  sFilterConfig;
  static CanTxMsgTypeDef        TxMessage;
  static CanRxMsgTypeDef        RxMessage;

  hcan1.Instance = CAN1;
    hcan1.pTxMsg = &TxMessage;
  hcan1.pRxMsg = &RxMessage;

  hcan1.Init.Prescaler = 2;
  hcan1.Init.Mode = CAN_MODE_LOOPBACK;
  hcan1.Init.SJW = CAN_SJW_1TQ;
  hcan1.Init.BS1 = CAN_BS1_11TQ;
  hcan1.Init.BS2 = CAN_BS2_4TQ;
  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__);
  }

     /*##-2- Configure the CAN Filter ###########################################*/
  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;

  if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
  {
    /* Filter configuration Error */
    Error_Handler();
  }

}

So, can the problem be the fact that I don't have an external transceiver or is it something else?

\$\endgroup\$
  • \$\begingroup\$ Did it work...? \$\endgroup\$ – Peter Mortensen Feb 1 '18 at 15:18
  • \$\begingroup\$ Preferably you should place the sample point after the CANopen standard, rather than coming up with some home-made "garage-standard". Was it you who picked this or the ST driver? DS301 lists 85-90% as valid range for location of the sample point at 500kbps, with 87,5% being the recommended practice. The advantage in following the standard is that all cable length recommendations etc are based on it. \$\endgroup\$ – Lundin Feb 2 '18 at 14:06
  • \$\begingroup\$ It was the ST driver not me! Yeah I also noticed that the sample point is below 50% and I don't really understand why \$\endgroup\$ – vamoirid Feb 3 '18 at 18:21
2
\$\begingroup\$

I couldn't try your solution because I didn't have other CAN devices but I tried to just use a jumper between the pins and it really worked! I can't understand why because the datasheet states that the TX pin is connected to the RX internally!

\$\endgroup\$
  • \$\begingroup\$ It does sound as if the CAN driver is not in loopback mode at all. \$\endgroup\$ – Lundin Feb 2 '18 at 14:08
  • \$\begingroup\$ My solution was to pull RX high, not involving other CAN devices. Can you try that as well? \$\endgroup\$ – Peter Mortensen Feb 4 '18 at 15:07
  • \$\begingroup\$ Yeah it worked again like this. I can't understand why though. \$\endgroup\$ – vamoirid Feb 10 '18 at 19:19
1
\$\begingroup\$

If it actually uses pin CAN1_RX (is not in loop back mode), then pin CAN1_RX needs to be pulled high, either internally or externally. Recessive is logic high on the microcontroller side and dominant is logic low. On the CAN bus it is sort of the inverse, a high voltage difference is dominant and no voltage difference is recessive.

You really don't need the transceivers until you have more than one CAN device. They don't hurt either, but then the terminating resistor(s) on the CAN bus side needs to be connected between CAN_H and CAN_L (it acts as a pull-together resistor, to get a well-defined recessive (differential) voltage level on the CAN bus side, approximately 0 V).

\$\endgroup\$
1
\$\begingroup\$

I had the same problem when used silent loopback mode. The solution was to pull up RX pin so it could receive 11 recessive bits while changing a mode from "Initialization mode" to "Normal mode".

Edit:- I have also the same problem that during initialization the CAN was waiting for the ACK. but I found out that I set the Rx pin as GPIO_NOPULL mode and that makes problem because generally CAN bus is staying HIGH when there is no communication but it goes to LOW when the message is being sent via bus. The best solution is to configure the Rx and Tx pin as GPIO_PULLUP mode.

\$\endgroup\$
  • \$\begingroup\$ Do you mean to set the pullup during initialization or via an external resistor? \$\endgroup\$ – Michel Keijzers Nov 19 '18 at 9:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.