本帖最后由 STM新闻官 于 2024-3-15 15:05 编辑
一、引言
在嵌入式应用系统中,越来越多的应用需要扩展外部 Flash 来满足存储需求,例如 GUI 的应用,需要将视频、图片、字体等素材存储在外部 Flash。对于 SPI、FMC、 FSMC、QSPI、OCTOSPI、SDMMC 等接口存储器,需要一个 Flash Loader,把资源下载到外部 Flash。在 STM32CubeProgrammer 安装目录的“bin/ExternalLoader”目录下,ST 提供了官方开发板对应的 Flash Loader,也就是 stldr 文件。但官方提供的 Flash Loader 数量有限,不能完全满足用户需求,需要用户根据自己的 MCU 型号、Flash 类型,开发自己的 Flash Loader。
ST 的 X-Cube-DISPLAY 是 STM32Cube 扩展包,3.0 版本提供了 SPI/QSPI 接口的 MX25L6433F 的 Flash Loader 的源码工程,用户可以基于此进行自己 Flash Loader 的开发。本文档就是根据 X-CUBE-DISPLAY 3.0 所提供的 Flash Loader 工程,以 NUCLEO-STM32G474+GFX01M2 开发板为例,介绍了 STM32CubeIDE、KEIL、IAR 等不同编译器利用 X-CUBE-DISPLAY 所提供的 API 来生成外部 Flash Loader 的方法。
二、Flash Loader 的开发过程
参考 ST 在 X-CUBE-DISPLAY 3.0.0 所提供的 Flash Loader 工程,外部 Flash Loader 的开发过程主要包括以下 3 步。 (1)更新 Dev_Inf.c 中的存储器芯片信息。 (2)重写 Loader_Src.c 中的相关接口函数。 (3)更改输出文件名。 项目配置好后编译整个 Flash Loader 项目,将生成一个 ELF 文件,文件的扩展名取决于所使用的编译器,Keil 的为.axf,EWARM 的为.out,STM32CubeIDE 的为.elf,通过编译后处理指令更改为 stldr 扩展名的文件,将该 stldr 文件复制到 “bin/ExternalLoader”目录下就可以被 STM32CubeProgrammer 使用了。2.1. Dev_Inf.c 介绍 此文件中定义的 StorageInfo 结构提供有关外部存储器的信息。用户在制作自己的 Flash Loader 时,需要根据 Flash 的参数来更新相关信息。 2.2. Loader_Src.c file 该文件包含了制作外部 Flash Loader 所需的接口函数,主要包含初始化,擦除,写入以及读出等操作。其中 Init,Write, SectorErase 这些函数是必需的,不能被省略。除了这些函数之外,您还可以重写 Read,Verify,MassErase 函数。
2.2.1. Init
Init 初始化连接到外部存储器的 GPIO 引脚以及初始化 IP 所用的时钟。
如果成功,则返回 1,如果失败,则返回 0。
int Init (void)
2.2.2. Write
Write 函数将在 RAM 定义的缓冲区写入到外部存储器。
如果成功,则返回 1,如果失败,则返回 0。
int Write (uint32_t Address, uint32_t Size, uint8_t* buffer)
2.2.3. SectorErase
擦除内存指定的扇区。其中起始地址等于要擦除的第一个扇区的地址,结束地址等于要擦除的结束扇区的地址。
如果成功,则返回 1,如果失败,则返回 0。
int SectorErase (uint32_t StartAddress, uint32_t EndAddress)
2.2.4. Read 功能 Read 函数将存储器指定地址的数据读取到内存中的缓冲区中。
如果成功,则返回 1,如果失败,则返回 0
int Read (uint32_t Address, uint32_t Size, uint16_t* buffer)
2.2.5. Verify
功能当选择“边编程边验证”模式时调用验证函数。此功能检查编程的内存是否与 RAM 中定义的缓冲区相对应。
2.2.6. MassErase 功能
MassErase 功能会擦除全部内存。
如果成功,则返回 1,如果失败,则返回 0。
int MassErase (void)
2.2.7. Checksum 功能
描述的所有函数在操作成功时返回 1,在失败时返回 0。
三、利用 X-Cube-Display API 生成 Flash Loader 的方法
这里参考 X-CUBE-DISPLAY\3.0.0\Projects\NUCLEO-WB55RG\Applications 目录下的 GFX01M2_FlashLoader 工程的方法,来移植一个 NUCLEO-G474+GFX01M2 的 Flash Loader,这是一个 SPI 接口的 NOR FLASH,芯片型号 MX25L6433F。
我们打开 STM32CubeMX,MCU 选择 STM32G474RET6,首先配置时钟,其次这里用到外设有 SPI,还需要对 SPI 进行配置,查看 X-NUCLEO-GFX01M2 和 NUCLEOSTM32G474 原理图,外部 Flash 用到了 SPI2,GPIO 引脚用到了 PB13, PB14, PB15, PA8。SPI2 相关配置参数如下图所示。
▲ 图1. SPI 参数配置 SPI2 外设相关参数配置结束后,点击 X-CUBE-DISPLAY 标签,为相关的 IO 接口配置对应的引脚和外设。
▲ 图2. X-CUBE-DISPLAY IO 接口配置 相关参数配置好后,点击 Project Manager,给工程重新命名,由于 Flash Loader 不需要 main 函数,选中配置的 “Do not generate main()”,这样生成的代码就不会有 main 函数。然后点击生成代码按钮生成代码。
▲ 图3. Project Manager 修改 生成的代码还需要添加 Dev_Inf.c、Loader_Src.c、Dev_Inf.h、Loader_Src.h,将这个代码添加到 Core 文件夹下的 Inc 和 Src 文件夹,为了方便不同编译器生成的代码能够自动加载这几个文件,复制.extSettings 文件到该工程文件夹,该文件会为工程新建一个 Loader 文件组,然后再重新生成代码。生成的代码用 VSCode 打开,在 main.c 函数中新增 MX_Init()函数,函数主要的功能是复位外设和初始化 GPIO。▲ 图4. 添加 MX_Init()函数
关于 Dev_Inc.c 和 Loader_Src.c 文件中的函数,这里就不再做一一说明,大家可以对照附件查看,下面主要介绍下不同编译器的工程属性配置。3.1. STM32CubeIDE 工程配置 STM32CubeIDE 的配置修改包括从工程中去除 startup_stm32g474retx.s,修改 Linker 文件,修改启动函数入口,添加后处理生成 stldr 文件。
▲ 图5. STM32CubeIDE 中将 startup_stm32g474retx.s 从工程中去除 修改 Linker 的配置,通过“Properties”打开设置页,将 Linker 文件修改为 STM32_FLASH.ld。
▲ 图6. STM32CubeIDE 修改 Linker 文件
通过 “Settings” -> “Build Steps” 配置页中,在 “Post-build steps” 处添加指令 :cmd.exe /c copy /Y "$(BUILD_ARTIFACT)" "..\MX25L6433F_GFX01M2_STM32G4.stldr",编译后生成 stldr 文件。
▲ 图7. 在 STM32CubeIDE 中添加后处理语句 当这些配置好后,重新 Build 工程,这样就会产生所需要的 Flash Loader。
与 STM32CubeIDE 配置过程类似,KEIL 的配置过程主要包括以下操作。在 Target 标签页,Arm Compiler 选择“Use default compiler version 6”,如下图所示。
▲ 图8. 更改 Arm Complier
在 startup_stm32g474xx.s 的文件属性中,去除勾选“Include in Target Build”和 “Always Build”,这样这个文件就不会被编译和包含在这个工程中。
▲ 图9. 在 KEIL 中将 startup_stm32g474retx.s 从工程中去除 在属性界面,切换到 Linker 界面,去掉“Use Memory Layout from Target Dialog”勾选,修改链接文件,将链接文件更换为 stm32_loader.sct,同时注意在 Misccontrols 添加“--paged --pagesize 0x10--diag_suppress L6305” 。
▲ 图10. KEIL 中修改链接文件 与 STM32CubeIDE 配置类似,添加后处理语句“cmd.exe /C copy /Y "!L" "..\MDK-ARM\MX25L6433F_GFX01M2_STM32G4.stldr"”。
这些配置好后,重新编译代码,会在 MDK-ARM 文件夹下生成 stldr 文件。
|