如何自己实现J-Link的Flash烧录算法?

浏览:2447来源:本站时间:2021-10-14

Flash loader的基本原理

Flash是目前最主要的非易失性存储器,众多的MCU内部都集成了Flash存储器。但是Flash无法直接写入,任何的Flash写操作都必须是在Flash为空或者已经擦除的单元内进行。

Flash的擦除一般是以块为单位进行,而且不同MCU内部Flash以及串行Flash块的大小是不一样的,这就导致了每个设备的Flash写操作可能并不相同。Flashloader就是调试工具(IDE和硬件调试器)为了解决Flash的编程问题而采用的一种方法。Flashloader实际上是运行在MCU的RAM中的一段程序,调试工具先将Flashloader下载到RAM,再通过控制PC来执行Flashloader中的函数,完成对Flash的擦除和写入。


Open Flashloader

对于主流的MCU芯片,通常J-Link都支持直接通过J-Link进行代码的烧录。但是,对于外扩Flash,例如MCU外接了SPI Flash存储器,用户可能需要自己添加J-Link的支持,对其进行烧录。

默认情况J-Link DLL有一个内建数据库,记录了已支持的芯片型号,并可以通过一个名为“JlinkDevice.xml”的xml文件来扩展支持。实现J-Link的Flash烧录算法有两项工作要做。按照设备Flash类型修改JlinkDevice文件和修改Open Flashloader的源码。

下面先来说一说JlinkDevice.xml文件的基本格式。

扩展已存在的设备

如果是J-Link已经支持的芯片,只是要添加一个新的Flash bank信息。用文本编辑器打开JlinkDevice.xml文件,添加如下信息:

图片

标签的Name属性必须与内建数据库中的已存在的设备命名完全一致;BaseAddr是要增加的Flash的基地址;其他属性参见下面的新增设备。如果有多个Flash bank要扩展,只需要重复标签。

新增一个设备

新增一个J-Link还未支持新的芯片,用文本编辑器打开JlinkDevice.xml文件,添加如下信息:

图片

新增设备时,Vendor、Name和Core是要求强制填写的。如果还增加了FlashBankInfo,则WorkRAMAddr、WorkRAMSize也是强制要填写的。

其中是<Database>顶级标签,一个xml文件中只能存在一个;标签用于描述一个新的设备,没有属性说明,在xml文件里面可以存在多个。

标签用于添加设备的基本信息,其属性值如下。

Vendor:指定设备供应商名称的字符串,强制属性,例如Vendor=”ST”。

Name:设备名,强制属性,例如Name=”STM32F407IE”。

WorkRAMAddr:指定J-Link在Flash编程等过程中可以使用的RAM区域地址的十六进制值。不应该被设备上的任何DMA使用。

WorkRAMSize:指定J-Link在Flash编程等过程中可以使用的RAM区域大小的十六进制值。如果新设备未添加Flash Bank,则该属性为可选。

Core:指定设备的内核。当新增设备时,此属性为必选属性,例如Core= “ JLINK_CORE_CORTEX_M0 “。J-Link完整Core属性值请查看J-Link用户手册中的Attribute values - Core。

标签用于指定设备的Flash Bank。使得IDE、J-Link Commander等软件可以通过J-Link DLL的Flash下载功能对设备的Flash编程,其属性值如下。

Name:指定Flash Bank的字符名称,仅为了可视化的用途,不是必须属性。例如Name=”SPI FLASH”。

BaseAddr:指定Flash Bank起始地址的十六进制值。J-Link DLL使用BaseAddr和MaxSize来决定调试器执行的哪些内存写操作需要通过Flashloader。

MaxSize:以十六进制值指定Flash的大小,单位是字节。

Loader:指定Flashloader的ELF文件路径的字符串。路径可以是相对的或绝对的。

LoadType:指定Flashloader的类型。例如LoaderType = "FLASH_ALGO_TYPE_OPEN ",说明使用的算法是Open Flashloader算法。

AlwaysPresent:指定Flash是否始终存在,例如MCU片内的Flash。

创建一个Flashloader的步骤

下面介绍如何修改Flashloader的源码,创建一个自己的Flashloader。Segger官方有给出了Open Flash Loader的模板工程:(点击最下方“阅读原文”)

此模板是基于Cortex-M的,IDE使用的是SEGGER的Embedded Studio。下载模板工程文件后解压,并下载安装Embedded Studio for ARM,然后双击解压后的Flashloader_V5.34.emProject文件, Embedded Studio会自动打开工程。

图片图片

实践操作

下面将以STM32F103ZE芯片和W25Q128BV SPI Flash为例,修改Open Flashloader,让J-Link能直接通过STM32F103ZE烧录与之通过SPI连接的W25Q128BV。

W25Q128是华邦公司推出的一款SPI接口的NOR Flash芯片,16M字节大小,每页256字节,每扇区4k字节。擦除方式分为按单个扇区擦除,8个扇区,16个扇区或整个芯片擦除。

1、修改FlashDev.c

FlashDev.c比较简单,只定义了一个名为FlashDevice设备的结构体。但要注意,不要修改FlashDevice结构体的section属性。在这里我们只需要修改Flash设备名,Flash的基地址,Flash的总大小,Flash的页大小(page),Flash擦除后的值,以及Flash的扇区信息。

