Open Flash Loader - 简单搞定JLINK Ozone flash下载
JLINK和Ozone基本算是MacOS上嵌入式开发的唯一选择了,虽然基于CMSIS-DAP的pyocd在MacOS上跑得也挺欢,但是这个对于新产品支持并不友好,并且需要额外的芯片和一整套软件的移植,对于我来说还是有些复杂。因此我还是选择Segger公司的一套工具好了。
因为嵌入式芯片种类繁多,对于我这样总是研究新产品的人来说,等官方支持我们的产品明显是不现实的,所以我需要有一个可以比较自由定制的调试工具链,以前我都是通过Ozone的方式进行调试,程序基本也都是运行在RAM上面,但是有些应用对于RAM的需求很大,我很难在新产品上跑比较大型的应用,如果通过Bootloader下载程序,每次都要条线也是繁琐的要命。所以这时候有个直接Ozone能够支持的flashloader就非常完美了,正是因为基于这种需求我找到了Segger官方支持的一个Open Flash Loader
,这个flashloader可以支持用户自己定义新产品的flash下载,具体实现可以参考官方wiki.
Flash Loader的基本原理
Flash Loader是调试工具用来将用户的应用加载到芯片内部Flash的一个程序,我们知道芯片内部的Flash是无法直接支持写操作的,所以就要借助Flash loader完成这一操作。Flash Loader实际上是运行在芯片RAM的一个Flash操作代码,调试工具本身是支持RAM的直接访问的,所以可以直接Halt CPU然后通过写RAM的方式将程序下载到RAM,下载完成后Debugger可以通过控制程序PC的位置实现不同的函数调用,从而完成Flash擦除和写入的操作,比如在需要下载一段程序的时候,Debugger可以先调用擦除Sector的函数将Flash进行擦除,然后将待下载的程序分片写入RAM中,然后调用Flash loader的写入函数将数据从RAM写入到Flash中,从而完成下载操作。
从上面的描述中,我们可以看出,如果需要让Debugger和Flash Loader协同操作,Flash Loader需要有一定的格式,并且要实现必要的函数,也就是遵循一定的框架。今天我们要讲的Open Flash Loader
实际上就是Segger家Flash loader遵循的一套框架。
Open Flash Loader
Segger官方给出了一个Open Flash Loader
的模板工程,工程用到的开发环境也是Segger公司的一套IDE,真是不遗余力的推广呀,好在编译个Flash Loader还是免费的,所以还算良心。工程模板可以通过https://wiki.segger.com/images/4/4e/OpenFlashloader_CortexM_Template_EmbeddedStudio.zip 进行下载。
Open Flash Loader移植
这个工程还是非常简单的,我们移植的时候基本就是按照我们的Flash参数修改相应的参数,然后编写擦除和写入的两个函数就好了。
首先我们看一下设备定义的FlashDev.c
,这个文件主要就是一个结构体:
struct FlashDevice const FlashDevice __attribute__ ((section ("DevDscr"))) = {
ALGO_VERSION, // Algo version
"Internal flash", // Flash device name
ONCHIP, // Flash device type
0x00000000, // Flash base address
0x00080000, // Total flash device size in Bytes (256 KB)
16, // Page Size (number of bytes that will be passed to ProgramPage(). May be multiple of min alignment in order to reduce overhead for calling ProgramPage multiple times
0, // Reserved, should be 0
0xFF, // Flash erased value
100, // Program page timeout in ms
6000, // Erase sector timeout in ms
//
// Flash sector layout definition
//
0x00002000, 0x00000000, // 16 * 8 KB = 128 KB
0xFFFFFFFF, 0xFFFFFFFF // Indicates the end of the flash sector layout. Must be present.
};
注意DevDscr
的section属性很重要,别乱改,这里我们只需要修改Flash大小, page大小和最后的Flash结构。
另外一个需要修改的就是FlashPrg.c
这个文件包含Flash操作的各种函数,这里也就是实现两个函数就好了,首先我们看看基础的一些宏定义:
#define PAGE_SIZE_SHIFT (4) // The smallest program unit (one page) is 8 byte in size
#define SECTOR_SIZE_SHIFT (13) // 4096 sector size
//
// Some flash types require a native verify function as the memory is not memory mapped available (e.g. eMMC flashes).
// If the verify function is implemented in the algorithm, it will be used by the J-Link DLL during compare / verify
// independent of what verify type is configured in the J-Link DLL.
// Please note, that SEGGER does not recommend to use this function if the flash can be memory mapped read
// as this may can slow-down the compare / verify step.
//
#define SUPPORT_NATIVE_VERIFY (0)
#define SUPPORT_NATIVE_READ_FUNCTION (0)
#define SUPPORT_BLANK_CHECK (0)
#define SUPPORT_ERASE_CHIP (0)
#define SUPPORT_SEGGER_OPEN_Program (1)
#define SUPPORT_SEGGER_OPEN_ERASE (1)
这个部分也是根据需要修改,后面的几个为0的support如果改成1就要实现相应的函数,这里因为我们Flash一般都支持编址形式的访问(类似NOR flash)所以一般都是不用实现的,除非你搞成类似EMMC那样块操作的形式,那么是需要实现verify,read和check的函数的。这里我们根据Page和sector大小修改相应的shift就可以了。
下面我们看看Init函数,这个函数在每次flash操作之前调用,可以进行必要的初始化,我这为了省事,直接在这里关了WDOG,严谨软件不建议关🐶哈。对应的UnInit这里我就不写了,因为里面没什么需要恢复的。
int Init(U32 Addr, U32 Freq, U32 Func) {
(void)Addr;
(void)Freq;
(void)Func;
//
// Init code
//
disable_wdog();
return 0;
}
下面就来到比较重要的擦除函数了,这个调用的时候有地址参数,直接实现就好了
int EraseSector(U32 SectorAddr) {
//
// Erase sector code
//
*(volatile U32 *)(0x40020018) = SectorAddr; // FADDR
*(volatile U32 *)(0x40020010) = 0x42; // FCMD
*(volatile U32 *)(0x40020000) = 0x80; // FSTAT
while (!(*(volatile U32 *)(0x40020000) & 0x80))
;
if ((*(volatile U32 *)(0x40020000) & 0x01))
return 1; // FAIL
_FeedWatchdog();
return 0;
}
然后就是写Flash的函数,没啥好说的,相应的Flash命令填上去就好了,这些函数可以在main里面直接Debug。
int ProgramPage(U32 DestAddr, U32 NumBytes, U8 *pSrcBuff) {
volatile U32 *pSrc;
U32 NumPages;
int r;
r = -1;
//
// RAMCode is able to program multiple pages
//
NumPages = NumBytes >> PAGE_SIZE_SHIFT;
//
// Program page-wise
//
pSrc = (U32 *)pSrcBuff;
if (NumPages) {
r = 0;
do {
_FeedWatchdog();
//
// Program one page
//
*(volatile U32 *)(0x40020018) = DestAddr;
*(volatile U32 *)(0x40020020) = pSrc[0];
*(volatile U32 *)(0x40020024) = pSrc[1];
*(volatile U32 *)(0x40020028) = pSrc[2];
*(volatile U32 *)(0x4002002c) = pSrc[3];
*(volatile U32 *)(0x40020010) = 0x24;
*(volatile U32 *)(0x40020000) = 0x80; // FSTAT
while (!(*(volatile U32 *)(0x40020000) & 0x80))
;
if ((*(volatile U32 *)(0x40020000) & 0x01))
return 1; // FAIL
pSrc += 4;
DestAddr += 4;
} while (--NumPages);
}
return r;
}
上面两个函数我们都可以在Main函数里面调用调试,并不影响FlashLoader,因为Debugger并不会调用Main函数。
搞定函数之后就可以编译(Release)得到elf文件了,这个文件就是我们Debugger需要的Flash Loader了。
向Ozone和JLINK里面添加Device
有了Flash Loader之后我们还要让调试工具知道怎么去找flash loader,当然我们还可以为我们的产品起一个响亮的名字,这个时候我们就需要到JLink或者ozone安装目录下面找一个JLinkDevices.xml
的文件了,打开文件,在文件的末尾依照格式添加device吧!比如我们搞一个:
<Device>
<ChipInfo Vendor="Wukong" Name="West" Core="JLINK_CORE_CORTEX_M0" WorkRAMAddr="0x20000000" WorkRAMSize="0x4000" />
<FlashBankInfo Name="Internal Flash" BaseAddr="0x00000000" MaxSize="0x20000" Loader="Devices/Wukong/flash_loader_west.elf" LoaderType="FLASH_ALGO_TYPE_OPEN" AlwaysPresent="1"/>
</Device>
这个里面Vendor就是企业的名称,Name是产品的名称,CORE是产品核心的名称,然后根据需要修改RAM的地址和大小,Flash Loader的路径就可以了,保存之后打开Ozone或者J-Flash Lite就可以选我们自己定义的Device了,然后debugger会根据elf文件内容自动加载Flashloader下载,非常完美的。
最后更新于 2020-06-02 09:06:45 并被添加「Flash Flashloader 自定义 新产品」标签,已有 12740 位童鞋阅读过。
本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。
你好 请问可以请教一些具体的问题么 可以请教一个联系方式么 ,不然您邮件我 [email protected]
我也在做同样的问题 想把我的设备添加到jlink里面 不太清楚细节的地方要怎么做 可以问一下么 谢谢
你好 我刚刚阅读了您的这篇文章 有一些细节想要询问一下 可以给一个联系方式么 或者直接在这里?