IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> stm32f4 CubeMX生成IAR工程 移植ST官方 Bootloader 教程 -> 正文阅读

[嵌入式]stm32f4 CubeMX生成IAR工程 移植ST官方 Bootloader 教程

一、前言

产品发布后的升级不能再依赖于烧录器,如果能用产品预留的串口就可以更新芯片的APP程序,对于一些不便于拆卸的产品,这种维护方式非常好用。

bootloader的代码有很多选择,比如正点原子的bootloader 和 RT-thread 官方的bootloader。
作者选用ST官方提供的bootloader,使用Ymodem协议传输。

bootloader的工作原理这里不展开说,总结下来就是把bootloader的程序写到原来的0x08000000,而主程序作为App程序,往0x08008000地址烧录,bootloader里提供三个功能,一个是往0x08008000里烧录App,一个是下载0x08008000里的程序,一个是跳转到0x08008000 App程序。
当然刚上电是先进入bootloader,再跳转App。

二、CubeMX生成 IAR 工程

1.CubeMX生成工程

在CubeMX除了选择MCU还可以选择开发板的,有限官方的开发板自带了IAP例程,也就是bootloader。
在这里插入图片描述
Toolchain/IDE 选择EWARM就是生成IAR工程了。注意要配置好烧程序用的串口。
在这里插入图片描述

2.官方的IAP例程

只有默写板子有IAP例程,可以去安装包Applications的这个路径下找到IAP文件夹。
在这里插入图片描述
这是个文件和对应的头文件就是用到的,另外main 函数里有写进入menu.c 的入口函数,也可以复制到自己的程序中。
在这里插入图片描述

三、移植bootloader

1.移植相关代码

将bootloader相关的.c和.h 文件加入工程后就编译一下,如果报有缺少头文件添加一下。
注意下面几个函数:
1.Serial_PutString()函数

这个是代替printf用的(printf文件比较大一般bootloader不使用),这个函数在common.c中,注意修改官方例程中的串口为你的烧录串口,比如你CubeMX 配置的是UART_HandleTypeDef huart1,就把用到串口的地方都改成huart1。

2.Main_Menu ()函数
这个是进入bootloader菜单选择的函数,可以看到串口输入1,2,3,4分别有不同的功能,其中1是烧录app,3是跳转app。

void Main_Menu(void)
{
  uint8_t key = 0;

  Serial_PutString((uint8_t *)"\r\n======================================================================");
  Serial_PutString((uint8_t *)"\r\n=              (C) COPYRIGHT 2016 STMicroelectronics                 =");
  Serial_PutString((uint8_t *)"\r\n=                                                                    =");
  Serial_PutString((uint8_t *)"\r\n=          STM32F4xx In-Application Programming Application          =");
  Serial_PutString((uint8_t *)"\r\n=                                                                    =");
  Serial_PutString((uint8_t *)"\r\n=                       By MCD Application Team                      =");
  Serial_PutString((uint8_t *)"\r\n======================================================================");
  Serial_PutString((uint8_t *)"\r\n\r\n");

  while (1)
  {

    /* Test if any sector of Flash memory where user application will be loaded is write protected */
    FlashProtection = FLASH_If_GetWriteProtectionStatus();
    
    Serial_PutString((uint8_t *)"\r\n=================== Main Menu ============================\r\n\n");
    Serial_PutString((uint8_t *)"  Download image to the internal Flash ----------------- 1\r\n\n");
    Serial_PutString((uint8_t *)"  Upload image from the internal Flash ----------------- 2\r\n\n");
    Serial_PutString((uint8_t *)"  Execute the loaded application ----------------------- 3\r\n\n");

    if(FlashProtection != FLASHIF_PROTECTION_NONE)
    {
      Serial_PutString((uint8_t *)"  Disable the write protection ------------------------- 4\r\n\n");
    }
    else
    {
      Serial_PutString((uint8_t *)"  Enable the write protection -------------------------- 4\r\n\n");
    }
    Serial_PutString((uint8_t *)"==========================================================\r\n\n");

    /* Clean the input path */
    __HAL_UART_FLUSH_DRREGISTER(&huart1);
	
    /* Receive key */
    HAL_UART_Receive(&huart1, &key, 1, RX_TIMEOUT);

    switch (key)
    {
    case '1' :
      /* Download user application in the Flash */
      SerialDownload();
      break;
    case '2' :
      /* Upload user application from the Flash */
      SerialUpload();
      break;
    case '3' :
      Serial_PutString((uint8_t *)"Start program execution......\r\n\n");
      /* execute the new program */
      JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);
      /* Jump to user application */
      JumpToApplication = (pFunction) JumpAddress;
      /* Initialize user application's Stack Pointer */
      __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);
      JumpToApplication();
      break;
    case '4' :
      if (FlashProtection != FLASHIF_PROTECTION_NONE)
      {
        /* Disable the write protection */
        if (FLASH_If_WriteProtectionConfig(OB_WRPSTATE_DISABLE) == HAL_OK)
        {
          Serial_PutString((uint8_t *)"Write Protection disabled...\r\n");
          Serial_PutString((uint8_t *)"System will now restart...\r\n");
          /* Launch the option byte loading */
          HAL_FLASH_OB_Launch();
          /* Ulock the flash */
          HAL_FLASH_Unlock();
        }
        else
        {
          Serial_PutString((uint8_t *)"Error: Flash write un-protection failed...\r\n");
        }
      }
      else
      {
        if (FLASH_If_WriteProtectionConfig(OB_WRPSTATE_ENABLE) == HAL_OK)
        {
          Serial_PutString((uint8_t *)"Write Protection enabled...\r\n");
          Serial_PutString((uint8_t *)"System will now restart...\r\n");
          /* Launch the option byte loading */
          HAL_FLASH_OB_Launch();
        }
        else
        {
          Serial_PutString((uint8_t *)"Error: Flash write protection failed...\r\n");
        }
      }
      break;
    default:
	Serial_PutString((uint8_t *)"Invalid Number ! ==> The number should be either 1, 2, 3 or 4\r");
	break;
    }
  }
}