图片

Flash的扇区信息是一个结构体数组,包含两个成员,扇区大小的字节数和扇区的起始地址。但这里有一个需要注意的地方,结构体数组的个数与不同大小扇区的数量有关。有一些MCU内部的Flash有多个块,并且块的大小还不一样,例如一款MCU内部Flash分成4个16 KB的块,1个 64 KB块,1 个128 KB块,所以不同大小的扇区数就是3。

图片

扇区信息结构体最后一个成员必须是“0xFFFFFFFF, 0xFFFFFFFF”,指示Flash扇区的结束。因为W25Q128BV的扇区大小都是4KB,所以扇区信息结构体元素个数为2(包括用于指示扇区结束的结构)。

图片

2、修改FlashPrg.c

这个文件是Flashloader的核心,包含了Flash操作的各种函数,其中必须要实现的函数有下面的4个:

Init(),UnInit(),EraseSector(),ProgramPage()

Init()用于实现必要的硬件初始化,包括Flash的配置,解锁操作等。UnInit()是初始化反操作,例如实现Flash的上锁,防止误操作。W25Q128写和擦除操作是自动上锁的,也没其他的必要操作,所以UnInit()只返回0表示操作成功即可。EraseSector()和ProgramPage()实现单个扇区的擦除和单个页的写入操作。这4个函数都返回0表示操作成功,返回1表示失败。

此外有几个可选实现的函数,包括多扇区擦除,多页写入,全片擦除,擦除状态检测和校验等。

(1)、SEGGER_OPEN_Read()

这是一个针对非地址映射的Flash读才需要的函数,比如W25Q128这样的SPI Flash,读操作是通过SPI发生读指令和地址,然后通过接收读出的数据并存储到缓存。

图片

(2)、SEGGER_OPEN_Program

如果每次只写一个页,这样效率势必会比较低(PC端的工具软件通过USB向J-Link传输命令和数据,并设置PC调用ProgramPage()写一个页),如果一次操作写多个页效率自然提高了。

图片

这个函数不需要修改,但这个函数有使用了两个宏定义,需要在文件中修改这两个宏定义:

#define PAGE_SIZE_SHIFT              (8)

#define SECTOR_SIZE_SHIFT           (12)

这是根据Flash的页和扇区的大小来设定的,含义是2的幂,比如这里的设置页的大小为2^ 8 = 256字节,扇区大小为2^12=4096字节。

(3)、SEGGER_OPEN_Erase

同样,当要编程的数据超过一个扇区的时候,如果一次能擦除多个扇区可以提升效率。特别对W25Q128来说,擦除的速度是很慢的,如果要擦除64KB的时候,按照64KB块擦除的时间要小于按照32KB块擦除的时间,远小于按照4K扇区擦除的时间

(4)、BlankCheck()是为了检测Flash是否已经擦除。Flash擦除操作比较耗时,如果要编程的地址范围都已经擦除了,就直接写入,这样可以加快Flash编程速度;EraseChip()是实现全片擦除功能;Verify()函数的用途是Flash编程完成之后,通过按字节回读,验证写入后的数据是否正确。这也是非地址映射的Flash需要实现的函数。

3、修改MemoryMap.xml

MemoryMap是Embedded Studio的内存映射配置文件,用于指定MCU的RAM和Flash的基地址和大小。

图片

4、调试和构建Flashloader

调试是为了验证FlashPrg.c中这些实现的函数是否能够如期工作,在main.c中将调试的宏定义开关打开:

#define DEBUG  1

#define SUPPORT_BLANK_CHECK  1

将工程配置切换到Debug,然后构建代码并下载到硬件中执行。如果测试通过,再将配置切换到Release构建Flashloader。

5、修改JlinkDevices.xml

我是直接在J-Link驱动目录下复制一份出来进行修改,并用修改后的文件进行替换。

图片

按照前面的介绍,这里给STM32F103ZE增加了一个扩展,扩展了一个名为“SPI Flash”的Flash bank,基地址设置为0x09000000,大小为0x01000000(16MB)。

图片

并将Flashloader的执行文件设置为相对于JlinkDevices.xml的Devices\ST\STM32F1路径,将生成的Flashloader执行文件复制到该目录中。

图片

至此,修改Flashloader的工作全部完成了。

6、使用J-Link进行测试

使用Embedded Studio建立一个工程进行测试,在链接脚本中将Flash的地址改成指定的外扩Flash地址,构建代码。

图片

然后使用IDE的下载按钮,将代码下载到W25Q128:

图片

烧录功能正常。

使用J-Link Commander软件的下载功能,将一个大约1MB的图片bin文件,烧录到W25Q128:

图片

从测试结果来看,实现的Flashloader的正常工作的。

总结

J-Link是嵌入式开发中广泛使用的硬件调试器,如果用户掌握修改Flashloader的方法,可以让工具变得更加得心应手,不论硬件上外扩了何种Flash,都可以使J-Link直接实现代码和数据的烧录功能。如果需要了解更多有关J-Link或者Open Flashloader有关信息,可以参考J-Link用户手册以及SEGGER官网。

京ICP备:京ICP备05011254号-1 版权归北京麦克泰软件技术有限公司所有
北京麦克泰软件技术有限公司