cancel
Showing results for 
Search instead for 
Did you mean: 

Hello, i am implementing a HAL CAN Driver for my STM32F405. I am using a TJA1048 as a Tranciever. Down below there is my Source Code. If i want to Transmit one Message, it ends in the Errorcode: HAL_CAN_ERROR_TX_TERR0. So do you know whats wrong ?

SLeit.1
Associate

My APB1 Clock Frequency is 42Mhz.

Init:

hcan1.Instance = CAN1;

 hcan1.Init.TimeTriggeredMode = DISABLE;

 hcan1.Init.AutoBusOff = ENABLE;

 hcan1.Init.AutoWakeUp = DISABLE;

 hcan1.Init.AutoRetransmission = DISABLE;

 hcan1.Init.ReceiveFifoLocked = DISABLE;

 hcan1.Init.TransmitFifoPriority = DISABLE;

 hcan1.Init.Mode = CAN_MODE_NORMAL;

 hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;

 hcan1.Init.TimeSeg1 = CAN_BS1_2TQ;

 hcan1.Init.TimeSeg2 = CAN_BS2_4TQ;

 hcan1.Init.Prescaler = 5; //6

   if (HAL_CAN_Init(&hcan1) != HAL_OK)

 {

   Error_Handler();

 }

   CAN_FilterTypeDef CAN1_Filter;

   CAN1_Filter.FilterBank = 0;

 CAN1_Filter.FilterMode = CAN_FILTERMODE_IDMASK;

 CAN1_Filter.FilterScale = CAN_FILTERSCALE_32BIT;

 CAN1_Filter.FilterIdHigh = 0x0000;

 CAN1_Filter.FilterIdLow = 0x0000;

 CAN1_Filter.FilterMaskIdHigh = 0x0000;

 CAN1_Filter.FilterMaskIdLow = 0x0000;

 CAN1_Filter.FilterFIFOAssignment = CAN_RX_FIFO0;

 CAN1_Filter.FilterActivation = ENABLE;

 CAN1_Filter.SlaveStartFilterBank = 14;

   if (HAL_CAN_ConfigFilter(&hcan1, &CAN1_Filter) != HAL_OK)

 {

   /* Filter configuration Error */

   Error_Handler();   

 }

   if (HAL_CAN_Start(&hcan1) != HAL_OK)

 {

   /* Start Error */

   Error_Handler();

 }

   /*##-4- Activate CAN TX notification #######################################*/

   if (HAL_CAN_ActivateNotification(&hcan1, CAN_IT_TX_MAILBOX_EMPTY) != HAL_OK)

 {

   /* Notification Error */

   Error_Handler();

 }

      /*##-4- Activate CAN RX notification #######################################*/

 if (HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)

 {

   /* Notification Error */

   Error_Handler();

 }

MspInit:

GPIO_InitTypeDef GPIO_InitStruct;

 /* USER CODE BEGIN CAN1_MspInit 0 */

 /* USER CODE END CAN1_MspInit 0 */

   /* CAN1 clock enable */

     __HAL_RCC_CAN1_CLK_ENABLE();

         //__HAL_PPP_ENABLE_IT(hcan1, );

   /**CAN1 GPIO Configuration   

   PB8    ------> CAN1_RX

   PB9    ------> CAN1_TX

   */

   GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;

   GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

   GPIO_InitStruct.Pull = GPIO_NOPULL;

   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

   GPIO_InitStruct.Alternate = GPIO_AF9_CAN1;

   HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

   /* CAN1 interrupt Init */

   HAL_NVIC_SetPriority(CAN1_TX_IRQn, 0, 0);

   HAL_NVIC_EnableIRQ(CAN1_TX_IRQn);

   HAL_NVIC_SetPriority(CAN1_RX0_IRQn, 0, 0);

   HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn);

   HAL_NVIC_SetPriority(CAN1_RX1_IRQn, 0, 0);

   HAL_NVIC_EnableIRQ(CAN1_RX1_IRQn);

 /* USER CODE BEGIN CAN1_MspInit 1 */

Transmiting the Message:

      TXheader1.StdId = 0x390;

      TXheader1.RTR = CAN_RTR_DATA;

      TXheader1.IDE = CAN_ID_STD;

      TXheader1.DLC = 8;

   

         if(HAL_CAN_AddTxMessage(&hcan1, &TXheader1, tData, &TxMailbox) != HAL_OK){

               Error_Handler();               

         }

         while(HAL_CAN_GetTxMailboxesFreeLevel(&hcan1) == 0){}; // Buffer

1 REPLY 1
MattKefford
Associate III

HAL_CAN_GetTxMailboxesFreeLevel() <- this function will return the number of mailboxes available. If it is greater than 0 then you can send a message. If it is equal to 0 then all your mailboxes are busy. In your case it will most likely return a number and never go into the while loop.

I think the function you want is HAL_CAN_IsTxMessagePending() if you want to poll a certain mailbox and see when it becomes free.

Or just use the CAN_IT_TX_MAILBOX_EMPTY interrupt you have enabled by adding the HAL_CAN_TxMailbox0CompleteCallback() to your code and when the mailbox becomes free that function will be called. I'm not sure you need it though unless you are sending messages at a high rate or you are using the time triggered mode.

The value you set for prescaler will have 1 deducted from it before the BTR register is set, so you can set it to 6 rather than 5, if indeed you want it to be 6.

Those settings for the prescaler and time segments do look a bit odd too though...

With 42MHz, using SJW = 1, time seg1 = 2, time seg2 = 4 will give you a bit rate of 1,000,000 so I assume you're interfacing with a 1Mbit/s CAN bus. But it will also give a time quantum of 142.857 nS and your sample point would be at 42.8% which seems a bit low/early.

If you try prescaler = 3, time seg1 = 11, time seg2 = 2 that should give a 714.286 nS time quantum so multiply that by 14 (11 + 2 + 1) that gives you your 1 microsecond Nominal Bit Time and therefore 1 MBit/s Baud Rate but with a 85.7% sample point which should be better.

Are you able to see the received messages and verify that the hardware/wiring is correct?

If you aren't using time triggered mode and you've verified your hardware, you may as well enable automatic retransmission and you should see most (if not all) of the TERR0 errors stop occurring.

http://www.bittiming.can-wiki.info/