cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 goes outside of program code if CAN is enabled and the flash address in not the default

DamianoF
Associate II

I need to debug an application code which is not on the default flash address (0x8000000) but it is at 0x8008000. I just changed the flash origin address to that value. When the execution reaches the CAN initialization part, the program counter goes outside of program code (0x8000f44). Note that the code work as expected if I move the origin flash address to the default value in the linker script.

Here is a minimum reproducible example:

 

#include "main.h"

CAN_HandleTypeDef hcan1;

void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_CAN1_Init(void);

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_CAN1_Init();
  /* USER CODE BEGIN 2 */
  // Setup can
  const uint32_t filter_mask = 0x00000000;
  const uint32_t filter_id = 0x00000000;
  CAN_FilterTypeDef canfilterconfig = (CAN_FilterTypeDef) {
  	  .FilterBank = 0,
  	  .FilterActivation = CAN_FILTER_ENABLE,
  	  .FilterFIFOAssignment = CAN_FILTER_FIFO0,
  	  .FilterMaskIdHigh = (filter_mask >> 13) & 0xFFFF,
  	  .FilterMaskIdLow = (filter_mask << 3) & 0xFFF8,
  	  .FilterIdHigh = (filter_id >> 13) & 0xFFFF,
  	  .FilterIdLow = (filter_id << 3) & 0xFFF8,
  	  .FilterMode = CAN_FILTERMODE_IDMASK,
  	  .FilterScale = CAN_FILTERSCALE_32BIT,
  	  .SlaveStartFilterBank = 27,
  };
  HAL_CAN_ConfigFilter(&hcan1, &canfilterconfig);
  HAL_CAN_Start(&hcan1);
  HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
  /* USER CODE END 2 */
  while (1)
  {
  }
}

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 8;
  RCC_OscInitStruct.PLL.PLLN = 180;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 2;
  RCC_OscInitStruct.PLL.PLLR = 2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  if (HAL_PWREx_EnableOverDrive() != HAL_OK)
  {
    Error_Handler();
  }

  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_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    Error_Handler();
  }
}

static void MX_CAN1_Init(void)
{

  hcan1.Instance = CAN1;
  hcan1.Init.Prescaler = 15;
  hcan1.Init.Mode = CAN_MODE_NORMAL;
  hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;
  hcan1.Init.TimeSeg1 = CAN_BS1_5TQ;
  hcan1.Init.TimeSeg2 = CAN_BS2_6TQ;
  hcan1.Init.TimeTriggeredMode = DISABLE;
  hcan1.Init.AutoBusOff = DISABLE;
  hcan1.Init.AutoWakeUp = DISABLE;
  hcan1.Init.AutoRetransmission = DISABLE;
  hcan1.Init.ReceiveFifoLocked = DISABLE;
  hcan1.Init.TransmitFifoPriority = DISABLE;
  if (HAL_CAN_Init(&hcan1) != HAL_OK)
  {
    Error_Handler();
  }

}

static void MX_GPIO_Init(void)
{
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
}

void Error_Handler(void)
{
  __disable_irq();
  while (1)
  {
  }
}

#ifdef  USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
}
#endif /* USE_FULL_ASSERT */

 

Here is the linker part I changed:

 

MEMORY
{
  RAM    (xrw)    : ORIGIN = 0x20000000,   LENGTH = 128K
  FLASH    (rx)    : ORIGIN = 0x8008000,   LENGTH = 480K
}

 

Attached you can find the whole project

 

1 ACCEPTED SOLUTION

Accepted Solutions
SofLit
ST Employee

Hello,

Did you set the vector table to this new flash address:

SCB->VTOR = 0x8008000;

in system_stm32f4xx.c ?

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

2 REPLIES 2
SofLit
ST Employee

Hello,

Did you set the vector table to this new flash address:

SCB->VTOR = 0x8008000;

in system_stm32f4xx.c ?

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.

Yeah, even the answers here guide you to the issue - it is not the solution.

Remember this:

  • on every reset done, or power up - the MCU looks at 0x08000000 for the SP value and at 0x08000004 for the entry to the Reset_Handler
  • So, you "MUST" have code at 0x08000000, with the vector table!
  • you can branch via the entry on 0x08000004 (the address value written there) to your Reset_Handler, now somewhere else, e.g. at 0x08008000.
  • but you need code (SP and address of Reset Handler) at 0x08000000!

Yes, you can move the Vector Table to a different address, e.g. 0x08008000. But a "chicken and egg" problem:
Your MCU starts always at 0x08000000, and just now you can move the Vector Table (via a Reset_Handler entry address found at 0x0800004 and doing all this stuff).

You have to have code at 0x08000000! At least a little bit of code "binding" now to your new address location for all other stuff at 0x08008000, e.g. with a new vector table (relocate the Vector Table base address via code, but done in the "master/main" Reset_Handler, referenced via its entry address at 0x08000004 (and SP value in 0x08000000).

Without any "correct" code on 0x08000000 and 0x08000004 - it cannot work. These locations must be programmed with "code" which forwards now to your code at 0x08008000.