硬汉嵌入式论坛

 找回密码
 立即注册
查看: 14|回复: 0
收起左侧

[J-Link] 基于vscode与gcc的open flashload制作记录

[复制链接]

0

主题

5

回帖

5

积分

新手上路

积分
5
发表于 4 小时前 | 显示全部楼层 |阅读模式
本帖最后由 老叶子 于 2025-9-26 14:33 编辑

背景导入
需求很容易理解,制作固件时,并不是程序写完就完事了,程序运行还需要外部资源,比如字库、图片、音频数据等。这些资源通常是只读的,而且很大,所以它们一个合适的归宿就是spiflash。
我想了三种方法烧录这些资源
  • 先烧录程序,再通过ymodem、http之类的协议将资源下载到spiflash中
  • 通过jflash将程序与资源一起烧录到板子内
  • 通过JFlashSPI将资源烧录到板子上的spiflash中
JFlashSPI也是segger提供的一个小工具,将板子上spi引脚与jlink连接后,可以直接识别、烧录spiflash
方法2最好,一步到位。方法2也是最麻烦的,需要为板子写下载算法(flashload)程序
下载算法的知识有点冷门,但也有教程,搜了搜发现内容与安富莱的教程类似,所以略过中间商,直接看安富莱的就行《STM32H7 的 SPI 总线应用之 SPI Flash的 MDK 下载算法制作》、《STM32H7 的 SPI 总线应用之 SPI Flash的STM32CubeProg下载算法制作》。通过本文标题也知道,这两篇文章都与我的需求不太相符,但众多教程里又说了,MDK的下载算法与segger的下载算法通用,这句话确实没错,甚至segger也承认了
Snipaste_2025-09-26_13-54-47.jpg
上图出自于https://kb.segger.com/J-Link_Device_Support_Kit。解释几个名词:
device support kit:segger提供的数据烧录方案(付费),segger flashload是其中的一部分
segger flashload:segger最新推出的下载算法,替代open flashload
open flashload(OFL):segger以前的下载算法,但segger为了推广sfl,将ofl的资料全删了
cmsis loaders:arm推出的下载算法,即MDK支持的下载算法。
经过测试,直接将MDK中的FLM文件应用于jflash是可以的,但将安富莱例程应用于jflash时,又报错了,将安富莱例程应用于MDK时,又可以使用,那么,肯定有地方出了差错。
将MDK下载算法应用于jflash的方法请参考以下几个链接:
以7.62版本为界,jflash添加下载算法的方式有了改变。7.62版本后C:\Users\<USER>\AppData\Roaming\SEGGER目录下默认没有JLinkDevices目录,用户新建一个即可。除JLinkDevices目录外,JLinkDevices目录内文件夹、xml、下载文件的命名没有要求。关于xml文件的语法,除上述链接外,还可以参考上述的segger DSK文档
OFL制作

最后解决问题是依靠这篇文章。
问题的根源在于MDK要求下载算法是位置无关的,即安富莱教程中“84.3.7第 7 步, 保证生成的算法文件中 RO 和 RW 段的独立性,即与地址无关”章节。当代码地址无关后,生成的FLM文件中PrgData 域中.bss段的执行地址域DSCR域中.constdata的执行地址(exec addr)重合,即下图中红框内容。我猜测,MDK会处理地址冲突,然后将下载算法传递给jlink,但通过jflash传递给jlink的下载算法则不会处理这种地址冲突
Snipaste_2025-09-26_14-00-42.jpg

虽然segger删除了OFL的资料,但互联网是有记忆的,从我找到的一些OFL工程来看,并没有出现“-fPIC”编译选项,也印证了OFL代码不需要地址无关
OFL中模板有两个库文件SEGGER_OFL_Lib_CortexM_LE.a、SEGGER_OFL_Lib_CortexM_BE.a。分别供SEGGER_OPEN_CalcCRC函数、SEGGER_OPEN_Start函数使用。具体的使用方法看模板就清楚了。虽然segger说SEGGER_OPEN_CalcCRC比Verify校验快,但我感觉还不如Verify。SEGGER_OPEN_Start开启flash trubo模式,但我不知道这个模式的功能,希望有大神补充一下
在此基础上,我也制作了一个工程,供大家参考。f407_openflashload: 基于vscode与gcc的open flashload制作记录
MCU:STM32F407VET6
norFLash:W25Q64
外设:usart1、spi2
工程基于STM32CubeMx生成,CMAKE_BUILD_TYPE为Debug时,生成测试程序,可直接烧录在内部flash上运行。CMAKE_BUILD_TYPE为Release时,生成下载算法
ofl/gcc-arm-none-eabi.cmake为Release时的编译选项,除了下述修改外,与cubemx生成的gcc-arm-none-eabi.cmake相同。
[C] 纯文本查看 复制代码
# 模板内也用的软浮点
set(TARGET_FLAGS "-mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=soft ")
# 更改链接脚本
set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -T ${CMAKE_SOURCE_DIR}/ofl/stm32f4xx_flashloader.ld")

