单片机FLASH下载算法的制作

本文详细介绍了在STM32F407开发板上使用MDK下载工具、JLINK和W25Q128Flash进行固件下载的过程,涉及下载算法的工作原理、FLM文件制作步骤,以及如何配置下载算法工程以适应不同Flash设备。
摘要由CSDN通过智能技术生成

环境

硬件使用正点原子STM32F407探索者V2开发板
编程环境使用MDK
下载工具使用JLINK
FLASH芯片使用W25Q128

什么是下载算法

单片机FLASH的下载算法是一个FLM文件,FLM通过编译链接得到,其内部包含一系列对FLASH的操作,包括初始化、擦除、写、读、校验等等操作。

单片机固件下载流程

想要制作下载算法,先要了解下载算法的工作原理。我们下载一个程序的流程大概是这样的:下载工具(比如jlink)先读取FLM文件,然后JLINK提取FLM文件的信息,将其传输到单片机的内部SRAM,下载算法在开始SRAM中运行,由于下载算法包含了一系列对FLASH的操作,那么下载工具通过下发初始化、擦除、写入、校验等指令给单片机,单片机去执行这些指令操作,实现对单片机FLASH的下载。

下载算法FLM文件的制作步骤

首先需要准备一份FLASH的驱动代码,能实现初始化、擦除,读,写等功能。

  1. 从MDK安装目录下拷贝一份下载算法工程,路径:MDK\ARM\PACK\ARM\CMSIS\5.4.0\Device_Template_Flash,使用的MDK版本不一样路径可能不一样。此时我们得到了一份空的下载算法工程。
  2. 取消工程的只读属性。
  3. 给工程添加分组,将Flash驱动代码和用到的库函数添加到对应的分组,和普通工程一样,根据模块添加即可。在这里插入图片描述
  4. 添加头文件路径,把头文件的路径都包含进来。
  5. 给C/C++选项卡添加宏STM32F40_41xxx,USE_STDPERIPH_DRIVER。
  6. Device选项卡选择单片机型号。Target选项卡勾选微库。
  7. 在FlashDev.c文件中根据实际Flash属性修改FlashDevice结构体变量。
  8. 将target选项卡中的输出文件名字改成FlashDevice结构体Device Name成员中的设备名字,这一步不是必须的,只是为了输出的FLM文件名称和设备名称一致。
  9. 在FlashPrg.c文件中根据模板添加Flash操作的相关代码。
  10. 编译得到一个FLM文件。

其实上边看似繁琐,实则只有修改FlashDevice结构体变量和修改FlashPrg.c文件是我们新接触的,其它步骤在平时单片机编程中已经再熟悉不过了。接下来我们重点分析这两点。

修改FlashDevice结构体变量的值

struct FlashDevice const FlashDevice  =  {
   FLASH_DRV_VERS,             // Driver Version, do not modify!
   "W25Q128_16M_FLM",   // Device Name 
   EXTSPI,                     // Device Type
   FLASH_BASE_ADDR,            // Device Start Address
   0x01000000,                 // Device Size in Bytes (256kB)  2M
   4096,                       // Programming Page Size 
   0,                          // Reserved, must be 0
   0xFF,                       // Initial Content of Erased Memory
   3000,                       // Program Page Timeout 3000 mSec
   3000,                       // Erase Sector Timeout 3000 mSec

// Specify Size and Address of Sectors
   0x001000, 0x000000,         // Sector Size  8kB (8 Sectors)
   SECTOR_END
};

其实每一个成员的作用注释已经解释的很清楚了,注意这里把页编程大小改成了4096个字节,不是W25Q128指定的256个字节,这不是必须要改的,修改成4096只是为了提高下载效率。我实测把4096改成8,下载速度非常明显的变慢。
第四个实参使用了一个宏FLASH_BASE_ADDR来初始化的,我这里对FLASH_BASE_ADDR定义的是0x00000000,就以SPI FLASH为例,FLASH的存储空间是从0开始的,为什么我没有固定写0而是写了一个宏定义呢?这在我们验证下载算法的时候介绍。
器件大小、扇区大小、扇区擦除超时时间、页编程超时时间些都根据实际FLASH芯片参数填写即可。

添加FLASH接口代码到FlashPrg.c文件

在FlashPrg.c文件中有InitUnInitEraseChipEraseSectorProgramPageVerify这些函数,每个函数的功能一目了然。函数实现如下:

