# STM32 HAL_CAN_Transmit always returns TIMEOUT (HAL_CAN_STATE_TIMEOUT)

## Setup

I am using an STM32F103C8T6 (aka Blue Pill). With the STM32Cube I set CAN_RX to PB8 and CAN_TX9 to PB9 (these are defaults/nonchangeable).

## Circuit

simulate this circuit – Schematic created using CircuitLab

Components in above circuit:

• STM #1: STM32F103C8T6
• STM #2: STM32F103C8T6
• Transceiver #1: TJA1050 based transceiver (see TJA 1050)
• Transceiver #2: TJA1050 based transceiver (see TJA 1050)

I found out the TJA1050 works on 5V and the output VCCs from STM32 are 3.3V, so I used a breadboard power supply to give 5V to Transceiver 1 and 2 VCC. I assume the USB GNDs are coupled to the GNDs of the STM32s (probably internally since I didn't do any specific wiring), same as the USB +5V is coupled to the VCC of the STMs.

The transceivers already contain 120 ohm resistors so I assume I don't need any additional. The current distance between CANL and CANH of transceiver #1 and #2 is about 10 cm / 4" (simple wire). In my real application it will be about 2 meters.

Also I assume that the CAN TX needs to be connected to the Tranceiver's TX (and RX to RX).

## Can Settings

The generated CAN settings are below. This executes ok.

/* CAN init function */
static void MX_CAN_Init(void)
{

static CanRxMsgTypeDef CanRX;
static CanTxMsgTypeDef CanTX;
CAN_FilterConfTypeDef sFilterConfig;

hcan.Instance = CAN1;

hcan.pRxMsg = &CanRX;
hcan.pTxMsg = &CanTX;

hcan.Init.Prescaler = 128;
hcan.Init.Mode = CAN_MODE_NORMAL;
hcan.Init.SJW = CAN_SJW_1TQ;
hcan.Init.BS1 = CAN_BS1_12TQ;
hcan.Init.BS2 = CAN_BS2_5TQ;
hcan.Init.TTCM = DISABLE;
hcan.Init.ABOM = DISABLE;
hcan.Init.AWUM = DISABLE;
hcan.Init.NART = DISABLE;
hcan.Init.RFLM = DISABLE;
hcan.Init.TXFP = DISABLE;
if (HAL_CAN_Init(&hcan) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}

sFilterConfig.FilterNumber = 0;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig.FilterIdHigh = 0x0000;
sFilterConfig.FilterIdLow = 0x0000;
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
sFilterConfig.FilterActivation = ENABLE;
sFilterConfig.BankNumber = 14;

if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
{
Error_Handler();
}
}


## Program

Transmitter:

int main(void)
{
..
/* USER CODE BEGIN 2 */
hcan.pTxMsg->StdId = 0x100;
hcan.pTxMsg->ExtId = 0x01;
hcan.pTxMsg->RTR   = CAN_RTR_DATA;
hcan.pTxMsg->IDE   = CAN_ID_STD;
hcan.pTxMsg->DLC   = 2;

while (1)
{
hcan.pTxMsg->Data[0] = 0x10;
hcan.pTxMsg->Data[1] = 0x1;

if (HAL_CAN_Transmit(&hcan, CAN_FIFO0) != HAL_OK)
{
Error_Handler();
}
HAL_Delay(1000);
}
}


Receiver (interrupt code is never called):

void RxIntEnable(CAN_HandleTypeDef *CanHandle)

{
if (CanHandle->State == HAL_CAN_STATE_BUSY_TX)
{
CanHandle->State = HAL_CAN_STATE_BUSY_TX_RX0;
}
else
{
CanHandle->ErrorCode = HAL_CAN_ERROR_NONE;
__HAL_CAN_ENABLE_IT(CanHandle, CAN_IT_EWG); // Error warning interrupt
__HAL_CAN_ENABLE_IT(CanHandle, CAN_IT_EPV); // Error passive interrupt
__HAL_CAN_ENABLE_IT(CanHandle, CAN_IT_BOF); // Bus-off interrupt
__HAL_CAN_ENABLE_IT(CanHandle, CAN_IT_LEC); // Last error code interrupt
__HAL_CAN_ENABLE_IT(CanHandle, CAN_IT_ERR); // Error interrupt
}

__HAL_CAN_ENABLE_IT(CanHandle, CAN_IT_FMP0); // FIFO0 message pending interrupt
}

void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef* CanHandle)
{
if ((CanHandle->pRxMsg->StdId == 0x100) &&
(CanHandle->pRxMsg->IDE   == CAN_ID_STD) &&
(CanHandle->pRxMsg->DLC   == 2))
{
printf("1");
}

RxIntEnable(CanHandle);
}


