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 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 从零开始手写BootLoader--STM32L073/IAR/HAL库 -> 正文阅读

[嵌入式]从零开始手写BootLoader--STM32L073/IAR/HAL库

从零开始手写BootLoader–STM32L073/IAR/HAL库

一、测试平台:
MCU:STM32L073V8T6(Cortex-M0+)
固件库:HAL+STM Cube
IDE:IAR For STM32
二、实验目的
使用BootLoader通过串口将程序bin文件烧录至单片机内,然后跳转到烧录位置运行程序。
三、基础知识
STM32L073V8T6的启动方式有三种:内置FLASH启动、内置SRAM启动、系统存储器ROM启动,通过BOOT0和BOOT1引脚的设置可以选择从哪中方式启动,这里选择内置的FLASH启动。
四、准备
1 基础功能代码:使用STMCube代码生成器生成,在本实验中开启按键输入、LED引脚与串口4,配置时钟为MSI(4.194MHz)。此部分代码不予演示。
2 App程序:用户最终使用的应用程序(以下用App代替),复位后LED点亮,在while中循环发送字符串。

#define CODE_OFFSET 0x8000
int main(void)
{
  __disable_irq();
  SCB->VTOR = FLASH_BASE | CODE_OFFSET ;
  __enable_irq();

  HAL_Init();

  System_HSIClock_Config();

  System_Port_Config();

  HAL_UART_Receive_IT(&huart4,&Uart4_RX_Char,1);

  while(1)
  {
     char str[] = "test\r\n";
     HAL_UART_Transmit(&huart4,str,strlen(str),1000);
     HAL_Delay(500);
     LED_Pulse;
  }
}

相较于普通程序,App程序需要做以下两点修改
(1)在程序的起始阶段重定位中断向量表

  __disable_irq();//关闭全局中断,若未关闭,此时BootLoader程序仍可产生中断,会发生意想不到的错误
  SCB->VTOR = FLASH_BASE | CODE_OFFSET ;//设置中断向量的偏移,使得中断能够跳转到正常的位置
  __enable_irq();//开启全局中断

(2)在IAR中配置烧录位置
在这里插入图片描述这里将烧录位置设置为0x0800 8000
编译生成bin文件
在这里插入图片描述

3 BootLoader程序:引导App程序运行。

五、BootLoader
1 分配程序空间
通过芯片手册得知STM32L073V8T6内部flash为64K
在这里插入图片描述注意:这里的参考手册给出的是L0x3系列flash空间的最大值,需要再查具体芯片的型号规格,如果意外写入到错误的地址,程序崩溃。
在这里插入图片描述本次实验使用的是STM32L073V8T6芯片,使用者可根据芯片型号的不同自行定义flash空间。
在这里插入图片描述可以看到flash的地址空间为0x8000 0000~0x8000 FFFF(32K)。
接下来是重要的一步:定义App的烧录位置。此时一定需要确保BootLoader程序的代码不能和App程序冲突。烧录位置需要根据BootLoader程序的大小进行确定,这里仅仅为了方便起见将flash均分为两个32K空间,实际使用时需要根据BootLoader程序的大小灵活调整
在这里插入图片描述

#define FLASH_USER_START_ADDR   0x08008000           /* Start @ of user Flash area */
#define FLASH_USER_END_ADDR     0x0800FFFF   /* End @ of user Flash area */

初始化

	HAL_Init();
	//开时钟
	System_HSIClock_Config();
	//开串口
	MX_USART4_UART_Init();//这里使用USART4

串口中断回调函数

uint8_t   Uart4_RX_Char;//接收字节缓存
__no_init u8 USART_RX_BUF[10240]@0X20002000;//将接收缓存地址指定为片内SRAM(20K),如果需要从SRAM启动则跳转到该位置即可(注意SRAM起始地址为0x2000 0000,同样需要设置偏移地址以使得代码不冲突)

u16 USART_RX_STA=0;       	//接收状态标记
u32 USART_RX_CNT=0;			//接收的字节数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  if(huart->Instance==USART4)//如果是串口1
  {
    USART_RX_CNT++;//保存总共接收了多少个字节
	USART_RX_BUF[USART_RX_STA]=Uart4_RX_Char ;
	USART_RX_STA++;//缓冲区当前位置
	if(USART_RX_STA>(USART_REC_LEN-1))
	USART_RX_STA=0;//接收数据错误,重新开始接收
	HAL_UART_Receive_IT(&huart4,&Uart4_RX_Char,1);
  }
}

