一、简介
当内部的Flash不够使用时可以通过拓展外部Flash来存储更多代码和数据。上章讲了W25N04的Flash驱动,这次来将如何讲如何讲代码烧录到W25N04上。
二、系统框架
首先了解一下代码是如何通过编译器烧录到硬件上的。
1、IAR将读取xx.board文件获取PCB的flash描述和每个flash对应的烧录算法(flashloader)。
2、IAR通过烧录器将烧录算法加载到MCU的RAM中。
3、IAR通过flashloader将代码烧录到对应的flash中。
(xx.board文件:描述了PCB上的flash资源和对应的.flash文件地址)
(xx.out文件:flashloader的工程输出,也就是烧录算法本体)
(xx.max文件:.mac 文件(宏文件)是一个关键的配置和脚本文件,主要用于 调试阶段的硬件初始化和自动化操作。它的核心作用是通过脚本语言(类似 C 语言)控制调试器(C-SPY)与目标硬件的交互,从而实现调试前的硬件准备、调试过程的自动化,以及烧录程序时的外设配置。)
(xx.flash:描述flash的基本参数和对应的算法文件xx.out)

三、flashloader基础工程构建
在IAR的软件安装路径下有许多写好的flashloader工程,如下图所示。我们找到对应芯片的型号复制一份就好了。

我以STM32F4XX NOR的为例,复制一份工程做当模板进行开发。

这里最重要的是要实现图中标记的文件。Framework,flash_loader.c定义的是一些被调用的Flash接口。而用户实现则放在了
FlashSTM32F10x_NOR.c中。实现用户自己的Flash驱动并适配flash_loader的接口。
四、实现Flashloader
创建一个工程添加模板中必要的文件,如下图所示。添加的Flash_Loader 等同于模板中的Framework,其他的是Flash驱动的本体和依赖文件。

1、配置链接文件
前面说了,flashloader是加载到RAM中运行的,这里我们也是将链接地址修改成RAM的地址。


2、实现Flash驱动
这里就不细说了,本章重点讲解Flashloader的内容。关于W25N04xx的驱动在这里
3、适配Flashloader对应的接口
1)FlashInit
该函数主要实现系统和Flash的初始化功,如果Debug的需要可以添加UART功能。另外需要存储函数参数中的base_of_flash,后面会有用到。代码如下,
uint32_t FlashInit(void *base_of_flash, uint32_t image_size,
uint32_t link_address, uint32_t flags,
int argc, char const *argv[])
{
sys_stm32_clock_init(360, 25, 2, 8); /* 设置时钟,180Mhz */
delay_init(180); /* 延时初始化 */
usart_init(90, 115200); /* 初始化USART */
w25n04k_init(); /* 初始化W25N04K闪存 */
base_addr = (uint32_t)base_of_flash;
printf("base addr = 0x%x\r\n", base_addr);
// main(); // init system
// w25n04k_test(); // Test W25N04K flash memory
// sfud_demo(0, sizeof(sfud_demo_test_buf), sfud_demo_test_buf);
return RESULT_OK;
}
2)FlashWrite
这里是先的是写Flash的内容,需要将参数转化成相对于Flash的绝对地址。
uint32_t FlashWrite(void *block_start,
uint32_t offset_into_block,
uint32_t count,
char const *buffer)
{
uint32_t dest = (uint32_t)block_start + offset_into_block - base_addr;
// W25QXX_Write((uint8_t *)buffer, dest, count);
printf("flash write addr:0x%x , size:%d\r\n", dest, count);
// const sfud_flash *flash = sfud_get_device(SFUD_W25Q256_DEVICE_INDEX);
// sfud_write(flash, dest, count, buffer);
w25n04k_write(dest, (uint8_t *)buffer, count);
printfArrayHex(buffer, 100);
return 0;
}
3) FlashErase
uint32_t FlashErase(void *block_start,
uint32_t block_size)
{
// W25QXX_EraseSector((uint32_t)block_start - base_addr);
// const sfud_flash *flash = sfud_get_device(SFUD_W25Q256_DEVICE_INDEX);
uint32_t addr = (uint32_t)block_start - base_addr;
printf("flash erase addr:0x%x , size:%d\r\n", addr, block_size);
// sfud_erase(flash, addr, block_size);
w25n04k_earse(addr, block_size);
return 0;
}
至此已完成了Flashloader的接口适配了
五、添加Flashloader到项目中
1、主项目中添加.board文件
这里添加外部flash的声明。
range范围是MCU中的绝对地址。后续链接文件中需要声明内容链接到改地址。
loader声明了Flashloader.flash对应的文件。
rel_offset是烧录的时候flash的偏移地址,0x90000000 - 0x90000000 = 0。
创建.board文件并放置在.eww文件(工程文件)下。
<?xml version="1.0" encoding="UTF-8"?>
<flash_board>
<pass>
<loader>$TOOLKIT_DIR$/config/flashloader/ST/FlashSTM32F427xG.flash</loader>
<range>CODE 0x8000000 0x81fffff</range>
</pass>
<pass>
<loader>$PROJ_DIR$\FlashLoader\STM32F4xx_SPI.flash</loader>
<range>CODE 0x90000000 0x91ffffff</range>
<rel_offset>-0x90000000</rel_offset>
</pass>
</flash_board>
2、主项目中添加Flashloader相关文件
将Flashloader文件输出的.out文件、.mac和.flash文件添加到工程目录下。

.mac文件使用IAR的模板中的文件。
.flash文件需要参考模板进行修改。
以下可供参考。
flash_base将被作为参数传入到前面提及的FlashInit函数中。
page参数是页大小。
block描述了flash块的数量和大小。
<?xml version="1.0" encoding="iso-8859-1"?>
<flash_device>
<exe>$PROJ_DIR$\FlashLoader\SPIFlashLoader.out</exe>
<page>2048</page>
<block>1024 0x20000</block>
<flash_base>0x00000000</flash_base>
<aggregate>1</aggregate>
</flash_device>
至此已经完成将Flashloader添加到主项目中了。
但是想要代码或数据存储在外部flash还需要修改链接脚本。
另外值得一提的是SPI驱动的Flash不支持XIP(在存储本地运行),所以需要将代码和数据加载到RAM或者MCU的ROM中。
这将会在下一期讲。
6524

被折叠的 条评论
为什么被折叠?