within main:

if (HAL_CAN_Receive_IT(&hcan, CAN_FIFO0) != HAL_OK)
{
Error_Handler();
}


## Loopback mode

When I use loopback mode:

hcan.Init.Mode = CAN_MODE_LOOPBACK


instead of Normal mode, I can transmit and receive messages (and the hcan shows the correct data in the received message).

## Problem

However, in Normal mode (as shown in the code fragment above) I always get a timeout in the next command:

 if (HAL_CAN_Transmit(&hcan, 10) != HAL_OK)


The function returns: HAL_CAN_STATE_TIMEOUT within this fragment (default HAL 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;

/* Cancel transmission */
__HAL_CAN_CANCEL_TRANSMIT(hcan, transmitmailbox);

/* Process unlocked */
__HAL_UNLOCK(hcan);
return HAL_TIMEOUT;
}
}
}


All initialization seems to be ok (all functions return HAL_OK).

## Analysis

What I tried/checked was:

• Using another STM32: no difference
• Using another transceiver: no difference
• Played a bit with the SJW/BS1/BS2 time quantities: no difference
• Making sure the time quantities were equal
• Playing with different data values and filters: no difference
• Checked the output of PB9 (CAN transmit): it seems not to change at all (so this is a problem): no difference
• Removing the wire from GPIO PB9 (CAN Tx) to the TX of my CAN transceiver : no difference.
• Checking the Transmit is cancelled (which is needed and was an old bug, but has already been fixed by the HAL library I'm using).
• Checking the resistance between CANL and CANH which moves between 63 and 70 ohms.
• Checking the voltage between CANL and CANH (while not sending after the error). 0 Voltage; I wouldn't expect this.

## Questions

1. Why do I get a timeout? I'm having a hard time trying to find more to check what I already did.

Related question:

Update

This is an old question, but trying again to get CAN working with same bad result (timeout). I changed some settings and updated the information above accordingly.

• Well, does that transceiver PCB have the termination resistors connected to the CAN lines per default? If you measure resistance between CAN high and CAN low, is it 60 Ohm? Also, perhaps needless to say, but do you share a signal ground between the boards? (Just connecting the PCB supply grounds together should be enough for lab purposes.) Oct 20 '17 at 14:47
• I looked at some of my own code to refresh my memory, try monitoring the DBG bit in the MCR reg. I didnt have time to fully look at its affects but i seem to rememeber an issue where it would get stuck trying to activate normal mode, but when the DBG bit was changed it would release from the timeout loop Jan 18 '18 at 9:38
• Yeah, at least thats what i did, (I use KEIL u5 IDE). Yeah i figured this might be deadpan now, but found the question while looking for answers of my own. If i find anyhting new ill let you know Jan 18 '18 at 9:55
• Did you try to lower the CAN baud rate by increasing the prescaler to 80 in CAN_Config yet? You may need a CM Balun on your signals, like ethernet. for signal integrity to reject CM noise. Jun 22 '18 at 22:33
• If you had 2 calibrated probes with very short matched ground leads and measured A-B to see textbook waveforms then that would eliminate physical level 1 next level 2 ( see OSI model) Jun 23 '18 at 13:08

I got the new version and what a difference there are quite a couple of changes to keep in mind so here are some snippets:


// To send a message
// Old version:
HAL_CAN_Transmit(&hcan1, 10);

//new version:

//To receive a message by polling

// here is the Polling Function

uint8_t messages = HAL_CAN_GetRxFifoFillLevel(&hcan, CAN_RX_FIFO0);
if(messages > 0){
if(HAL_CAN_GetRxMessage(&hcan, CAN_RX_FIFO0, &RxMessage_, RxData_) == HAL_OK){
Indicate();
}
}
}


