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?