从SRAM将代码复制到片内flash

void Write_Flash(uint32_t address, uint8_t *pData,uint32_t length)
{
  uint32_t Address = 0, PAGEError = 0;
  uint32_t* ptr32;
  Address = address;

  EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
  EraseInitStruct.PageAddress = FLASH_USER_START_ADDR;
  EraseInitStruct.NbPages     = ((FLASH_USER_END_ADDR - FLASH_USER_START_ADDR) / FLASH_PAGE_SIZE);


  HAL_FLASH_Unlock();


  if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK)
  {
    while (1)
    {
    }
  }
  ptr32 = (uint32_t*)pData;
  while (Address < address +length)
  {
    data32 = (uint32_t)*ptr32;
    if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Address, data32) == HAL_OK)
    {
      Address = Address + 4;
      ptr32++;
    }
    else
    {
      while (1)
      {
      }
    }
  }
  HAL_FLASH_Lock();
}

这里注意写flash是以u32类型写入的(FLASH_TYPEPROGRAM_WORD),即4个字节,需要指针转换操作(data32 = (uint32_t)*ptr32;),每写一次地址+4(Address = Address + 4;),由于ptr32已经是u32指针,+1即可(ptr32++;)。

程序跳转

typedef  void (*iapfun)(void);				//定义一个函数类型的参数.
void iap_load_app(u32 appxaddr)
{
  if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000)//检查栈顶地址是否合法.
  {
    jump2app=(iapfun)*(vu32*)(appxaddr+4);		//用户代码区第二个字为程序开始地址(复位地址)				
    __set_MSP(*(__IO uint32_t*) appxaddr);		//初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
    jump2app();									//跳转到APP.
  }
}

在这里插入图片描述在这里插入图片描述
根据<<Cortex-M0权威指南>>,修改栈顶和跳转函数入口地址

主函数

#define KEY0            HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)
#define KEY0_PRES 	1

void Write_Flash(uint32_t address, uint8_t *pData,uint32_t length);

u8 key;

u8 KEY_Scan(u8 mode)//按键检测函数
{
    static u8 key_up=1;     //按键松开标志
    if(mode==1)
      key_up=1;    //支持连按
    if(key_up&&(KEY0==0))
    {
        HAL_Delay(1);
        key_up=0;
        if(KEY0==0)
          return 1;
    }
    else
      key_up=1;
    return 0;   //无按键按下
}

int main(void)
{
  HAL_Init();
  //开时钟
  System_HSIClock_Config();
  //开串口
  System_USART4_Init();

  USART_SendString(&huart4,"Warship STM32\r\n",strlen("Warship STM32\r\n"));
  USART_SendString(&huart4,"IAP TEST\r\n",strlen("IAP TES\r\nT"));

  while(1)
  {
    key=KEY_Scan(0);

    if(key==KEY0_PRES)//按键按下后执行跳转
    {
      USART_SendString(&huart4,"开始执行用户代码!!\r\n",strlen("开始执行用户代码!!\r\n"));
      Write_Flash(FLASH_APP1_ADDR,USART_RX_BUF,USART_RX_CNT);
      iap_load_app(FLASH_APP1_ADDR);//SRAM地址
    }
  }
}

工作流程
1 将BootLoader程序烧录至单片机中
2 上电启动
3 使用串口工具向单片机发送App程序的bin文件
4 按下按键,程序跳转到App程序中执行

关键点
1 根据芯片手册、App文件大小、BootLoader文件大小计算计算各个部分在flash、SRAM中占用的空间
2 使用串口下载App的bin文件至SRAM区域
3 将SRAM中的文件搬运至片内flash中
4 跳转到App的flash中运行

总结
本程序只是实现了最简单的程序下载、烧录、跳转,用户可根据自身需求做出修改,其他的附加功能如擦除、校验、选择启动方式、下载位置等功能待完善。

参考
正点原子IAP实验程序
HAL库官方例程
《Cortex-M0权威指南》
《STM32L0x3参考手册》
https://www.cnblogs.com/wanghuaijun/p/7810182.html

附件
正点原子串口IAP例程
HAL库官方例程
串口助手

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-08-07 12:15:04  更:2021-08-07 12:17:32 
 
开发: 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年12日历 -2024/12/28 2:43:20-

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