much different to the old Library but it works very well I have not yet looked at the Interrupts and receiving with them but I am sure that they also work fine in the new version of the HAL_CAN Driver

• Iam work on Stm32f103c8t6 and use Tjaart van aswegen Can example But i didnt recive anything and iam not sure for sending message, there is no error but this is not clear send is on or not Also i wanna to use new version of Stmcube if you have new test examle pleas send me to test Thanks Feb 12 '20 at 11:04
• Thanks for this answer (upvoted). Sorry for having missed this answer. I'm not using CAN anymore, but next time I will check into it. Feb 12 '20 at 11:32
• Ehsan boloor Kashani I have actually moved over to Atmel in the meanwhile, the snippets that i gave above was from a peice of code that i used to test the code my code snippets include a function Indicate() this was a small function to place the data received in to a UART string similar to arduino libraries I didn't use any LEDs or other means of showing when a message is received Feb 13 '20 at 12:27
• Link for the latest STM32CUBE st.com/en/development-tools/stm32cubemx.html Feb 13 '20 at 12:35

Is it not so simple that you have connected the STM32 TX pin to the TX pin of the transceiver? The Transceiver is expecting that signal at the RX pin.

Swap wiring so that STM32 TX >> Transceiver RX and vice versa.

Tx aka Transmit is a one way bus that always feeds into an Rx aka Receive pin.

• I need to check at home, it might indeed be wrong... I see the CAN receiver as one ' device' so I probably have the STM 32 RX pin to the CAN Receiver RX pin too (like in the circuit in my question) ... I can check it today or tomorrow. Jun 18 '18 at 8:58
• I hope it is - good luck! Jun 18 '18 at 8:59
• Although in all circuits I found on internet, I see from the MCU RX coupled to transceiver RX and MCU TX to transceiver TX. Jun 18 '18 at 9:15
• I tried swapping RX and TX but without any improvement. Jun 19 '18 at 21:23
• Did you swap TX and RX at both ends? Jun 20 '18 at 6:46

It has been a long time since i used CAN but the first thing came to my mind is that the possibility of the transmitter is waiting for an ACK from the receiver n order to complete transmission successfully. And the line staying at 0V also makes me think about a missing ACK handshake. I'm sure you have already checked but i would check the global interrupt enable flag on the receiver side.

• I also was thinking about this (missing handshake)... when I use the code with loopback mode than the transmitter gets the interrupt code, so I assume, if I use normal mode the receiver should get it. So I'm almost sure it's some hardware problem... I wonder if it is possible to connect on the STM32_transmitter_can_TX to STM32_transmitter_can_RX and vice versa, and bypass the TJA1050 transceivers, just as a test to check if the TJA's are the problem of software? Jun 18 '18 at 8:33
• Connecting TX1->RX2 and RX1<-TX2 is a little bit tricky. Looking at the transceiver datasheet (nxp.com/docs/en/data-sheet/TJA1050.pdf) it is clear that TX drives push-pull and RX is with pull-up. I would try connecting them only with a few resistances for security. But theoretically I can say that TX1->RX1 won't work because of bidirectional communication requirement for ACK. Jun 18 '18 at 18:47
• Thanks for the reply ... I also see in all circuits that RX on uC is connected to RX at the TJA1050 and same for TX so I assume that is good. Jun 19 '18 at 21:22

I had the same problem getting CAN working on the STM32F103C8T6. I found a small problem in the HAL_CAN_Transmit() function. It would stop executing at this line:


hcan->pTxMsg->DLC &= (uint8_t)0x0000000F;



I changed it to:


TxMessage.DLC &= (uint8_t)0x0000000F;



and got results. There are still a few problems, like in my setup I give a Standard ID and not extended, but it sends an extended ID. Also, I try to send a message and it sends a remote request frame, but I managed to read a message from the STM32 to the Arduino.

Here is my main.c file:



/**
******************************************************************************
* @file           : main.c
* @brief          : Main program body
******************************************************************************
** This notice applies to any and all portions of this file
* that are not between comment pairs USER CODE BEGIN and
* USER CODE END. Other portions of this file, whether
* inserted by the user or by software development tools
* are owned by their respective copyright owners.
*
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*   1. Redistributions of source code must retain the above copyright notice,
*      this list of conditions and the following disclaimer.
*   2. Redistributions in binary form must reproduce the above copyright notice,
*      this list of conditions and the following disclaimer in the documentation
*      and/or other materials provided with the distribution.
*   3. Neither the name of STMicroelectronics nor the names of its contributors
*      may be used to endorse or promote products derived from this software
*      without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f1xx_hal.h"
#include "string.h"
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private variables ---------------------------------------------------------*/
CAN_HandleTypeDef hcan1;
UART_HandleTypeDef huart1;

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/

CAN_FilterConfTypeDef sFilterConfig;
CanTxMsgTypeDef TxMessage;
CanRxMsgTypeDef RxMessage;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
static void MX_CAN_Init(void);
void Serialprintln(char _out[]);
void newline(void);
HAL_StatusTypeDef T_HAL_CAN_Transmit(CAN_HandleTypeDef* hcan, uint32_t Timeout);

/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/

/* USER CODE END PFP */

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
* @brief  The application entry point.
*
* @retval None
*/
int main(void)
{
/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

/* MCU Configuration----------------------------------------------------------*/

/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();

/* USER CODE BEGIN Init */

/* USER CODE END Init */

/* Configure the system clock */
SystemClock_Config();

/* USER CODE BEGIN SysInit */

/* USER CODE END SysInit */

/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
Serialprintln("Welcome");
Serialprintln("UART and GPIO is initiated");
Serialprintln("Clock configured ");
Serialprintln("HAL initiated");
Serialprintln("Going to try to initiate MX_CAN");
Serialprintln("INITIALISING CAN BUS NOW");
MX_CAN_Init();
HAL_Delay(500);
Serialprintln("Setting the Messages and perameters");
Serialprintln("Starting with sFilterConfig");
sFilterConfig.FilterNumber = 0;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig.FilterIdHigh = 0x0000;
sFilterConfig.FilterIdLow = 0x0000;
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
sFilterConfig.FilterActivation = ENABLE;
sFilterConfig.BankNumber = 14;

Serialprintln("Filter config was done now to link to hcan");

HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig);

Serialprintln("Now for the Tx side of it");

Serialprintln("Setting up the TxMessage");
TxMessage.IDE = CAN_ID_STD;
TxMessage.StdId = 0x01;
TxMessage.RTR = CAN_RTR_DATA;

TxMessage.DLC = 8;
TxMessage.Data[0] = 0x00;
TxMessage.Data[1] = 0x01;
TxMessage.Data[2] = 0x02;
TxMessage.Data[3] = 0x03;
TxMessage.Data[4] = 0x04;
TxMessage.Data[5] = 0x05;
TxMessage.Data[6] = 0x06;
TxMessage.Data[7] = 0x07;

Serialprintln("Message data configured");
Serialprintln("Linking it to the hcan ");
/* USER CODE BEGIN 2 */

/* USER CODE END 2 */

/* Infinite loop */
/* USER CODE BEGIN WHILE */
HAL_Delay(500);
while (1)
{
Serialprintln("In the loop now");
Serialprintln("Trying to send a message");
T_HAL_CAN_Transmit(&hcan1, 10);
Serialprintln("Message sent");

/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */

}
/* USER CODE END 3 */

}

/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{

RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;

/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
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_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != 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);
}

/* CAN init function */
static void MX_CAN_Init(void)
{

hcan1.Instance = CAN1;
hcan1.Init.Prescaler = 9;
hcan1.Init.Mode = CAN_MODE_NORMAL;
hcan1.Init.SJW = CAN_SJW_1TQ;
hcan1.Init.BS1 = CAN_BS1_13TQ;
hcan1.Init.BS2 = CAN_BS2_2TQ;
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)
{
newline();
Serialprintln("/////////////////////////////////////////");
Serialprintln("/////////////////////////////////////////");
Serialprintln("ERROR INITIATING CAN BUS");

_Error_Handler(__FILE__, __LINE__);
}
else{
Serialprintln("CAN BUS INITIATED");
}

}

