cancel
Showing results for 
Search instead for 
Did you mean: 

Can anyone help me with my project using a STM32F103 and a CAN transceiver ? I can't make it work

Math86
Associate II

Hi everyone,

I've been trying to reprogram some modules made to transmit some CAN data frames to a car when plugged in the OBD socket. Basically the MCU is programmed to send some frames and I'd like to replace these frames with others ones.

Here is a picture of the device as well as a schematic I made :

0693W00000Lwpq8QAB.jpg0693W00000LwpqrQAB.pngThe MCU is a STM32F103C8T6 and the CAN transceiver shows the writing "NXP A1040/C DBA000 D64.1" on it. When I type that in Google it returns the TJA1040 high speed CAN transceiver : https://www.nxp.com/docs/en/data-sheet/TJA1040.pdf.

So I did a bit of research and started my project. Here is the configuration I used in MX :

0693W00000LwpwGQAR.png0693W00000LwpwLQAR.png0693W00000LwpwpQAB.png0693W00000LwpwuQAB.png 

I first started by trying to use the buzzer to test the basics and it works. Then my next step was to use the CAN loopback mode to try and see if I could send/receive messages. This is where I struggle.

I joined the whole code below. It compiles and runs (I use a ST link to debug). It just never gets into the interrupt function that is supposed to activate the buzzer. Please note that the transceiver is correclty powered with 5V from the ST link during my test (I checked with a multimeter). I really have no idea what's my issue, any help would be greatly appreciated. Thanks in advance !

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2022 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
 
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
 
/* USER CODE END Includes */
 
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
 
/* USER CODE END PTD */
 
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
 
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
 
/* USER CODE END PM */
 
/* Private variables ---------------------------------------------------------*/
 CAN_HandleTypeDef hcan;
 
/* USER CODE BEGIN PV */
 
/* USER CODE END PV */
 
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_CAN_Init(void);
/* USER CODE BEGIN PFP */
 
/* USER CODE END PFP */
 
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
 
CAN_TxHeaderTypeDef TxHeader;
CAN_RxHeaderTypeDef RxHeader;
 
uint32_t Mailbox;
uint8_t TxData[8];
uint8_t RxData[8];
 
uint8_t count = 0;
 
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
	HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, RxData);
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, 1);
	HAL_Delay(100);
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, 0);
 
}
 
/* USER CODE END 0 */
 
/**
  * @brief  The application entry point.
  * @retval int
  */
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_CAN_Init();
  /* USER CODE BEGIN 2 */
 
  HAL_CAN_Start(&hcan);
 
  HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING);
 
  TxHeader.DLC = 1;
  TxHeader.ExtId = 0;
  TxHeader.IDE = CAN_ID_STD;
  TxHeader.RTR = CAN_RTR_DATA;
  TxHeader.StdId = 0x103;
  TxHeader.TransmitGlobalTime = DISABLE;
 
  TxData[0] = 0xf3;
 
  HAL_CAN_AddTxMessage(&hcan, &TxHeader, TxData, &Mailbox);
 
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  HAL_CAN_AddTxMessage(&hcan, &TxHeader, TxData, &Mailbox);
	  HAL_Delay(5000);
    /* 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 = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
 
  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  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();
  }
 
  /** Initializes the CPU, AHB and APB buses 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();
  }
}
 
/**
  * @brief CAN Initialization Function
  * @param None
  * @retval None
  */
static void MX_CAN_Init(void)
{
 
  /* USER CODE BEGIN CAN_Init 0 */
 
  /* USER CODE END CAN_Init 0 */
 
  /* USER CODE BEGIN CAN_Init 1 */
 
  /* USER CODE END CAN_Init 1 */
  hcan.Instance = CAN1;
  hcan.Init.Prescaler = 18;
  hcan.Init.Mode = CAN_MODE_LOOPBACK;
  hcan.Init.SyncJumpWidth = CAN_SJW_1TQ;
  hcan.Init.TimeSeg1 = CAN_BS1_1TQ;
  hcan.Init.TimeSeg2 = CAN_BS2_2TQ;
  hcan.Init.TimeTriggeredMode = DISABLE;
  hcan.Init.AutoBusOff = DISABLE;
  hcan.Init.AutoWakeUp = DISABLE;
  hcan.Init.AutoRetransmission = DISABLE;
  hcan.Init.ReceiveFifoLocked = DISABLE;
  hcan.Init.TransmitFifoPriority = DISABLE;
  if (HAL_CAN_Init(&hcan) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN CAN_Init 2 */
 
  CAN_FilterTypeDef canfilterconfig;
  canfilterconfig.FilterActivation = CAN_FILTER_DISABLE;
  canfilterconfig.FilterBank = 10;
  canfilterconfig.FilterFIFOAssignment = CAN_RX_FIFO0;
  canfilterconfig.FilterIdHigh = 0;
  canfilterconfig.FilterIdLow = 0x0000;
  canfilterconfig.FilterMaskIdHigh = 0;
  canfilterconfig.FilterMaskIdLow = 0x0000;
  canfilterconfig.FilterMode = CAN_FILTERMODE_IDMASK;
  canfilterconfig.FilterScale = CAN_FILTERSCALE_32BIT;
  canfilterconfig.SlaveStartFilterBank = 12;
 
  HAL_CAN_ConfigFilter(&hcan, &canfilterconfig);
 
  /* USER CODE END CAN_Init 2 */
 
}
 
/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
 
  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOD_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
 
  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
 
  /*Configure GPIO pin : PA5 */
  GPIO_InitStruct.Pin = GPIO_PIN_5;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
}
 
