Error de tiempo de espera de inicialización CAN en STM32F4

2

Estoy usando una placa Nucleo STM32F446ZET6U (programada con CubeMx y Keil uVision 5) e intento usar algunos de los ejemplos del ST para aprender sobre sus periféricos. Estoy atascado con el periférico CAN. El problema es que cuando el código entra en la

HAL_StatusTypeDef HAL_CAN_Init(CAN_HandleTypeDef* hcan)

devuelve un HAL_TIMEOUT por lo que la CAN no se puede inicializar. Quiero usar CAN en el modo LOOPBACK (sin un transceptor externo conectado) para probar las funciones. Mientras rastreé el error del programa con el Depurador KEIL, el código parece estar atascado en el

/* 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;
  }
}

Que está en el archivo stm32f4xx_hal_can.c.

Así que busqué en la hoja de datos y encontré esto

  

30.4.1 Modo de inicialización   La inicialización del software se puede hacer mientras el hardware está en el modo de inicialización. Para ingresar a este modo, el software establece el bit INRQ en el registro CAN_MCR y espera hasta que el hardware haya confirmado la solicitud configurando el bit INAK en el registro CAN_MSR. Para salir del modo de inicialización, el software borra el bit INQR. bxCAN ha abandonado el modo de inicialización una vez que el hardware ha eliminado el bit INAK.

y también porque es el bit 0 del registro CAN_MSR, también lo indica

  

Bit 0 INRQ: solicitud de inicialización   El software borra este bit para cambiar el hardware al modo normal. Una vez que se han monitoreado 11 bits recesivos consecutivos en la señal Rx, el hardware CAN está sincronizado y listo para la transmisión y recepción. El hardware señala este evento al borrar el bit INAK en el registro CAN_MSR. El software establece este bit para solicitar al hardware CAN que ingrese al modo de inicialización. Una vez que el software ha establecido el bit INRQ, el hardware CAN espera hasta que la actividad CAN actual (transmisión o recepción) se complete antes de ingresar al modo de inicialización. El hardware señala este evento estableciendo el bit INAK en el registro CAN_MSR.

Después de esto, puedo entender que el problema es que CAN_RX no recibe los 11 bits recesivos, por lo que el Hardware no borra el Bit INAK en el registro CAN_MSR, por lo que no se puede inicializar el CAN. Siento que el problema podría ser el hecho de que no uso un transceptor, por lo que de alguna manera el CAN_RX no puede recibir los 11 bits recesivos que necesita, pero si no es así, no sé cómo solucionarlo. (Ya ordené algunos transceptores y los probaré cuando lleguen). Esta es también la implementación del código:

El reloj está configurado para el HSI interno a 16 MHz y APB1 Prescaler a 1, por lo que la CAN obtiene un reloj de 16 MHz.

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);
}

Aquí está el procedimiento de inicialización de CAN. Con 16MHz de reloj y un prescaler de 2, entonces SJW = 1, BS1 = 11, BS2 = 4 le da una velocidad en baudios de 500 kbps con el punto de muestra en el 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();
  }

}

Entonces, ¿el problema puede ser el hecho de que no tengo un transceptor externo o es otra cosa?

    
pregunta vamoirid

3 respuestas

2

No pude probar tu solución porque no tenía otros dispositivos CAN, ¡pero intenté usar un puente entre los pines y funcionó! ¡No puedo entender por qué porque la hoja de datos indica que el pin TX está conectado al RX internamente!

    
respondido por el vamoirid
1

Si en realidad usa el pin CAN1_RX (no está en modo de bucle invertido), entonces el pin CAN1_RX debe colocarse alto, ya sea interna o externamente. La lógica recesiva es alta en el lado del microcontrolador y la lógica baja es dominante. En el bus CAN es una especie de inverso, una diferencia de alto voltaje es dominante y ninguna diferencia de voltaje es recesiva.

Realmente no necesita los transceptores hasta que tenga más de un dispositivo CAN. Tampoco les duele, pero entonces la resistencia (s) de terminación en el lado del bus CAN debe conectarse entre CAN_H y CAN_L (actúa como una resistencia de agrupamiento, para obtener un nivel de voltaje recesivo (diferencial) bien definido) en el lado del bus CAN, aproximadamente 0 V).

    
respondido por el Peter Mortensen
1

Tuve el mismo problema cuando usé el modo de bucle de retorno silencioso. La solución fue levantar el pin RX para que pudiera recibir 11 bits recesivos al cambiar un modo del "Modo de inicialización" al "Modo normal".

Editar: - También tengo el mismo problema que durante la inicialización, el CAN estaba esperando el ACK. pero descubrí que configuré el pin Rx como modo GPIO_NOPULL y eso crea un problema porque generalmente el bus CAN permanece ALTO cuando no hay comunicación pero pasa a LOW cuando el mensaje se envía a través del bus. La mejor solución es configurar el pin Rx y Tx como modo GPIO_PULLUP.

    
respondido por el Viktor Anchutin

Lea otras preguntas en las etiquetas