你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

从零编写STM32H7的MDK SPI FLASH下载算法

[复制链接]
STMCU小助手 发布时间:2023-2-20 21:04
Part1前言

当我们要下载编译好的镜像到Flash时,首先要做的一步就是选择合适的Flash下载算法,而这个算法本身就是一个FLM文件:

* M, b, j: i) l) L

微信图片_20230220210427.png


! |) O. C# D2 ]1 f& m

代码既可以下载到内部flash,也可以下载到外部flash,或者一部分下载到内部,一部分下载到外部。

) v, D! w& m$ A6 y6 s

Part2一、将代码中的图片资源下载到外部flash

在UI设计中往往需要大量的图片和字体,图片和字体资源在代码中以静态数组的形式存在,这些大数组在内部flash中一般存放不下,所以需要把这些占用资源比较大的数组放在外部flash中,然后通过QSPI地址映射的方式访问,或者通过SPI将flash中的资源分批读取到RAM缓存中使用。

  • 通过MDK打开分散加载文件,配置“ExtFlashSection”段:# W# i( n& o7 m& Y  x
  1. ; *************************************************************
    + L" w( {# u, \8 `
  2. ; *** Scatter-Loading Description File generated by uVision ***
    ; {7 c: [0 @. D7 Q; b
  3. ; *************************************************************4 {4 Q$ {8 W0 l5 D
  4. # f, i; C* g8 Z& [4 E
  5. LR_IROM1 0x08000000 0x00020000  {    ; load region size_region
      N$ {/ b. {5 o7 r
  6.   ER_IROM1 0x08000000 0x00020000  {  ; load address = execution address! D! J% {6 A" p  g! I$ H' x+ C
  7.    *.o (RESET, +First)
    7 d8 k* ]. @( o, v; `: b, b
  8.    *(InRoot$Sections)
    % X/ F/ N/ l: P' @5 P( P
  9.    .ANY (+RO)5 @2 f9 ?5 |3 g! R
  10.    .ANY (+XO)4 w2 z/ y! y8 d7 Y# M0 ?& k
  11.   }9 ]/ j5 u* a6 u0 g
  12.   RW_IRAM1 0x20000000 0x00020000  {  ; RW data
    . A2 }/ w+ O" A5 E" b" b4 j# i/ P
  13.    .ANY (+RW +ZI)
    # m8 T% b- B6 r
  14.   }
    7 ?! l: m, x" U8 K
  15.   RW_IRAM2 0x24000000 0x00080000  {
    9 W5 k0 {- W' A& G0 ^6 T
  16.    .ANY (+RW +ZI)
    $ x2 g& L; y9 ?2 L
  17.   }9 h8 \$ V7 s! S( N
  18. }
    9 h* b3 l# u* u0 }" U0 ^+ d! R9 Q; O8 d

  19. ! Q$ V* u$ [% Q! O
  20. LR_EROM1 0x90000000 0x01000000  {    ; load region size_region3 Z6 c9 ]+ i+ D: Y8 X& }
  21.     ER_EROM1 0x90000000 0x01000000  {  ; load address = execution address
    + T. p0 B# J  d+ H) k, ]# y1 J5 v( d
  22.   *.o (ExtFlashSection)
    $ l" Y$ M4 ]% u1 B$ \: D" P  r
  23.   *.o (FontFlashSection): q' |" ?$ ~6 C! g; _' a
  24.   *.o (TextFlashSection)3 o8 Y9 C5 N4 t2 D
  25. }
      E& T4 r8 ?9 {, D1 N4 k3 h
  26. }
复制代码

& K2 r& D% l" [9 B8 u/ T
6 K: B& ^! ]  u

添加LR_EROM1 段,起始地址为0x90000000 ,大小为0x01000000  。


" X! j( x" ?: V5 g) |; z' d

2.在代码中将图片资源分配到ExtFlashSection段

  1. #define LOCATION_ATTRIBUTE(name) __attribute__((section(name))) __attribute__((aligned(4)))
    " C+ B; N& f2 z! \( F5 O/ `6 ~. ]/ O6 J

  2. 0 v& B- s+ d9 x3 K" U
  3. KEEP extern const unsigned char image_watch_seconds[] LOCATION_ATTRIBUTE("ExtFlashSection") = // 4x202 ARGB8888 pixels.
    ; i( ?7 W$ W1 a+ i+ N) J( U! s9 [" L# q
  4. {
    2 `0 j8 v6 U  V9 W
  5.     0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00,) a' M8 [8 W7 R
  6.     0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0xff,
    6 W6 r4 a/ C7 W5 Z* E" D8 f
  7.     0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00,
    - w% F& E/ S  j8 V
  8.     0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0x00,
    & b2 S- q- b$ v, R3 n7 U0 ^
  9.     0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0xff,
    ! v$ q2 I- a# k; h1 ~' A3 L; {6 a9 l. Q
  10.     0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0xff,8 I3 h& U# s& U) @+ E
  11.     0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00,
    ( b  b2 m. W% b( m4 ^  @
  12.     0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0x00,/ ~3 e( f( i7 J7 D. P- V* N- ^
  13.     0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0xff,
    8 J+ r. U( R( J. w3 h$ T, t, c9 z3 L
  14.     0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0x00,# e: U+ x/ b7 a( N* k  w
  15.     0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0xff,
    + d( `$ y/ x0 K' i5 a. ?
  16.     0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0xff,
      G) L- t0 @* N& W0 p+ m6 E1 e9 ?
  17.     0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0x00,, [/ R( A. o- I( z2 i% s7 R. S5 z
  18.     0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00,
    - i2 [' z3 O3 J4 H, o
  19.     0xf8, 0xfc, 0xf8, 0x003 I, R& T; l/ O8 q/ I, ^
  20. };
复制代码
- I# W2 v- B7 A- ?$ K
% N3 F3 d6 Q% h' g3 r
3.编译代码! d4 W0 p0 ^( [" x3 B. ]
, e; B2 b; C+ H' D8 A% f, x  w0 r
1 o5 D, f) a! X5 O0 O9 `) l
7M0~6]}WEV(W3{9CZ5I8_R5.png
$ I9 L9 n& d. a; u& q
! C9 o6 ?1 H! B/ H, e3 A, R/ h

# a* o# t& J4 Y5 v& k5 r

查看map文件,image_watch_seconds这个数组已经被分配到了0X90138690这个地址了,这个地址正是LR_EROM1 所在的区间。


( c: W! D% G' |3 L, y

Part3二、MDK下载算法原理1程序能够通过下载算法下载到芯片的原理

通过MDK创建一批与地址信息无关的函数,实现的功能主要有初始化,擦除,编程,读取,校验等,然后MDK调试下载阶段,会将算法文件加载到芯片的内部RAM里面(加载地址可以通过MDK设置),然后MDK通过与这个算法文件的交互,实现程序下载,调试阶段数据读取等操作。

4 }  N0 I1 E0 }+ z: [* n6 R# d0 G5 z

2算法程序中擦除操作执行流程4 S; c# J3 W2 f) Q  z  f
+ p% }' K0 o: e" d

6 ?/ c$ f) D: F: p SC~H`7SQW7MR4]WI)K{%RP5.png 1 {2 C7 y/ W" G& n
% f6 o' I$ G3 b

+ H8 V( M" N, W+ z算法程序中擦除操作执行流程
  • 加载算法到芯片RAM。
  • 执行初始化函数Init。
  • 执行擦除操作,根据用户的MDK配置,这里可以选择整个芯片擦除或者扇区擦除。
  • 执行Uinit函数。
  • 操作完毕。$ G, S) Y6 J1 i5 A1 z# C
" G4 `  t/ q0 e/ C% p

. r# ]  ]+ b- r# B$ Q3 q- g3制作FLM文件步骤
  • 将ARM:CMSIS Pack文件夹(通常是C:\Keil\ARM\Pack\ARM\CMSIS\ version \Device_Template_Flash)中的工程复制到一个新文件夹中,取消文件夹的只读属性,重命名项目文件NewDevice.uvprojx以表示新的flash 设备名称,例如MyDevice.uvprojx。
  • 打开工程,从工具栏中,使用下拉选择目标来选择处理器架构。
  • 打开对话框Project - Options for Target - Output并更改Name of Executable字段的内容以表示设备,例如MyDevice。
  • 调整文件FlashPrg中的编程算法。
  • 调整文件FlashDev中的设备参数。
  • 使用Project - Build Target生成新的 Flash 编程算法。
    6 |9 `2 C% @# [0 V( t8 O

以上步骤是利用官方的工程模板修改代码,这种方式网上已有很多教程(推荐使用这种方法),不再重复介绍,接下来介绍一种不使用模板工程制作的方法,目的是为了了解其实现原理。


* c, {% n3 l8 w( w! Y; U2 N) y

Part4三、使用STM32CubeMX新建工程6 j5 l. S1 c' U8 U8 [- j& r
4新建工程

硬件平台:   RT-Thread官方ART-PI H750开发版

软件:   STM32CubeMX,MDK

选择MCU型号(STM32H750XBH6)
) W# d/ k) i4 J# @* C' U; I6 Q- y% o' \0 }4 L- `  }: I  q; y4 U# Q: Q3 a0 w
! S% ?( q6 F1 [" d8 I6 s* ^2 J
{FDY0OIRG(7AA96PX1%XO.png 7 p# u8 f6 B) R* Q
选择MCU型号
  s$ Y/ k8 G7 e2 D& u- W! |
/ m, j% y* H6 w2 \) J' p2 b8 k

' e5 W+ Z8 y8 l, o$ [! o# B配置SPI
: j% F( a& J! Y) W' a3 k
! C2 [& X! O2 }0 f) z

' G6 b; \5 o) }0 W. A8 I9 }
+ `3 p1 W2 R' ~+ ~9 {) w& N, j1 q3 x: {1 }& b
+ n9 z" I! z3 W& t2 `

2 k7 {6 [- b! O

& _1 ^/ u- w, t8 ?/ [% x配置UART! ~8 w1 A" v1 t
6 w/ a+ h# V  z& Z) k$ C: c' q+ n

& g/ t* \) ]5 D6 T3 t; v$ a 2OE4M$R`38~L@7F$}$RLA3B.png " ?1 G$ [! p" j2 @
2 F2 B7 f; l# g* a2 B0 n; S

  `7 f$ }# b) [( B% V- U6 P8 U" U- z配置时钟树
2 _: B: t1 u' R/ ?# v  s! ^$ ]$ K4 x  [( I

9 ^' |# `* W4 x* t& E' N$ e* ^. R ~0HV%~)P44TTQZEA3B[1JQC.png 4 p) m# ^* U+ \7 x1 Z% F

0 ]' j: ?# g( g/ \. ^( o! f9 \

* L4 ?/ ^( Q( T  x: D% o  _: U) X" w% w& @8 l0 E

6 ^: c+ b* ~. I( R* S& q设置调试接口
. u% H: t! I7 E# l
- P: ], V/ m1 [( L

! _( z3 r9 y# [$ K6 w# t3 H* | 1ZJX$BP9O0GEJAAZ(ALW2$M.png 6 T0 {. M+ Z8 ^, o  P4 J
' v6 P: r$ z$ X, v+ W  S
2 w/ c. f2 K# h
设置工程并生成工程
, K+ W8 O, Q9 p2 O8 `. r0 Z# o2 P+ g9 o' g
) x4 N7 u! m- f6 ^
D48WYLW`EFGMDK8D[[{5E7K.png ! a3 j7 B; J7 [& n; y1 T

) a/ Y, c5 {3 o* v/ b
6 s, E% S* t6 f# w
52. 移植SFUD串行 Flash 通用驱动库. T( A" M5 V0 Q; L& ]0 T8 m
SFUD 是什么

SFUD是一款开源的串行 SPI Flash 通用驱动库。由于现有市面的串行 Flash 种类居多,各个 Flash 的规格及命令存在差异, SFUD 就是为了解决这些 Flash 的差异现状而设计,让我们的产品能够支持不同品牌及规格的 Flash,提高了涉及到 Flash 功能的软件的可重用性及可扩展性,同时也可以规避 Flash 缺货或停产给产品所带来的风险。

  • 主要特点:支持 SPI/QSPI 接口、面向对象(同时支持多个 Flash 对象)、可灵活裁剪、扩展性强、支持 4 字节地址
  • 资源占用8 W# j3 y% O& e$ O
    • 标准占用:RAM:0.2KB ROM:5.5KB
    • 最小占用:RAM:0.1KB ROM:3.6KB' s- a& w1 \+ c0 W
  • 设计思路:" R" t5 y' ?( }* b( d' U6 h, A2 m* Q
    • 什么是 SFDP :它是 JEDEC (固态技术协会)制定的串行 Flash 功能的参数表标准,最新版 V1.6B (点击这里查看)。该标准规定了,每个 Flash 中会存在一个参数表,该表中会存放 Flash 容量、写粒度、擦除命令、地址模式等 Flash 规格参数。目前,除了部分厂家旧款 Flash 型号会不支持该标准,其他绝大多数新出厂的 Flash 均已支持 SFDP 标准。所以该库在初始化时会优先读取 SFDP 表参数。
    • 不支持 SFDP 怎么办 :如果该 Flash 不支持 SFDP 标准,SFUD 会查询配置文件 ( /sfud/inc/sfud_flash_def.h ) 中提供的 Flash 参数信息表 中是否支持该款 Flash。如果不支持,则可以在配置文件中添加该款 Flash 的参数信息。获取到了 Flash 的规格参数后,就可以实现对 Flash 的全部操作。
      # o* J- e6 w! M0 e% q- L) q

( g1 t$ l) ?( x# [: U4 T- K+ N

8 w0 {$ E& S( |9 h, D移植SFUD

将下载到sfud源代码放置在工程目录中


4 u, I0 }8 K; y  c+ O& `+ w+ {) D. ]

CS_RO6]$RS7@YZOD_2GK649.png


% |* x" A9 R% E9 R9 m4 o

将sfud添加到工程目录:

0 [( o( |3 D' x

AXVS]LMBFQ{[@O7[(UH7H.png


" p) o3 c$ V( o9 Y! N7 @6 o

修改sfud_port.c文件:

  1. #include <string.h>5 s3 W0 L7 t2 x8 M% ^- {% \
  2. #include <sfud.h>
    5 l. U+ e% Z: a% X
  3. #include <stdarg.h>6 ~+ t& w. z, g6 W$ }
  4. #include "gpio.h"6 r! c8 U# b, p
  5. #include "spi.h"
    + p  I/ l  }( q$ n

  6. ! M( \  k3 y" v" ^) R3 ~- o8 v6 s
  7. typedef struct {; W- H: ]: N, B. N# [" s$ f3 g8 w
  8.     SPI_HandleTypeDef *spix;3 L: o2 V& L9 M; G! M4 }6 ]
  9.     GPIO_TypeDef *cs_gpiox;
    ; e6 v3 o0 k1 X- Z+ y
  10.     uint16_t cs_gpio_pin;
    ' M6 X& ~; r4 G
  11. } spi_user_data, *spi_user_data_t;
    3 P1 E% I+ n. k2 ?
  12. 3 \- B9 U0 h8 ?$ ]9 K, c+ s; I/ K1 I
  13. static spi_user_data spi1;) p" z7 R5 F* f  f' m
  14. static char log_buf[256];
    ) y' P1 g9 M7 T
  15. void sfud_log_debug(const char *file, const long line, const char *format, ...);
    4 x, ~. Q; x; i; a5 j/ C) K
  16. extern int rt_vsnprintf(char *buf, int size, const char *fmt, va_list args);$ H7 F# |& E( @7 X8 x7 D
  17. extern int rt_kprintf(const char *fmt, ...);
    / `- g3 b3 Y$ L7 M2 O7 T
  18. static void spi_lock(const sfud_spi *spi)! I- P$ {/ ]! p- b4 k/ B2 R
  19. {
    % H1 @5 B* l( P. Q4 `1 K% B, L
  20. 9 E/ m- o8 R5 o
  21. }
    : {) x5 k9 U: L0 _  H* b9 v

  22. ) l1 t' G2 l7 Q7 S
  23. static void spi_unlock(const sfud_spi *spi)
    / K7 f( _& {$ O# T" i* r
  24. {; U: l8 ~3 Z: d2 T5 e% x) N' o# Z: ~
  25.   U4 R4 N9 t' U- i+ Z" B
  26. }6 R$ C6 T; c! z2 X1 n1 N
  27. /* about 100 microsecond delay */
    / v* h5 a" a3 T3 j  e) s
  28. static void delay_100us(void) {) u  ?% g; f" s
  29.     uint32_t delay = 2000;7 D" E" q" a7 ~5 ~* Q2 C
  30.     while(delay--);
    5 u# ~, t0 B4 k" i' T  b- ]
  31. }' a: ]& J6 @$ U; x* G
  32. /**6 b. o" ?. p& u/ w% |0 D
  33. * SPI write data then read data- W3 O/ |- [0 p' B
  34. */
    ! ~: d% h: D0 @9 d
  35. static sfud_err spi_write_read(const sfud_spi *spi, const uint8_t *write_buf, size_t write_size, uint8_t *read_buf,
    ' I2 K& k4 t2 h; C" L" b" W: f
  36.                                size_t read_size)
    1 L1 a. u! g7 `" K" A4 ~6 `% l
  37. {: c6 r3 Z/ x5 P/ t( B
  38.     sfud_err result = SFUD_SUCCESS;
    ) q! |$ s( p. Y2 P( c! D. y5 K
  39.     /**
    # g$ Q6 W6 b3 B9 [
  40.      * add your spi write and read code& ~1 r6 b! Z2 v  e8 ~
  41.      */* D' s% _. N5 R# R. a& K( _
  42.     spi_user_data_t spi_dev = (spi_user_data_t) spi->user_data;
    % M$ U0 [& u1 j" p9 R5 W
  43. % D% T% Z- f) g# [/ f+ ~0 l
  44.     HAL_GPIO_WritePin(spi_dev->cs_gpiox, spi_dev->cs_gpio_pin,GPIO_PIN_RESET);
    + C# o) N' G0 x: i
  45.     if (write_size) {, q8 i% D5 q, H6 m$ a* N
  46.         HAL_SPI_Transmit(spi_dev->spix, (uint8_t *)write_buf,write_size,1);2 b! t3 _% p# F) J9 D) e
  47.     }
    0 e; t7 Y4 t' z% s, E, a9 V
  48.     if (read_size) {5 W8 G" y! K- |2 v* R, r
  49.         HAL_SPI_Receive(spi_dev->spix, read_buf,read_size,1);
    2 x( A$ w5 D: s, i# }
  50.     }
    * Q/ X+ K& M4 M  o, Z
  51. exit:: R& |) K0 j6 c2 j. Q! X
  52.     HAL_GPIO_WritePin(spi_dev->cs_gpiox, spi_dev->cs_gpio_pin,GPIO_PIN_SET);' Y/ n) x4 Z- V5 R9 R8 z
  53.     return result;# l) t7 Y4 g) @% \+ d5 X4 P
  54. }
    6 B3 z8 |2 M6 u+ ?5 Q
  55. # d2 A! o( L6 k% |7 q; ?' j
  56. sfud_err sfud_spi_port_init(sfud_flash *flash)
    * I5 I4 l  l( X
  57. {
    ! J7 ?( q' D% E. r+ Q/ [
  58.     sfud_err result = SFUD_SUCCESS;
    3 ~/ V; `5 U# C2 f9 W( B
  59. , n5 k: a! Y. u4 T1 d/ W3 Q
  60.     switch (flash->index) {
    ! P4 Y' h5 Z) A. J
  61.         case SFUD_W25Q128_DEVICE_INDEX: {
    7 ~4 \! B8 @- D! p4 z
  62.             spi1.spix = &hspi1;
    3 C* ?2 B* b, o% X
  63.             spi1.cs_gpiox = GPIOA;
    : u9 U2 S5 z( k0 A
  64.             spi1.cs_gpio_pin = GPIO_PIN_4;6 |2 q# k1 U( @. d8 o4 d3 u
  65.             /* 同步 Flash 移植所需的接口及数据 */
    ( q% r# D* H6 U% k4 G' R
  66.             flash->spi.wr = spi_write_read;3 w1 T1 }, v/ p! _
  67.             flash->spi.lock = spi_lock;
    % t. m* |2 P2 e0 {# x  q
  68.             flash->spi.unlock = spi_unlock;5 M3 G5 D& P9 V
  69.             flash->spi.user_data = &spi1;
    - s0 @" r; j, a5 m3 z9 Y
  70.             /* about 100 microsecond delay */" |2 |- X# G& R5 Q+ a
  71.             flash->retry.delay = delay_100us;
    " m0 l; p4 K$ G4 @. r! ~
  72.             /* adout 60 seconds timeout */1 C( W9 t1 O0 W& Y! _- c/ [' B. m2 Y
  73.             flash->retry.times = 60 * 10000;
    1 y" u$ g6 y3 K6 Y# S. J# S5 r
  74. , U7 q2 `- i+ c, ?1 e! j" F  {# ?
  75.             break;4 C% F7 J3 w* E3 {" X+ f8 i. p; ^
  76.         }
    % I/ ]9 p, c& W! W: \, e& t" i
  77.     }+ q: P+ u- t& a+ O
  78. ' v1 s: N9 c/ J
  79.     return result;
    * B8 b0 n) q- J0 F4 ^$ H( {
  80. }& w9 Y0 z3 r8 L3 ]5 _! @; v

  81. 3 u. H8 ^5 x) O; L1 W4 j0 f% Y
  82. void sfud_log_debug(const char *file, const long line, const char *format, ...) {3 p) X+ A1 J/ Z; v
  83.     va_list args;/ s  n0 e( V) v% I! ^) A  H" T
  84. + }5 f# h+ N; i
  85.     /* args point to the first variable parameter */* {0 o: C3 d& l; R6 }6 C8 V9 ~4 n' _
  86.     va_start(args, format);
    / K9 Q* O2 R* V2 o
  87.     rt_kprintf("[SFUD](%s:%ld) ", file, line);
    % [- H! E2 R' @
  88.     /* must use vprintf to print */
    6 h# B2 J3 y6 F* F. Z
  89.     rt_vsnprintf(log_buf, sizeof(log_buf), format, args);
    ) D0 o, Y$ ^$ D0 ~# R2 b4 _
  90.     rt_kprintf("%s\r\n", log_buf);8 o. t) w7 H5 L" O2 D7 f# \
  91.     va_end(args);# ]0 @5 T+ K' j) e
  92. }
    1 W) {8 A2 `8 F. h0 }) p& x: O

  93. ) {! E8 L% n3 o( y6 {
  94. void sfud_log_info(const char *format, ...) {
    7 x( n, j. N# _* B) r
  95.     va_list args;
    6 K! o( ?6 H$ w; D' M6 K
  96. 6 F( P, Z# t9 K0 L% y
  97.     /* args point to the first variable parameter */
    ; A8 `; o  k+ h0 f% x
  98.     va_start(args, format);
    # I: J4 L3 h6 k) n3 ~( `8 W
  99.     rt_kprintf("[SFUD]");
    + m) O' b7 p5 p! n; t
  100.     /* must use vprintf to print */  ]5 j* [* i/ o1 @7 k  e
  101.     rt_vsnprintf(log_buf, sizeof(log_buf), format, args);
    * ^3 W3 D% u( ?
  102.     rt_kprintf("%s\r\n", log_buf);
    3 b  d* [) m4 P: K) Z& ]: w" ~; T. V
  103.     va_end(args);8 @7 ^# |3 n0 g* ~" F
  104. }
    7 M8 ?7 k$ T6 j0 E: r
复制代码

  P; y- u; A0 P6 O
# H# h* o% }8 g, ~0 Y
测试SFUD

在main.c中添加测试代码:

  1. /* USER CODE END Header */
    0 v; P, U+ F$ V1 _1 F
  2. /* Includes ------------------------------------------------------------------*/
    , A& S2 n' B' G0 W4 c1 v
  3. #include "main.h"
    ( k; \1 V( [5 {4 `% d
  4. #include "spi.h"' s; M+ R2 Z9 y
  5. #include "usart.h"
    * o# `- L: Q9 ]2 W- A6 k
  6. #include "gpio.h") d( R6 d3 F% l' |" o" d! Y# y
  7. . f8 y" C3 i) z6 ~. r
  8. /* Private function prototypes -----------------------------------------------*/
    2 }1 ~) c" ~5 |4 k
  9. void SystemClock_Config(void);/ G" \, j& ]$ I4 T8 T: ]8 o
  10. static void MPU_Config(void);
    * Z4 q( A  r7 m! I+ o
  11. /* USER CODE BEGIN PFP *// n" q' ]& k! _3 j% t+ a* o% f
  12. extern int rt_kprintf(const char *fmt, ...);. G8 b' z7 l: d3 K
  13. #include "sfud.h"
    " K# z7 ]) e9 A$ h
  14. /* USER CODE END PFP */3 k8 F4 m! J0 b% T; s+ }
  15. * A$ Z2 h, |; H4 Y. T( U, E
  16. /* Private user code ---------------------------------------------------------*/4 k  V  r; Y& C8 k" h
  17. /* USER CODE BEGIN 0 */9 s- N1 t" }0 r+ I
  18. #define SFUD_DEMO_TEST_BUFFER_SIZE                     1024
    8 X" h( m0 n5 z8 j4 u: ?

  19. " B1 X8 g+ }1 o4 _! L# |3 T
  20. static uint8_t sfud_demo_test_buf[SFUD_DEMO_TEST_BUFFER_SIZE];
    : y) F. s- x/ J3 d/ ?) o7 w
  21. /**
    / ?, c# {( v" B' d+ `
  22. * SFUD demo for the first flash device test.3 t+ W, m7 R$ F3 l2 _
  23. *
    5 @. k1 A' \# X* v
  24. * @param addr flash start address% u- N( _9 T( p
  25. * @param size test flash size
    / Y  {& J) m* W5 v( A, u9 H
  26. * @param size test flash data buffer
    ! }/ s, t* T4 z1 @/ w! H2 @7 u
  27. */
    : `$ O8 d  I' b) m; W, L$ C
  28. static void sfud_demo(uint32_t addr, size_t size, uint8_t *data) {: X1 H4 Q7 h* |
  29.     sfud_err result = SFUD_SUCCESS;% _* |- C1 C+ W5 l
  30.     const sfud_flash *flash = sfud_get_device_table() + 0;6 @9 O7 V9 y3 q' a
  31.     size_t i;
    ! z4 H9 L# E7 N" n! I
  32.     /* prepare write data */
    5 k* L, e4 w4 A& P+ T
  33.     for (i = 0; i < size; i++) {1 {/ L& s! X& e0 b0 X$ b( E
  34.         data[i] = i;
      l% S5 y! F5 i1 C8 R& t3 {
  35.     }6 Y/ j; L  g( Q% q" D
  36.     /* erase test */# j2 u1 c; C) x/ [5 N' k; s( q
  37.     result = sfud_erase(flash, addr, size);
    ( {6 C# c+ s: N" `( I- Y; l  y
  38.     if (result == SFUD_SUCCESS) {: c, t9 b4 N! c
  39.         rt_kprintf("Erase the %s flash data finish. Start from 0x%08X, size is %d.\r\n", flash->name, addr,
    & x7 d* p0 I' V+ J: u) V$ a
  40.                 size);+ V# s2 Z# Z" [
  41.     } else {3 P5 P/ d7 O: W/ g; A
  42.         rt_kprintf("Erase the %s flash data failed.\r\n", flash->name);
    + C6 q0 Y% g! v( N* Q) e' {. {
  43.         return;5 q8 Y* G9 `! I6 j' q
  44.     }% ^$ B& R2 u8 z" a( D, m4 D1 s
  45.     /* write test */5 v% O( L# W) Z7 v- v- D
  46.     result = sfud_write(flash, addr, size, data);
    0 j0 g( T% |5 z7 k1 T
  47.     if (result == SFUD_SUCCESS) {
    ( F2 n5 M8 ]8 f+ [1 Q* p% C/ [
  48.         rt_kprintf("Write the %s flash data finish. Start from 0x%08X, size is %d.\r\n", flash->name, addr,5 F6 `. A3 {- K' n/ p# C
  49.                 size);5 n3 z8 @+ ]- D6 P) c! L
  50.     } else {
    ! X: d! O9 s7 H+ M1 _1 ]$ y- K
  51.         rt_kprintf("Write the %s flash data failed.\r\n", flash->name);$ k" F( |! q# X! N4 `! m3 c" f
  52.         return;
    9 H) g7 l- _6 T4 s' j$ k1 j
  53.     }* Y! `& J) x! x
  54.     /* read test */
    " }3 j" @) U. c  Z) M4 K  A# i
  55.     result = sfud_read(flash, addr, size, data);" Y6 k8 ?  W/ r7 T+ z: l# y
  56.     if (result == SFUD_SUCCESS) {3 V9 _7 ^2 s% w( N5 X& l
  57.         rt_kprintf("Read the %s flash data success. Start from 0x%08X, size is %d. The data is:\r\n", flash->name, addr,
    6 e+ M0 d) s# J; i9 x5 L
  58.                 size);
    , @: ^; [( S6 l. D& O& H
  59.         rt_kprintf("Offset (h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\r\n");% b8 D: ?# ~" E; L+ S5 n
  60.         for (i = 0; i < size; i++) {
    3 N' t! l+ U5 z  x& U+ y
  61.             if (i % 16 == 0) {
    . F3 o' x& S( P# R7 e
  62.                 rt_kprintf("[%08X] ", addr + i);7 Z/ B- [) w8 K3 Q% R
  63.             }; f% }9 j5 n( Z4 X
  64.             rt_kprintf("%02X ", data[i]);
    / a2 l. N: T3 a2 D
  65.             if (((i + 1) % 16 == 0) || i == size - 1) {
      O* W( N/ p; [5 K: d' d" X7 }
  66.                 rt_kprintf("\r\n");
    9 k. R- }! R+ z6 N) h
  67.             }3 S4 R& h& X* ^6 {3 y) f/ A8 N
  68.         }: L9 d4 c5 ~$ b) |3 I
  69.         rt_kprintf("\r\n");: m2 P1 J. g! t* S
  70.     } else {) B, X0 z; W. w% C0 y
  71.         rt_kprintf("Read the %s flash data failed.\r\n", flash->name);3 S/ P2 O0 R! L
  72.     }, y/ K  Q& W. Y4 I4 K7 c. |) J' O
  73.     /* data check */& Q- ?7 [4 r: F7 Q/ q. }
  74.     for (i = 0; i < size; i++) {1 _( |/ f: ?, h0 g$ Q
  75.         if (data[i] != i % 256) {
    % ^( @" ]+ {& P) l- q3 m. j9 I# @
  76.             rt_kprintf("Read and check write data has an error. Write the %s flash data failed.\r\n", flash->name);+ }$ e; {2 a" o2 C
  77.    break;6 @! H3 @3 p4 H  A- C2 N
  78.         }8 i% ?& w7 }! F
  79.     }
    % M. h' y9 r, w& F7 X; U
  80.     if (i == size) {
    # G( j* g* |# V6 M
  81.         rt_kprintf("The %s flash test is success.\r\n", flash->name);2 f! u6 a" }! ~) e: C
  82.     }
    & w5 b% Q' y4 h8 ]  h* x1 B( C
  83. }0 k$ l4 z+ ]  ~! x  @! q7 S+ ?0 [

  84. - C0 Z! a1 X. H7 f- R
  85. /* USER CODE END 0 */; T* v4 D/ [3 @; W6 m' @7 e# F
  86. 4 E% x  Z2 D+ m/ @
  87. int main(void): e, @6 C6 }2 g2 ]% \0 B1 H
  88. {# B6 d" X6 o( t# w; b
  89. 8 J* S' D( C' Q5 W  a
  90.   /* MPU Configuration--------------------------------------------------------*/
    ! z- H% }8 a- E5 i7 u+ C
  91.   MPU_Config();/ t! Q$ |/ n1 A

  92. " k. {( e7 D4 u1 T( J
  93.   /* MCU Configuration--------------------------------------------------------*/
    ! ~( E1 K+ s/ v& F/ m/ J$ e9 |
  94. # e5 }' D7 t& |' ~. B
  95.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    0 s# r- w* G) e8 ^$ o* Q; x
  96.   HAL_Init();
    ; b. ]' R) v7 b- A
  97. / Y. p8 R# W4 W; v2 [5 j  B( f
  98.   SystemClock_Config();
    1 b7 d* J2 S/ a

  99.   k- n3 \. p: T" X% E5 W
  100.   MX_GPIO_Init();6 L: }; x1 n( V8 D8 m, |
  101.   MX_SPI1_Init();- M2 ~% v5 H" |2 q! K' M+ k
  102.   MX_UART4_Init();4 M4 \- ~  b4 y0 v( Z9 R- \
  103.   /* USER CODE BEGIN 2 */, W" R& B  ]; @( h, g/ T, l$ l& [/ m
  104.   if (sfud_init() == SFUD_SUCCESS) {7 x8 s4 R( l6 l6 o- R' e  A
  105.       sfud_demo(0, sizeof(sfud_demo_test_buf), sfud_demo_test_buf);5 j6 e5 C) M& ^
  106.   }
    , ^% {. u5 R$ D4 _$ x9 V/ I: B. {
  107. . P" W7 Y# t& D, R" o5 A
  108.   while (1): S& r) d& o  A' r
  109.   {; ^6 d5 D" V: V
  110. 8 [( R& a  q5 i- }, l( U  J; g
  111.   }
    4 N! _  V* h1 d( {  C/ |
  112. ! l9 w; b) f; S& b+ c7 y6 Q
  113. }
    & M# O4 J, O: v% S1 R
  114. 5 h  Q# G; P- L. S$ N; c- m6 X
  115. #endif /* USE_FULL_ASSERT */
复制代码

运行如下:


# E6 q" _$ B3 w6 j; G& [

~Z~@6]$JBY}EL7U$S9VDPWU.png


$ V- ?7 E" w( y( A1 I: b8 y$ O

63. 制作下载算法
/ ^, E, R$ O$ U, r0 n0 C重新生成不带main函数的工程
8 r6 F6 l" n4 N$ N7 C( s& @
: I5 e0 J0 {5 M; a2 v
FM5({[5%Y2KW1XJDT3ZR)N9.png
, O$ {4 W* s1 @2 {
8 B0 J/ A. o' |0 q7 C6 n添加修改编程算法文件FlashPrg.c

模板工程里面提供了FlashOS.h和FlashPrg.c ,复制到此工程中,然后对FlashPrg.c 代码进行填充。

  1. #include "FlashOS.H". [9 W7 {' B; z( k
  2. #include "sfud.h"
      Y3 ?3 L& B: X5 u+ v
  3. #include "gpio.h"6 C6 p! ~: `# B" I7 D9 I
  4. #include "usart.h"
    , x3 l4 @. i: }4 @6 n* @5 E' D; P: D
  5. #include "spi.h"
    1 Q1 m8 h1 _9 Z+ a* o1 r

  6. , m4 w# }, j8 s5 w3 p
  7. static uint32_t base_adr;7 f3 p0 r" r6 Y- W/ h! Q  _
  8. . m8 G& E) t* I# i
  9. /*; i- \6 k0 A' X# l
  10. *  Initialize Flash Programming Functions
    # Q' {3 _- F% e: b
  11. *    Parameter:      adr:  Device Base Address
    ) n. z3 f( g$ Y' T* G& H7 u
  12. *                    clk:  Clock Frequency (Hz)/ m: A1 E7 Z- ^/ ^4 c( `+ @. n' [
  13. *                    fnc:  Function Code (1 - Erase, 2 - Program, 3 - Verify)
    5 f, z8 {( y# F( y, K9 x
  14. *    Return Value:   0 - OK,  1 - Failed
    ) b/ E6 \8 R9 k* K( [; @4 s
  15. */
    % E( g$ k5 j7 D1 m/ E% d
  16. 8 Z# [$ L0 |" V* b
  17. #if defined FLASH_MEM || defined FLASH_OTP1 H$ J* H3 L, m
  18. int Init (unsigned long adr, unsigned long clk, unsigned long fnc)
    5 V: q3 d7 w  x; @  t3 t* V
  19. {9 J' Q0 |. X& X  Z3 l
  20.     MX_GPIO_Init();8 W  U% D* J: v, D
  21.     MX_UART4_Init();
    / V+ {& z9 H% g4 |' u: x! L
  22.     MX_SPI1_Init();5 e7 K9 D6 g0 I0 ?3 Y
  23.     base_adr = adr;
    9 {. w& a0 W) E2 F1 Z
  24.     if(sfud_init() == SFUD_SUCCESS) {
    # r% c5 n9 H% e! H+ o8 q- C! t
  25.         return 0;
    2 S- y7 u& `( X3 m
  26.     } else {
    9 O' o% t, k7 W9 F( [, w* P( n
  27.         return 1;
    7 ^4 V+ V7 }# b( v
  28.     }+ R9 x% D+ v# Q) x" E/ C
  29. }2 R# \; h* x( E3 J
  30. #endif
    9 M' _% p6 w! f7 ]  ]$ g
  31. " `' G- s" u2 h1 n, M
  32. + G5 ]- j; e: }1 x
  33. /*# L* `" j3 ?5 P& q
  34. *  De-Initialize Flash Programming Functions
    8 \3 U" f8 X. q* o: f
  35. *    Parameter:      fnc:  Function Code (1 - Erase, 2 - Program, 3 - Verify)
    5 p2 l+ a, Z# C$ w9 ?, i8 C
  36. *    Return Value:   0 - OK,  1 - Failed
    ( m8 p! p- f2 y' r+ |+ J
  37. */% m9 H8 Z: F1 X1 q$ B1 v& ^- W
  38. 9 I/ D. U! M' V
  39. #if defined FLASH_MEM || defined FLASH_OTP
    8 g9 ^  J$ l5 d: s! k! \
  40. int UnInit (unsigned long fnc)
    * M( G. d1 G  h9 @# E. r
  41. {
    : t& Q* a  J/ g/ D0 ]' v' E
  42. & g% Z6 Y. y' f4 o$ ^
  43.     return (0);
    * J2 c4 X" J$ ]# Y' T* r
  44. }
    * }  R; W6 d- U
  45. #endif$ X( m9 G9 Y' q9 \- X+ [7 {

  46. - v5 d, `3 k( h9 o0 ?
  47. /*
    - L& t% @# X" t$ H9 o
  48. *  Erase complete Flash Memory: d8 |. ]) p# U2 n9 Q: f' t
  49. *    Return Value:   0 - OK,  1 - Failed8 i  g# ]2 v' h" h% }/ k
  50. */
    . B2 I7 ~" \. P8 d$ I# n

  51. ( M# N- l# J- K1 \1 i7 ^9 K5 n
  52. int EraseChip (void)# t# Q$ M$ u# J
  53. {$ T* h7 {% ]2 v& ?
  54.     int result = 0;
    - I4 d& p- _# w$ J" Y7 ~
  55.     const sfud_flash *flash = sfud_get_device_table();
    0 M6 W* z4 L& p2 T  V. y1 A
  56.     /* Add your Code */" H- t1 w/ S2 _9 S3 F3 b! O4 b
  57.     result = sfud_erase (flash, 0, flash->chip.capacity);2 u7 [- u1 v0 l5 w- w/ p5 T9 U
  58. + O, A, o8 i7 p* C
  59.     if (result == SFUD_SUCCESS)
    6 Q6 R6 z( ~2 E8 l3 _0 i$ @2 [9 q4 \
  60.         return 0;
    & a2 x/ U, z* d/ h
  61.     else
    9 J5 `- Z- F, b) \9 _& ^
  62.         return result;                                  // Finished without Errors8 V1 U1 O# V- T4 P! h
  63. }
    " J" a. ?5 P# X+ A9 C, n
  64. 6 J$ B# U/ p- P' x# R
  65. /*4 k: Y5 U3 Z& U5 L
  66. *  Erase Sector in Flash Memory3 Z% @$ l! x2 x
  67. *    Parameter:      adr:  Sector Address' ]0 g$ A2 |! e/ X+ |2 [
  68. *    Return Value:   0 - OK,  1 - Failed
    / o. t3 @. @/ Y. u( C$ P
  69. */
    , R  f* M% m" ~0 ~
  70. 1 X6 J* |% T* [
  71. #ifdef FLASH_MEM
    $ w( `- R* _! z; j
  72. int EraseSector (unsigned long adr)
    3 H% J8 R9 j3 l' |4 q0 ?
  73. {. R! \0 ~. X' R4 ?2 i
  74.     int result = 0;0 n; ]! s* n! R9 t% r1 ]
  75.     uint32_t block_start;
    , H' i  U/ I  ?" o0 V9 I
  76.     const sfud_flash *flash;
    - U5 M) A, b2 j) G
  77.     flash  = sfud_get_device_table();- c9 W0 r. x: |; ?9 H: Y% q
  78.     block_start  = adr - base_adr;/ b& B0 b9 n" b
  79.     result = sfud_erase (flash, block_start, 4096);
    $ }4 ^2 g. g: ?$ \4 ^+ Y: X

  80. ; g# c+ o5 u# ~2 J6 V
  81.     if (result == SFUD_SUCCESS)$ K* j) e6 D. W, H+ s; D; A
  82.         return 0;) L% k' b3 ^1 k9 I5 M
  83.     else
    : M) }. J% }% h
  84.         return result;# _; {) }1 r. W/ c' ]/ L
  85. }
    & p' Z& g1 r! n7 Q5 m# x8 i( r
  86. #endif2 a4 e& |5 E5 R& X

  87. , o4 ^3 J5 n5 K7 w' q

  88. 6 [! u" y0 T( d' r5 x3 H: j8 q
  89. /*
    3 R* _1 R# k1 P
  90. *  Program Page in Flash Memory  a& d  K0 |* ~3 `& I9 G$ `7 ]
  91. *    Parameter:      adr:  Page Start Address
    2 B: _- O& B3 v# E7 S9 V& b
  92. *                    sz:   Page Size
    ) t( I2 n0 y  O) D7 m
  93. *                    buf:  Page Data
    8 ]8 W- ]( i5 D. ^9 Z' E2 n# _
  94. *    Return Value:   0 - OK,  1 - Failed
    0 v7 U3 B* _9 @  z
  95. */2 D7 r0 K9 B9 s' O8 |; D% [- U
  96. , X$ S$ [; v/ X, j0 |3 T
  97. #if defined FLASH_MEM || defined FLASH_OTP! _; j0 M9 p( k: S0 T$ @3 [, l
  98. int ProgramPage (unsigned long block_start, unsigned long size, unsigned char *buffer)* N" A: B  f9 B! |
  99. {  h2 Z5 |  Y( }/ e+ X6 o
  100.     const sfud_flash *flash = sfud_get_device_table() + 0;
    " Z5 ?2 R1 g& s9 ]( F
  101.     uint32_t start_addr = block_start - base_adr;
    2 A( r9 o. y/ L; f
  102. 5 f, e- t$ v/ B8 R" W0 H
  103.     if(sfud_write(flash, start_addr, size, buffer) == SFUD_SUCCESS)$ @) t( j* `+ ^  I
  104.         return 0;! N( i1 ]" S9 }0 Z6 [8 |
  105.     else. Z# @0 B4 ?! Z. Z8 d" Y
  106.         return 1;
    ! @1 }( m; `' S2 U' D) s$ y8 D
  107. }
    + N9 h4 {- d# G4 X' ^

  108. + y5 E% X8 g- N% {; h, u& R

  109.   R* d* [$ \8 }7 T. X- @/ q) Z, ?
  110. #define PAGE_SIZE            4096. L! I9 F) e0 Z1 ~8 b: Y
  111. uint8_t aux_buf[PAGE_SIZE];6 A" {% H3 C& K+ V
  112. unsigned long Verify (unsigned long adr, unsigned long sz, unsigned char *buf)
    - [6 ]# t4 |/ e* D+ G
  113. {
      G' \  c$ p4 w  V6 w! G9 d; \
  114.     int i;% K+ o4 @0 f1 y0 L# U
  115.     const sfud_flash *flash = sfud_get_device_table();6 P( K% V! R$ {
  116.     sfud_read(flash, adr - base_adr, sz, aux_buf);- p; {" _6 s# L, O

  117. 3 V! p; o: R* f# S
  118.     for (i = 0; i < PAGE_SIZE; i++) {0 \4 f  p* D3 u7 g& m( l
  119.         if (aux_buf[i] != buf[i])
    9 F, J5 {2 Y5 B& w
  120.             return (adr + i);                 // Verification Failed (return address)
    # ]3 Z! ~1 i( d6 R
  121.     }
    8 B! ?" Y) @# H
  122. " h' |) ?8 ^  |$ a* H! n+ S
  123.     return (adr + sz);                    // Done successfully: Q& C/ s' M6 \+ B. I6 f
  124. }7 |- q: T5 V, X3 ]. R' I" U; M
  125. 7 Q  T+ [0 u1 Z* g
  126. #endif
复制代码

4 `  Y  m. N& q
' P, p4 F+ {( x7 M

在工程中定义FLASH_MEM宏


8 O  l) N- G6 A, T

微信图片_20230220211259.png


3 ]7 R0 R& s4 {8 b$ K, d

添加修改配置文件FlashDev.c

模板工程里面提供了FlashDev.c ,复制到此工程中,然后对代码进行修改。

  1. #include "FlashOS.H"        # y8 f7 Y* ~3 N* i# }8 ?, G4 U6 u

  2. ! y7 P7 [2 b' i
  3. #ifdef FLASH_MEM
    1 |( L0 ^: O, T6 [
  4. struct FlashDevice const FlashDevice  =  {
    , S! s! ^" ?% N2 D
  5.    FLASH_DRV_VERS,             // Driver Version, do not modify!
    0 N+ l, P7 N6 F' J
  6.    "STM32H750-ARTPI",          // Device Name 9 B6 Z$ {4 a1 `% k
  7.    EXTSPI,                     // Device Type
    : h: k! N* T5 Z4 H* x  }
  8.    0x90000000,                 // Device Start Address8 D5 |" x7 @) x0 E
  9.    0x08000000,                 // Device Size in Bytes (128MB); c/ c0 j6 O6 @
  10.    0x00001000,                 // Programming Page Size 4096 Bytes* s3 `8 O) Q% w8 x7 M
  11.    0x00,                       // Reserved, must be 0) c, W" D" z) i3 b
  12.    0xFF,                       // Initial Content of Erased Memory
    9 }9 O+ p" m( ]2 Y3 t5 i3 _6 v
  13.    10000,                      // Program Page Timeout 100 mSec
    # X+ T0 @+ A8 N4 }/ k
  14.    6000,                       // Erase Sector Timeout 6000 mSec
    3 Q4 z6 d- ~' C9 a

  15. 8 V6 c4 _+ T9 i# ^  a4 F
  16. // Specify Size and Address of Sectors- }( x' j, U8 |% l0 q
  17.    0x1000, 0x000000,            // Sector Size  4kB
    2 X$ d& d$ N3 e  \9 f& `
  18.    SECTOR_END5 w1 ^; r! k) G, z' M* @2 P) b
  19. };2 d5 S$ s* d- ~+ t
  20. #endif // FLASH_MEM
复制代码

3 q/ W/ J1 ]9 l% E2 J

特别注意:"STM32H750-ARTPI"就是MDK的Option选项里面会识别出这个名字。0x90000000是MDK分散加载文件中定义的外部flash起始地址。

& k% ^. i8 {" l* o0 A- s7 d* M" M

地址无关代码实现

C和汇编的配置勾选上:

; w$ k  \$ |8 j: N! s

KL5CE)S$H~6IOI1G(D35HTQ.png


; ^: q3 ~! r4 Z2 ]% z4 Z

ROPI地址无关实现

如果程序的所有只读段都与位置无关,则该程序为只读位置无关(ROPI, Read-only position independence)。ROPI段通常是位置无关代码(PIC,position-independent code),但可以是只读数据,也可以是PIC和只读数据的组合。选择“ ROPI”选项,可以避免用户不得不将代码加载到内存中的特定位置。这对于以下例程特别有用:

(1)加载以响应运行事件。

(2)在不同情况下使用其他例程的不同组合加载到内存中。

(3)在执行期间映射到不同的地址。


, Y2 g, k$ n& r. c) V1 V( V2 c

RWPI数据无关实现使用Read-Write position independence同理,表示的可读可写数据段。使用RWPI编译代码,解决RW段即全局变量的加载。首先编译的时候会为每一个全局变量生成一个相对于r9寄存器的偏移量,这个偏移量会在.text段中。

在加载elf阶段,将RW段加载到RAM当中之后,需要将r9寄存器指向此片内存的基地址,然后接下来就可以跳转到加载的elf的代码中去执行,就可以实现全局变量的加载了。

综上所述,勾选ROPI和RWPI选项,可以实现elf文件的动态加载,还遗留的一个小问题是elf模块如何调用系统函数,这与此文无关,留在以后再讲。

$ E0 n* w1 J7 n6 M; e- E1 B

特别注意:

  • 由于模块中不含中断向量表,所以程序中不要开启任何中断。
  • startup_stm32h750xx.s不再需要参与编译
    9 j+ I' n1 f1 @7 q) T& @$ z
1 K6 e/ K/ T) N3 q# a1 x# M) ]

/ ]1 P& j8 e( g4 Z; D! l 微信图片_20230220205842.png
2 s/ J8 X' @5 Q' k3 ?+ R4 T% s3 |
9 q1 b) A0 {5 P/ R- L

7 l8 s, l& Z. j/ n修改分散加载文件

复制一份新的分散加载文件到工程目录中,然后修改成如下代码

$ A3 g3 L6 f2 l5 X! K

J2(7FVO7MLDYI5VA15HGJ(A.png


# L8 l  K) ?3 `" u/ t, s  Z3 Z

--diag_suppress L6305用于屏蔽没有入口地址的警告信息。

  1. ; Linker Control File (scatter-loading)
    % }4 I% H- D+ V/ A( C0 ]5 U4 L
  2. ;
    $ ~0 k3 z* r- O1 e

  3. # I. ^5 b6 X  l' h3 Q3 i
  4. PRG 0 PI               ; Programming Functions
    3 X' n6 k5 g2 U+ C# O4 t
  5. {1 L% `% U8 y% O" B7 w* I
  6.   PrgCode +0           ; Code
    , q7 n, X( \9 R0 }* O$ ^; V& s
  7.   {
    / U8 Z3 O& a9 S0 W4 f. g
  8.     * (+RO)
    5 X/ ~9 {  H( e" i" `
  9.   }9 F3 u" e$ |7 x4 d. K7 [
  10.   PrgData +0           ; Data
    7 a. E/ O6 m+ Y6 f; _, t
  11.   {
    / J, S/ F1 Z5 y3 n' a
  12.     * (+RW,+ZI)
    $ g" L9 s7 Z) F  z5 y
  13.   }
    1 k% L. I/ F. r
  14. }
    ' {4 f+ d. r9 H
  15. 3 c' Z9 o7 W. X: L4 a# i+ W9 d
  16. DSCR +0                ; Device Description2 a1 E- U0 e9 K" [+ Z) U" `
  17. {3 n. m; Y$ U8 l! u3 t) n% E& K% K
  18.   DevDscr +0$ q2 f1 j% e) ^; h# Y# P$ A4 F+ H$ |# @
  19.   {$ M! G/ q- _: @. l% J! e
  20.     FlashDev.o
    , H3 g2 o3 q# |0 U/ q# k
  21.   }5 a, i+ A. y: u  R. ~
  22. }
复制代码
3 m. d$ K. g- d# p7 e
将程序可执行文件axf修改为flm格式

通过这个cmd.exe /C copy "!L" "..\@L.FLM"命令可以将生成的axf可执行文件修改为flm。


# j& o$ S+ J1 V2 ^

M]8}JQN})49_8NUM_XN}14X.png

% F& R% n& k- o

将生成的flm文件拷贝到...\Keil_v5\ARM\Flash目录,即可被MDK识别到。

- t% |8 Z/ u' W* ~3 s+ y
完整版请查看:附件
& x' Q6 T& k/ I# J4 K, b) h5 V
% N: _" K+ k+ i, d" O, a5 i
收藏 评论1 发布时间:2023-2-20 21:04

举报

1个回答
brack 回答时间:2023-3-10 15:13:10

可以分享附件吗?

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版