/* USER CODE BEGIN 4 */
 
/* USER CODE END 4 */
 
/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  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,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

1 ACCEPTED SOLUTION

Accepted Solutions

Please decrease the prescaler as much as possible and increase BS1 and BS2 in order to match your bitrate of 500kb/s

I propose for example:

Prescaler = 4

Bit Segment 1 = 11 Times

Bit Segment 2 = 6 Times

PS: if you disable the filter you cannot receive any frame; the CAN cell will acknowledge the received frame but the data of the frame doesn't go to your FIFO.

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

View solution in original post

10 REPLIES 10
JPeac.1
Senior

You didn't mention what you're using for the second node when testing your code. CAN requires a minimum of two nodes, connected with twisted-pair wire, and a termination resistor at each end. Both ends have to use the same data rate and bit timing.

You'll need to enable the SCE interrupt to trap errors. At a guess you have bus errors, which is why your RX interrupts don't trigger. Too many bus errors and the transceiver will be disconnected from the bus, without sending or receiving any messages. Check the status registers in the SCE interrupt to determine what your error is.

Wouldn't be putting delays in callbacks, these are done in interrupt context, so probably might expect multiple messages on the bus over 100 ms, and you're going to jam things up and cause overflows.

Want to use an LED, toggle it, and scope the pin to measure intervals.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Hello,

Thanks a lot for your answer. I don't have another node (just a resistor). I thought that with the loopback mode it wasn't necessary. I was referring to this video : https://www.youtube.com/watch?v=JfWlIY0zAIc&t=0s where the author also uses the loopback mode with no other node. Is that a mistake ?

Since there is no other node on the bus I guess there should be no error right ? I'm very new to all of this (this is my first electronics project) so I'm sorry if it takes a lot of explanation to make me understand something.

Hello,

Thanks a lot for your answer. I tried without the buzzer toggle and the delays but it still doesn't work. I set a breakpoint in the callback function but it's never called. It just loops the while infinitely (I set another breakpoint there and it's called every 5sec as per the delay).

Any other idea on what could be the issue ? Thanks in advance!

SofLit
ST Employee

Hello,

When you are using CAN in loopback mode, the transceiver does not have effects and you can remove it if you want. The purpose of this mode is to test CAN communication without any external HW (transceivers, termination resistors etc ..)

Meanhile, in your code you have disabled the CAN filter on FIFO 0, Why?:

canfilterconfig.FilterActivation = CAN_FILTER_DISABLE;

It should be canfilterconfig.FilterActivation = CAN_FILTER_ENABLE !

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

Hello,

Oh thanks now I know already that the issue doesn't come from the transceiver etc. That's already very useful to me !

I disabled the filter because I thought it might be the reason it wasn't going through. I reactivated it now but still no luck. It is now configured like this :

 /* USER CODE BEGIN CAN_Init 2 */
 
  CAN_FilterTypeDef canfilterconfig;
  canfilterconfig.FilterActivation = CAN_FILTER_ENABLE;
  canfilterconfig.FilterBank = 10;
  canfilterconfig.FilterFIFOAssignment = CAN_RX_FIFO0;
  canfilterconfig.FilterIdHigh = 0;
  canfilterconfig.FilterIdLow = 0x0000;
  canfilterconfig.FilterMaskIdHigh = 0;
  canfilterconfig.FilterMaskIdLow = 0x0000;
  canfilterconfig.FilterMode = CAN_FILTERMODE_IDMASK;
  canfilterconfig.FilterScale = CAN_FILTERSCALE_32BIT;
  canfilterconfig.SlaveStartFilterBank = 12;
 
  HAL_CAN_ConfigFilter(&hcan, &canfilterconfig);
 
  /* USER CODE END CAN_Init 2 */

I'm trying to let every message through since I'm only at the first step, I can take care of filtering later.

Can it be that issue would come from the configuration ?

 /* USER CODE END CAN_Init 1 */
  hcan.Instance = CAN1;
  hcan.Init.Prescaler = 18;
  hcan.Init.Mode = CAN_MODE_LOOPBACK;
  hcan.Init.SyncJumpWidth = CAN_SJW_1TQ;
  hcan.Init.TimeSeg1 = CAN_BS1_1TQ;
  hcan.Init.TimeSeg2 = CAN_BS2_2TQ;
  hcan.Init.TimeTriggeredMode = DISABLE;
  hcan.Init.AutoBusOff = DISABLE;
  hcan.Init.AutoWakeUp = DISABLE;
  hcan.Init.AutoRetransmission = DISABLE;
  hcan.Init.ReceiveFifoLocked = DISABLE;
  hcan.Init.TransmitFifoPriority = DISABLE;
  if (HAL_CAN_Init(&hcan) != HAL_OK)
  {
    Error_Handler();
  }

Thanks in advance !

Please decrease the prescaler as much as possible and increase BS1 and BS2 in order to match your bitrate of 500kb/s

I propose for example:

Prescaler = 4

Bit Segment 1 = 11 Times

Bit Segment 2 = 6 Times

PS: if you disable the filter you cannot receive any frame; the CAN cell will acknowledge the received frame but the data of the frame doesn't go to your FIFO.

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

And typically, to keep sampling point at ~80% of bit time:

Prescaler = 4

Bit Segment 1 = 13 Times

Bit Segment 2 = 4 Times

or

Bit Segment 1 = 14 Times

Bit Segment 2 = 3 Times

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

It works !!! Amazing thank you so much ! It would have taken ages for me to troubleshoot that on my own.