/* USART1 init function */
static void MX_USART1_UART_Init(void)
{

huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}

}

/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
static void MX_GPIO_Init(void)
{

GPIO_InitTypeDef GPIO_InitStruct;

/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();

/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_RESET);

/*Configure GPIO pin : PB13 */
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */
void Serialprintln(char _out[]){
HAL_UART_Transmit(&huart1, (uint8_t *) _out, strlen(_out), 10);
char newline[2] = "\r\n";
HAL_UART_Transmit(&huart1, (uint8_t *) newline, 2, 10);
}

void newline(void){
char newline[2] = "\r\n";
HAL_UART_Transmit(&huart1, (uint8_t *) newline, 2, 10);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
Copied and renamed the transmit function for debugging
*/
HAL_StatusTypeDef T_HAL_CAN_Transmit(CAN_HandleTypeDef* hcan, uint32_t Timeout)
{
Serialprintln("Starting the transmit function now");
uint32_t transmitmailbox = CAN_TXSTATUS_NOMAILBOX;
Serialprintln("transmitmailbox int created");
uint32_t tickstart = 0U;
Serialprintln("tickstart created");

/* Check the parameters */
assert_param(IS_CAN_IDTYPE(hcan->pTxMsg->IDE));
assert_param(IS_CAN_RTR(hcan->pTxMsg->RTR));
assert_param(IS_CAN_DLC(hcan->pTxMsg->DLC));
Serialprintln("Parameters checked");

if(((hcan->Instance->TSR&CAN_TSR_TME0) == CAN_TSR_TME0) || \
((hcan->Instance->TSR&CAN_TSR_TME1) == CAN_TSR_TME1) || \
((hcan->Instance->TSR&CAN_TSR_TME2) == CAN_TSR_TME2))
{
/* Process locked */
__HAL_LOCK(hcan);
Serialprintln("process locked");
Serialprintln("checking hcan status now");

/* Change CAN state */
switch(hcan->State)
{
case(HAL_CAN_STATE_BUSY_RX0):
Serialprintln("HAL_CAN_STATE_BUSY_TX_RX0");
hcan->State = HAL_CAN_STATE_BUSY_TX_RX0;
break;
case(HAL_CAN_STATE_BUSY_RX1):
Serialprintln("HAL_CAN_STATE_BUSY_TX_RX1");
hcan->State = HAL_CAN_STATE_BUSY_TX_RX1;
break;
case(HAL_CAN_STATE_BUSY_RX0_RX1):
Serialprintln("HAL_CAN_STATE_BUSY_TX_RX0_RX1");
hcan->State = HAL_CAN_STATE_BUSY_TX_RX0_RX1;
break;
Serialprintln("HAL_CAN_STATE_BUSY_TX");
hcan->State = HAL_CAN_STATE_BUSY_TX;
break;
}
Serialprintln("Select one empty transmit mailbox");

/* Select one empty transmit mailbox */
if (HAL_IS_BIT_SET(hcan->Instance->TSR, CAN_TSR_TME0))
{
Serialprintln("transmitmailbox = CAN_TXMAILBOX_0;");
transmitmailbox = CAN_TXMAILBOX_0;
}
else if (HAL_IS_BIT_SET(hcan->Instance->TSR, CAN_TSR_TME1))
{
Serialprintln("transmitmailbox = CAN_TXMAILBOX_1;");
transmitmailbox = CAN_TXMAILBOX_1;
}
else
{
Serialprintln("transmitmailbox = CAN_TXMAILBOX_2;");
transmitmailbox = CAN_TXMAILBOX_2;
}

Serialprintln("Set up the Id");
/* Set up the Id */
hcan->Instance->sTxMailBox[transmitmailbox].TIR &= CAN_TI0R_TXRQ;
if (hcan->pTxMsg->IDE == CAN_ID_STD)
{
assert_param(IS_CAN_STDID(hcan->pTxMsg->StdId));
hcan->Instance->sTxMailBox[transmitmailbox].TIR |= ((hcan->pTxMsg->StdId pTxMsg->RTR);
Serialprintln("Setting up a STD ID");
}
else
{
assert_param(IS_CAN_EXTID(hcan->pTxMsg->ExtId));
hcan->Instance->sTxMailBox[transmitmailbox].TIR |= ((hcan->pTxMsg->ExtId pTxMsg->IDE |
hcan->pTxMsg->RTR);
Serialprintln("Setting up an extended ID");
}
Serialprintln("Done setting the ID wrong");
/* Set up the DLC */
Serialprintln("Set up the DLC");

TxMessage.DLC &= (uint8_t)0x0000000F;
//hcan->sTxMailBox[transmit_mailbox].TDTR &= (uint32_t)0xFFFFFFF0;
//hcan->sTxMailBox[transmit_mailbox].TDTR |= TxMessage->DLC;

//hcan->pTxMsg->DLC &= (uint8_t)0x0000000F;
Serialprintln("hcan->pTxMsg->DLC &= (uint8_t)0x0000000F; DONE");
hcan->Instance->sTxMailBox[transmitmailbox].TDTR &= 0xFFFFFFF0U;
Serialprintln("hcan->Instance->sTxMailBox[transmitmailbox].TDTR &= 0xFFFFFFF0U; DONE");
hcan->Instance->sTxMailBox[transmitmailbox].TDTR |= hcan->pTxMsg->DLC;
Serialprintln("hcan->Instance->sTxMailBox[transmitmailbox].TDTR |= hcan->pTxMsg->DLC; DONE");
Serialprintln("Set up the DLC DONE");

/* Set up the data field */
Serialprintln("Set up the data field");
WRITE_REG(hcan->Instance->sTxMailBox[transmitmailbox].TDLR, ((uint32_t)hcan->pTxMsg->Data[3] pTxMsg->Data[2] pTxMsg->Data[1] pTxMsg->Data[0] Instance->sTxMailBox[transmitmailbox].TDHR, ((uint32_t)hcan->pTxMsg->Data[7] pTxMsg->Data[6] pTxMsg->Data[5] pTxMsg->Data[4] Instance->sTxMailBox[transmitmailbox].TIR, CAN_TI0R_TXRQ);

/* Get tick */
tickstart = HAL_GetTick();

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

/* Cancel transmission */
__HAL_CAN_CANCEL_TRANSMIT(hcan, transmitmailbox);

/* Process unlocked */
__HAL_UNLOCK(hcan);
return HAL_TIMEOUT;
}
}
}
/* Change CAN state */
switch(hcan->State)
{
case(HAL_CAN_STATE_BUSY_TX_RX0):
hcan->State = HAL_CAN_STATE_BUSY_RX0;
break;
case(HAL_CAN_STATE_BUSY_TX_RX1):
hcan->State = HAL_CAN_STATE_BUSY_RX1;
break;
case(HAL_CAN_STATE_BUSY_TX_RX0_RX1):
hcan->State = HAL_CAN_STATE_BUSY_RX0_RX1;
break;
default: /* HAL_CAN_STATE_BUSY_TX */
break;
}

/* Process unlocked */
__HAL_UNLOCK(hcan);

/* Return function status */
return HAL_OK;
}
else
{
/* Change CAN state */
hcan->State = HAL_CAN_STATE_ERROR;

/* Return function status */
return HAL_ERROR;
}
}

/* USER CODE END 4 */

/**
* @brief  This function is executed in case of error occurrence.
* @param  file: The file name as string.
* @param  line: The line in file as a number.
* @retval None
*/
void _Error_Handler(char *file, int line)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
while(1)
{
}
/* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
* @brief  Reports the name of the source file and the source line number
*         where the assert_param error has occurred.
* @param  file: pointer to the source file name
* @param  line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/**
* @}
*/

/**
* @}
*/

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/




I got the hint from here:

https://github.com/nitsky/stm32-example/blob/master/stm32/periph/src/stm32f30x_can.c