3.Ymodem_Receive() 函数

这个函数是执行Ymodem传输协议功能的,参考https://blog.csdn.net/INT_TANG/article/details/117334848

2.flash_if.h文件修改

修改USER_FLASH_END_ADDRESS(片内Flash结束地址),和APPLICATION_ADDRESS(App起始地址),这里改成0x08008000,0x08000000~0x08007FFF用于存放bootloader(Note: the 1st sector 0x08000000-0x08007FFF is reserved for the IAP code)

/* End of the Flash address */
#define USER_FLASH_END_ADDRESS        0x080FFFFF
/* Define the user application size */
#define USER_FLASH_SIZE   (USER_FLASH_END_ADDRESS - APPLICATION_ADDRESS + 1)

/* Define the address from where user application will be loaded.
   Note: the 1st sector 0x08000000-0x08007FFF is reserved for the IAP code */
#define APPLICATION_ADDRESS   (uint32_t)0x08008000 

这些修改好可以编译跑一下看看bootloader的输出是否正常。
在这里插入图片描述

3.准备App程序

bootloader使用Ymodem下载时用的是bin文件,IAR中要修改ROM起始地址,中断向量起始地址和输出文件。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.烧录*.bin

然后就可以在SecureCRT里调用Send Ymodem来烧录这个*.bin程序了。
在这里插入图片描述
在这里插入图片描述

移植参考 https://blog.csdn.net/INT_TANG/article/details/117235294 IAR和Keil工程的操作都是一样的。

四、调试及其他注意事项

1.中断向量表偏移没设对

如果debug的时候发现程序进入hard fault大概率是中断向量表没设对,在程序最开始加上下面的这段把向量表的起始地址强制设为App的起始地址。

SCB->VTOR=0x08008000;

2.进入App后时钟起不来或时钟混乱

官方手册上说:一旦启用了PLL,就无法更改主PLL配置参数,因此建议在启用PLL之前先对其进行配置(选择HSI或HSE振荡器为PLL时钟源,以及除法因子M,P,Q和乘法因子N的配置)。

也就是说PLL在启动之后便不能够重新配置。可以先把时钟改为内部时钟然后再配置PLL。

参考 https://blog.csdn.net/xiaoyuanwuhui/article/details/108772487

3.在bootloader的工程里怎么调试app程序

只能看Flash里反汇编的程序,一步步反推app哪里出现了问题。
IAR里看PC寄存器的值() PC指向当前程序运行的地址,跑到0x08008000以后就是进入App程序了。
然后通过看Disassembly反汇编查看对应的App的C程序在哪一行出现问题了。
App生成bin文件和hex文件也可以生成汇编文件的,用这里的反汇编和App的汇编文件去对比。
在这里插入图片描述

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-03-17 22:22:07  更:2022-03-17 22:23:13 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 6:45:59-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码