工程根目录下的CMakePresets.json若存在toolchainFile属性,一定要删除,否则Realse时不会使用ofl/gcc-arm-none-eabi.cmake
"toolchainFile": "${sourceDir}/cmake/gcc-arm-none-eabi.cmake"
ofl/stm32cubemx/CMakeLists.txt在cmake/stm32cubemx/CMakeLists.txt的基础上进行了精简,因为代码直接在RAM上执行,不需要启动文件。代码全部使用轮询操作,也不需要中断函数
[C] 纯文本查看 复制代码
# 新增两个宏定义,分别表示spiflash在工程中的逻辑起始地址与扇区尺寸,会传递给FlashPrg.c
target_compile_definitions(stm32cubemx INTERFACE 
	USE_HAL_DRIVER 
	STM32F407xx
    $<$<CONFIG:Debug>:DEBUG>
    EXFLASH_BASE_ADDR=0xC0000000
    EXFLASH_SECTORS_SIZE=4096
)
链接文件本来是用于STM32H743IITx,但修改为STM32F407VE的内存映射一样使用。注意,OFL不能把RAM全占用,毕竟RAM中还有jflash的下载缓存
[C] 纯文本查看 复制代码
MEMORY
{
  RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 64K
}

如何使用
代码中所有的字符串、字库、图片、音频,归根结底,都是数组。将外部资源转化为数组,再融入到程序中,就可以通过jflash烧录了。最终实现的效果与安富莱教程中《STM32H7 的内部 Flash 和 SPI Flash 同时使用 MDK 一键下载》相同
作者给出了一个测试例子,基于rt-thread env环境,通过gcc编译,没有这个环境也没关系,通过修改链接脚本,都可实现相同效果。注意,请预留4G空间为测试工程生成的bin文件(最后并不使用这个bin文件)
在链接脚本中开辟spiflash的内存映射。在下载算法中,将W25Q64的逻辑起始地址指定为0xC0000000(EXFLASH_BASE_ADDR)。W25Q64共8M,按1M、2M、5M分为3个区域,其中0xC0100000-0xC0300000区域供程序运行中使用,烧录时不能污染,所以没在连接脚本中体现
[C] 纯文本查看 复制代码
MEMORY
{
        ROM (rx) : ORIGIN = 0x08000000, LENGTH = 256k /* 512KB flash */
        RAM1 (rw) : ORIGIN = 0x20000000, LENGTH = 128k /* 128K sram */
        RAM2 (rw) : ORIGIN = 0x10000000, LENGTH =   64k /* 64K sram */
        NorFlash1 (rw) : ORIGIN =0xC0000000, LENGTH = 1M
        NorFlash2 (rw) : ORIGIN =0xC0300000, LENGTH = 5M
    }
SECTIONS
{
    .NorFlash1 : ALIGN(4)
    {
        . = ALIGN(4);
        KEEP(*(.NorFlash1))
            *(.NorFlash1.*)
            . = ALIGN(4);
        __NorFlash1_free__ = .;
    } > NorFlash1

    .NorFlash2 : ALIGN(4)
    {
        . = ALIGN(4);
        KEEP(*(.NorFlash2))
            *(.NorFlash2.*)
            . = ALIGN(4);
        __NorFlash2_free__ = .;
    } > NorFlash2
}
通过__attribute__,指定数组的section属性。__attribute__也可以指定数组所在的具体地址、对齐属性等
[C] 纯文本查看 复制代码
__attribute__((section(".NorFlash1"))) char spi_store_1[] = "aaa,This is stored in extenal norflash1. \n\r";
__attribute__((section(".NorFlash1"))) char spi_store_2[] = "bbb This is stored in extenal norflash1. \n\r";
__attribute__((section(".NorFlash2"))) char spi_store_3[] = "ccc This is stored in extenal norflash2. \n\r";
__attribute__((section(".NorFlash2"))) char spi_store_4[] = "ddd This is stored in  extenal norflash2. \n\r";
程序中可直接使用数组的地址(也就是字符串指针),但MCU若没有XIP功能,不能直接读取存放在spiflash地址的数组内容


[C] 纯文本查看 复制代码
extern char spi_store_1[];
extern char spi_store_2[];
extern char spi_store_3[];
extern char spi_store_4[];
int main(void)
{
    LOG_I("addr.spi_store_1=0x%x,spi_store_2=0x%x", spi_store_1,spi_store_2);
    LOG_I("addr.spi_store_3=0x%x,spi_store_4=0x%x", spi_store_3,spi_store_4);
    // 这种用法会报错
    // LOG_I("content.spi_store_3[0]=%d", spi_store_1[0]);
}

之前讲解了如何使MDK下载算法应用于jflash,将自己的OFL应用于jflash的步骤类似,按照ld中的内存映射修改xml即可。值得注意的是,一次烧录可以使用多种OFL
[XML] 纯文本查看 复制代码
<Device>
  <ChipInfo Vendor="ST"
    Name="Stm32F407VE_VS"
    WorkRAMAddr="0x20000000"
    WorkRAMSize="0x00020000"
    Core="JLINK_CORE_CORTEX_M4"/>
  <FlashBankInfo Name="MCU Flash"
    BaseAddr="0x08000000"
    MaxSize="0x00080000"
    Loader="STM32F4xx_512.FLM"
    LoaderType="FLASH_ALGO_TYPE_OPEN" />
  <FlashBankInfo Name="SPI1 Flash"
    BaseAddr="0xC0000000"
    MaxSize="0x00100000"
    Loader="f407_ofl.elf"
    LoaderType="FLASH_ALGO_TYPE_OPEN" />
  <FlashBankInfo Name="SPI2 Flash"
    BaseAddr="0xC0300000"
    MaxSize="0x00500000"
    Loader="f407_ofl.elf"
    LoaderType="FLASH_ALGO_TYPE_OPEN" />
</Device>
jflash中创建新工程,即可看到添加的内容
1.jpg
image (2).jpg
烧录时直接使用elf文件,若地址不在范围内还会报错


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-9-26 18:22 , Processed in 0.054465 second(s), 26 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表