int Init (unsigned long adr, unsigned long clk, unsigned long fnc) {
	SystemInit();//系统初始化
	W25QXX_Init();//初始化W25QXX芯片
  return (0);                                  // Finished without Errors
}
int UnInit (unsigned long fnc) {
  return (0);                                  // Finished without Errors
}
int EraseChip (void) {
	for(int i=0;i<4096;i++)//我用的是W25Q128
	{
		W25QXX_Erase_Sector(i);//注意这里参数是扇区的编号
	}
  return (0);                                  // Finished without Errors
}
int EraseSector (unsigned long adr) {

	uint32_t sector = 0;//扇区编号
	adr -= FLASH_BASE_ADDR; 
	sector = adr /4096;//扇区的大小是4096 计算出了扇区的编号
	W25QXX_Erase_Sector(sector);
  return (0);                                  // Finished without Errors
}
int ProgramPage (unsigned long adr, unsigned long sz, unsigned char *buf) {
	adr -= FLASH_BASE_ADDR; 
	W25QXX_Write_NoCheck(buf,adr,sz);
  return (0);                                  // Finished without Errors
}
uint8_t read_buf[4096];
unsigned long Verify (unsigned long adr, unsigned long sz, unsigned char *buf) {
	unsigned long remain = sz;	//剩余的字节数
	unsigned long current_add = 0;//当前的地址
	unsigned int index = 0;//用于buf的索引
	current_add = adr - FLASH_BASE_ADDR;
	
	while(remain >= 4096)
	{
		W25QXX_Read(read_buf,current_add,4096);
		for(int i=0;i<4096;i++)
		{
			if(read_buf[i] != buf[index+i])
				return adr+index+i;
		}
		current_add += 4096;
		remain -= 4096;
		index += 4096;
	}
	W25QXX_Read(read_buf,current_add,remain);
	for(int i=0;i<remain;i++)
	{
		if(read_buf[i] != buf[index+i])
			return adr+index+i;
	}
	return (adr+sz);                      // 校验成功
}

编译我们就能得到一个.FLM文件。

验证测试下载算法

这里我们只验证下载算法的功能,测试是否能正常下载,至于下载进去以后如何运行代码,这里不讨论,留在下一章介绍,因为涉及到链接脚本、拷贝、跳转、等等操作。
把该文件放在\MDK\ARM\Flash路径下,随便打开一个工程,添加下载算法在这里插入图片描述
编译下载,发现报错,如下图:
在这里插入图片描述
报错原因是下载算法没有找到08000000H这个地址,我这里使用的是默认的链接脚本:

LR_IROM1 0x08000000 0x00100000  {    ; load region size_region
  ER_IROM1 0x08000000 0x00100000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
   .ANY (+XO)
  }
  RW_IRAM1 0x20000000 0x00020000  {  ; RW data
   .ANY (+RW +ZI)
  }
}

下载算法文件里定义的FLASH起始地址是0x00000000,大小是0x01000000,那么下载算法的空间就是0x00000000~0x00FFFFFF。这里加载地址是0x08000000,就是要往0x08000000开始的地址写入数据。这样一来,很显然下载算法判断出了非法地址就报错了。
既然这个加载地址报错,那就把加载地址改成0x00000000,如下:

LR_IROM1 0x00000000 0x00100000  {    ; load region size_region
  ER_IROM1 0x0800000 0x00100000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
   .ANY (+XO)
  }
  RW_IRAM1 0x20000000 0x00020000  {  ; RW data
   .ANY (+RW +ZI)
  }
}

这总合法了吧,但遗憾的是编译报错,报错的原因是程序里调用了__main函数,__main函数中不能被链接到非启动区域,也就是加载地址和链接地址不一样。这里不讨论报错的原因和应对措施。其实有很多种解决方法。我暂时将链接地址也改成0x00000000如下图:

LR_IROM1 0x00000000 0x00100000  {    ; load region size_region
  ER_IROM1 0x0000000 0x00100000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
   .ANY (+XO)
  }
  RW_IRAM1 0x20000000 0x00020000  {  ; RW data
   .ANY (+RW +ZI)
  }
}

编译下载,下载成功。
在这里插入图片描述
下载成功了,我用一个SPI FLASH demo程序把FLASH0地址开始的数据读出来,打印出来:
在这里插入图片描述
在把我们烧写进去的固件对应的bin文件打开,对比一下。
在这里插入图片描述
可以看到是完全一样的。
证明制作的下载算法是没问题的。FLASH中存储的代码如何执行下一篇文章介绍。

补充

需要下载算法工程源码的请发私信。

  • 5
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Keil5是一款ST公司推出的嵌入式开发环境,适用于开发STM32系列单片机的软件。STM32标准库是ST公司提供的一套软件库,其中包含了许多关于STM32单片机的驱动程序和示例代码。 外部SPI Flash是一种外部存储器芯片,可以通过SPI总线与STM32单片机进行通信,实现数据的读写功能。要在Keil5中进行外部SPI Flash下载算法制作,首先需要了解SPI总线的通信协议以及外部Flash的规格和接口。 在Keil5中,可以通过编写C语言代码的方式实现外部SPI Flash下载算法。首先,需要定义与SPI Flash通信相关的寄存器地址、命令等参数。然后,可以使用SPI总线的驱动函数来初始化SPI接口,并按照SPI Flash的通信协议进行数据的读写操作。 具体而言,可以按照以下步骤进行外部SPI Flash下载算法制作: 1. 定义SPI Flash的相关参数,如芯片选择引脚、SPI总线的时钟速度等。 2. 初始化SPI总线,包括设置IO口模式、配置SPI时钟等。 3. 配置SPI Flash的命令、地址和数据长度。 4. 发送写使能命令,允许对SPI Flash进行写入操作。 5. 发送写命令和地址,将数据写入SPI Flash。 6. 发送读命令和地址,从SPI Flash读取数据。 7. 关闭SPI总线。 通过以上步骤,可以实现对外部SPI Flash下载算法制作。然后,可以将制作好的下载算法加入Keil5的工程中,通过编译和下载程序到STM32单片机上,从而实现外部SPI Flash的数据读写功能。这样,可以充分利用外部存储器扩展STM32单片机的存储容量,提高系统的性能和灵活性。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值