| 
 
金牌会员  
 
	积分2107金钱2107 注册时间2017-2-11在线时间307 小时 | 
 
 
 楼主|
发表于 2020-12-2 16:45:19
|
显示全部楼层 
| 本帖最后由 jiangyy 于 2020-12-9 10:06 编辑 
 废了九牛二虎之力(花了两天时间研究IAP),终于搞定了IDE软件如何IAP跳转。具体细节如下:
 
 一、准备bootloader程序
 因为STM32CUBEIDE软件生成的hex文件比较大,所以要给足够大的空间给bootloader(具体要看你生成的bin文件大小),我自己没加什么东西,就有32kb了,在这里我只是简单的做个演示,所以我给了它48kb。
 下面几个步骤很关键,如下:
 1.修改内部flash链接文件(STM32F407ZGTX_FLASH.ld)
 
 
 2.编写一个IAP跳转函数  你可以自己建立一个文件,也可以在main.c文件编写这个函数。复制代码/* Memories definition */
MEMORY
{
  CCMRAM    (xrw)    : ORIGIN = 0x10000000,   LENGTH = 64K
  RAM    (xrw)    : ORIGIN = 0x20000000,   LENGTH = 128K
  FLASH    (rx)    : ORIGIN = 0x8000000,   LENGTH = 48K
}
 
 复制代码#define ApplicationAddress       0x800C000          //应用程序起始地址(存放在FLASH)
typedef  void ( * pFunction ) ( void ); //定义一个函数类型的参数.
void iap_load_app(uint32_t appAddr);
//ulAddr_App:用户代码起始地址.
void iap_load_app(uint32_t appAddr)
{
        pFunction jump2app;
        printf("first word : 0x%x\r\n",(*(uint32_t*)appAddr));
        if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20020000)
        {
                printf("IAP load APP!\r\n");
                HAL_RCC_DeInit();
                jump2app = (void (*)())*(__IO uint32_t*) (appAddr + 4);
                __set_MSP(*(__IO uint32_t*) appAddr);
                jump2app();
        }
}
特别注意,HAL_RCC_DeInit();这个一定要加上,否则无法跳转!!!!这个坑我挖了好长时间终于找到是这个地方缺少了导致无法跳转,我也不清楚为啥一定要初始化复位RCC寄存器。还有一个坑是地址校验,不知道有没有小伙伴注意到,就是if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20020000)。红色的地方要修改,否则无法跳转!!!别问我为什么,你用STM32CubeProgrammer读取芯片flash的内容就知道首地址的值是多少就知道了,下面是我一个截图:
 
   
 3.main函数添加IAP跳转函数
 
 
 复制代码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_RTC_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
  /* USER CODE END 2 */
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
        HAL_GPIO_TogglePin(GPIOF,LED0_Pin);
        HAL_Delay(500);
        iap_load_app(ApplicationAddress);
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
此工作完成了一个简单的bootloader程序,下面就是要做一个APP程序了。
 
 二、准备APP程序
 1.修改内部flash链接文件(STM32F407ZGTX_FLASH.ld)
 
 
 复制代码MEMORY
{
  CCMRAM    (xrw)    : ORIGIN = 0x10000000,   LENGTH = 64K
  RAM    (xrw)    : ORIGIN = 0x20000000,   LENGTH = 128K
  FLASH    (rx)    : ORIGIN = 0x800C000,   LENGTH = 976K
}
在这里有人有点小疑问,为啥ORIGIN = 0x800C000?因为bootloader分配了0xC000字节大小,也就是48kb;起先默认FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K,所以在这里就应该修改ORIGIN = 0x800C000,LENGTH = 1024K-48K = 976K,不懂可以看一下芯片手册。
 
 2.修改中断偏移量地址
 这个很关键,不然APP是无法启动的。具体修改的地方是在文件夹Core - > Src文件夹 -> system_stm32f4xx.c文件,其中有个宏定义 VECT_TAB_OFFSET,这个值默认是 0x00,修改为:
 
 
 复制代码/*!< Uncomment the following line if you need to relocate your vector Table in
     Internal SRAM. */
/* #define VECT_TAB_SRAM */
#define VECT_TAB_OFFSET  0xC000 /*!< Vector Table base offset field.
                                   This value must be a multiple of 0x200. */
3.main函数写个简单的应用,如下:
 
 复制代码int main(void)
{
  /* USER CODE BEGIN 1 */
        uint8_t i = 0;
  /* 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_RTC_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
  /* USER CODE END 2 */
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  HAL_GPIO_WritePin(GPIOF,BEEP_Pin,GPIO_PIN_SET);
  HAL_Delay(500);
  HAL_GPIO_WritePin(GPIOF,BEEP_Pin,GPIO_PIN_RESET);
  while (1)
  {
        HAL_GPIO_TogglePin(GPIOF,LED1_Pin);
        HAL_Delay(200);
        i++;
        printf("i = %d\r\n",i);
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
好了,一切准备就绪,开始准备烧录bootloader。使用STM32CubeProgrammer全片擦除falsh,然后烧录bootloader和APP程序,串口打印显示如下:
 
   
 可以正常运行了,哎,心累啊!!!不过终于解决了这个问题,希望对使用STM32CubeIDE编程的小伙伴有帮助,也希望点个赞告慰一下我坚持不懈的找BUG。3QY
  
 
 
 | 
 |