I'm having a bit of trouble with the ST32CubeF4 v1.13.0 example of a CAN network. I'm using an STM32F429 discovery board, but I have ported over the CAN network example from the STM324x9_EVAL board. I built a CAN transceiver bus using MCP2551. I used the gnu-arm-eclipse plugin to generate the base code for my project.
Whenever I want to use the HAL_CAN_Transmit() function it always returns "HAL_CAN_STATE_TIMEOUT". I managed to track down the origin of the problem to the stm32f42xx_hal_can.c file and this piece of code:
/* Check End of transmission flag */
while(!(__HAL_CAN_TRANSMIT_STATUS(hcan, transmitmailbox)))
{
/* Check for the Timeout */
if(Timeout != HAL_MAX_DELAY)
{
if((Timeout == 0U)||((HAL_GetTick() - tickstart ) > Timeout))
{
hcan->State = HAL_CAN_STATE_TIMEOUT;
fprintf(stderr, "Error flag in CAN_Transmit");
/* Process unlocked */
__HAL_UNLOCK(hcan);
return HAL_TIMEOUT;
}
}
}
It seems the transmission flag is never set and the device always times out. I have read elsewhere on the ST forums that it is potentially a bug in the HAL libraries.
Is there a way around this? My ESR register also records this error code: 16253015 which I'm unsure what to make of.
Here is the clock and CAN init code in my main.c:
static void SystemClock_Config(void)
{
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;
/* Enable Power Control clock */
__HAL_RCC_PWR_CLK_ENABLE();
/* The voltage scaling allows optimizing the power consumption when the device is
clocked below the maximum system frequency, to update the voltage scaling value
regarding system frequency refer to product datasheet. */
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/* Enable HSE Oscillator and activate PLL with HSE as source */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 25;
RCC_OscInitStruct.PLL.PLLN = 360;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
/* Activate the Over-Drive mode */
HAL_PWREx_EnableOverDrive();
/* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
clocks dividers */
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);
}
static void CAN_Config(void)
{
CAN_FilterConfTypeDef sFilterConfig;
static CanTxMsgTypeDef TxMessage;
static CanRxMsgTypeDef RxMessage;
/*##-1- Configure the CAN peripheral #######################################*/
CanHandle.Instance = CAN1;
CanHandle.pTxMsg = &TxMessage;
CanHandle.pRxMsg = &RxMessage;
CanHandle.Init.TTCM = DISABLE;
CanHandle.Init.ABOM = DISABLE;
CanHandle.Init.AWUM = DISABLE;
CanHandle.Init.NART = DISABLE;
CanHandle.Init.RFLM = DISABLE;
CanHandle.Init.TXFP = DISABLE;
CanHandle.Init.Mode = CAN_MODE_NORMAL;
CanHandle.Init.SJW = CAN_SJW_1TQ;
CanHandle.Init.BS1 = CAN_BS1_6TQ;
CanHandle.Init.BS2 = CAN_BS2_8TQ;
CanHandle.Init.Prescaler = 2;
if(HAL_CAN_Init(&CanHandle) != HAL_OK)
{
/* Initialization Error */
fprintf(stderr, "Error_Handler active in CAN Config Init");
Error_Handler();
}
/*##-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(&CanHandle, &sFilterConfig) != HAL_OK)
{
/* Filter configuration Error */
fprintf(stderr, "Error_Handler active CAN Config Filter");
Error_Handler();
}
/*##-3- Configure Transmission process #####################################*/
CanHandle.pTxMsg->StdId = 0x321;
CanHandle.pTxMsg->ExtId = 0x01;
CanHandle.pTxMsg->RTR = CAN_RTR_DATA;
CanHandle.pTxMsg->IDE = CAN_ID_STD;
CanHandle.pTxMsg->DLC = 2;
}
As well as where my main calls to HAL_CAN_Transmit and Receive are:
int main(void)
{
/* STM32F4xx HAL library initialization:
- Configure the Flash prefetch, instruction and Data caches
- Configure the Systick to generate an interrupt each 1 msec
- Set NVIC Group Priority to 4
- Global MSP (MCU Support Package) initialization
*/
HAL_Init();
/* Configure the system clock to 180 MHz */
SystemClock_Config();
BSP_LED_Init(LED3);
BSP_LED_Init(LED4);
/* Configure Key Button */
BSP_PB_Init(BUTTON_KEY, BUTTON_MODE_GPIO);
/*##-1- Configure the CAN peripheral #######################################*/
CAN_Config();
/*##-2- Start the Reception process and enable reception interrupt #########*/
if(HAL_CAN_Receive_IT(&CanHandle, CAN_FIFO0) != HAL_OK)
{
fprintf(stderr, "Error_Handler active in CAN_Receive");
Error_Handler();
}
/* Infinite loop */
while(1)
{
while(BSP_PB_GetState(BUTTON_KEY) == KEY_PRESSED)
{
if(ubKeyNumber == 0x4)
{
ubKeyNumber = 0x00;
}
else
{
LED_Display(++ubKeyNumber);
/* Set the data to be transmitted */
CanHandle.pTxMsg->Data[0] = ubKeyNumber;
CanHandle.pTxMsg->Data[1] = 0xAD;
/*##-3- Start the Transmission process ###############################*/
if(HAL_CAN_Transmit(&CanHandle, 10000) != HAL_OK)
{
/* Transmition Error */
fprintf(stderr, "Error_Handler active in CAN Transmit");
Error_Handler();
}
HAL_Delay(10);
while(BSP_PB_GetState(BUTTON_KEY) != KEY_NOT_PRESSED)
{
}
}
}
}
}
EDIT:
I found a solution, though not an ideal one. I lowered the CAN baud rate by increasing the prescaler to 80 in CAN_Config. This has resulted in successful CAN communication.
The problem was most likely with my CAN bus. The CAN bus length might have been to short (mere centimeters) to use the 120 ohm termination resistances and the bit right to high to use the bus without them.