Skip to main content
Graduate
March 1, 2024
Solved

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

  • March 1, 2024
  • 1 reply
  • 1377 views

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

 

    This topic has been closed for replies.
    Best answer by mƎALLEm

    Hello,

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

    SCB->VTOR = 0x8008000;

    in system_stm32f4xx.c ?

    1 reply

    mƎALLEmAnswer
    Technical Moderator
    March 1, 2024

    Hello,

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

    SCB->VTOR = 0x8008000;

    in system_stm32f4xx.c ?

    Visitor II
    March 3, 2024

    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.