如何将SPI闪存添加到STM32CubeProgram的外部加载程序中?

1.简介:

需要使用初始内容制造外部存储器的应用程序在调试过程中可能非常困难,并在生产周期中造成巨大损失,因为通常需要使用不同的工具集使用两个编程过程,一个用于外部存储器,另一个用于对STM32内部闪存进行编程。STM32CubeProgramer的外部加载器是一种功能,它允许STM32CuboProgramer甚至STM32CubeIDE直接访问外部存储器,以读取、编程和擦除数据,而无需使用常规STLINK以外的任何其他工具,甚至无需更改STM32的内部闪存。这是一种可行的方法,可以加快使用外部存储器的应用程序的调试周期和制造程序过程。
本文的主要目的是提供一个关于如何开发自己的外部加载器来管理外部内存的分步指南。这个演示实现使用NUCLEO-G007RB和简单的SPI闪存,但它可以很容易地为其他微控制器和存储器类型量身定制。

2.先决条件:

    为了开发本文的演示,需要以下材料:

-硬件以下为:

  • Micro USB电缆:为板供电和编程
  • 核-G070RB
 

 
 
  • 外部SPI存储器(W25Q64)
 

-软件:

  • STM32管
  • STM32管式编程器

3.理论:

          要直接访问外部存储器,而不必对STM32内部闪存进行编程以承载驱动程序和基本功能,外部加载器会在将所有这些所需功能加载到STM32的RAM时做出响应。然后,STM32CubeProgram可以自由访问RAM存储器,从而使用SWD通信调用这些功能,从而使STM32CuboProgram能够执行读取、编程和擦除过程。
STM32CubeProgram已经配备了为我们所有的评估板和各自的内存创建的所有外部加载程序,但您可以根据您的应用程序添加更多的内存。我们需要创建一个从STM32的RAM执行所有管理功能的项目,这将需要一个自定义链接器文件、一个特定的头和函数集来构建*.stldr文件,这是STM32CubeProg外部加载器用于映射所有内存功能的方法。这个*.stldr可以使用编译器后期构建创建,然后手动添加到STM32CubeProgramer和STM32CubeIDE程序文件夹中。

4.发展:

          首先,我们需要创建带有驱动程序的ExternalLoader来管理外部内存,并将其设置为在RAM中运行。因此,让我们在STM32CubeIDE中为STM32G007RBT6(NUCLEO-G007RB的微控制器)创建一个项目。
      根据存储器规格配置SPI,在本例中使用SPI闪存:
          主代码需要外围设备初始化功能,以及后来的内存驱动程序,此外,具有单独源文件和头文件的外围设备使项目更清晰、更易于执行。要执行此操作,请转到“项目管理器”->“代码生成器”,并选中“将外围设备初始化生成为每个外围设备的一对“.c/.h”文件”框。
然后点击“设备配置工具代码生成”或进入项目->生成代码生成代码。
由于我们需要从RAM运行所有函数,因此链接器文件STM32G070RBTX_FLASH.ld中需要进行以下更改:
  1. 将代码的入口点从Reset_Handler更改为在稍后创建的Init函数中启动。
/*入口点*/Entry(初始化)
  1. 在入口点后添加以下行,以在二进制文件中生成两个段,第一个用于Loader代码(将接收Memory函数),第二个用于设备信息(将存储Cube Programmer和STLINK使用的一些信息)。
/*为Loader代码和设备信息生成2个段*/PHDRS{Loader PT_LOAD;SgInfo PT_LOAD;}
  1. 由于功能将从RAM运行,请删除内存区域代码中的FLASH区域,并将RAM区域名称更改为RAM_D1。将RAM的起始地址更改为0x20000004,以防止与将位于第一个内存位置的重置处理程序发生冲突(当入口点不同于重置处理程序时,此更改是必要的),因为我们稍后也将更改NVIC以放置在RAM中
/*内存定义*/MEMORY{RAM_D1(xrw):ORIGIN=0x20000004,LENGTH=36K-4}
  1. 更改要在RAM_D1上分配的中断矢量的位置,并使存储器偏移
.Irs_vector:{.=.+0x1FC;/*isr矢量偏移量*/.=ALIGN(4);KEEP(*(.irs_vector))/*启动代码*/.=ALIGN(4),}>RAM_D1:加载器
  1. 考虑到RAM区域的名称已更改,我们需要在堆栈地址设置上更改此名称
/*用户模式堆栈的最高地址*/_estack=ORIGIN(RAM_D1)+LENGTH(RAM _D1);/*“RAM”末端RAM型存储器*/
  1. 为了防止编译器倾向于删除未使用的函数进行优化,需要对*.text部分进行更改。我们需要维护RAM中的所有函数,因为它将从STM32CubeProgrammer调用。为此,添加“KEEP(*Loader_Src.o(.text*))”行代码。
/*将程序代码和其他数据放入RAM类型内存*/.text:{.=ALIGN(4);*(.text)/*.text sections(code)*/*(.text*)/*.text*sections(code)*/*代码*/}>RAM_D1末尾的符号:装载机
 
  1. 更改。ARM.extab。
.ARM.extab:{*(.ARM.eextab*.gnu.linkonce.armextab.*)}>RAM_D1
  1. 从.data部分删除RAM功能部分。
/*将数据段初始化为“RAM”RAM类型内存*/.data:{.=ALIGN(4);_sdata=.;/*在数据开始处创建全局符号*/*(.data)/*.data节*/*(_data*)/*.data*节*/.=ALIGN(4),_edata=.,/*在数据结束处定义全局符号*/}>RAM_D1:加载器
  1. 通过将“>FLASH”更改为“>RAM_D1:Loader”,强制将所有部分放置在RAM的Loader段中。
  2. 创建.Dev_Info部分,注意该部分被放置在步骤2中重新创建的SgInfo区域中。
.Dev_Info:{__Dev_Info_START=.;*(.Dev_Info*)KEEP(*(.DDev_Info))__Dev_Info _END=.;}>RAM_D1:SgInfo
  1. 删除.ARM、.preinit_array、.init_array和.fini_array的所有“.=ALIGN(4)”命令。
  2. 剪切.text、.Dev_Info和.rodata部分,并粘贴在de.bss部分之后。本系列文章的最后部分介绍了一个链接器代码示例。

所有链接器编辑完成后,是时候为项目导入自定义外部内存驱动程序了。如果您还没有,您可以使用我们的知识库来学习如何创建一个。
第2部分将展示如何创建外部加载器的必要文件,以及STM32CubeProgrammer和创建的项目之间的关系
再见!