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

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

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

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


8 o; K" I# n7 P9 V2 R6 T0 Y

微信图片_20230220210427.png

8 j' Y" ^7 K" x2 u! x/ ]

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

& u# E" i7 u# A3 f6 y5 K

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

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

  • 通过MDK打开分散加载文件,配置“ExtFlashSection”段:
    " C0 f; A  G: k
  1. ; *************************************************************
    7 Z9 q4 W2 _- F. {/ s& O
  2. ; *** Scatter-Loading Description File generated by uVision ***2 z$ e* A  K0 {( I
  3. ; *************************************************************8 {* D3 S; a, K5 C$ ~7 }# w. {

  4. & K( M% J  [7 g' x. `: Q: A! ~
  5. LR_IROM1 0x08000000 0x00020000  {    ; load region size_region- _) x- L$ m1 o, V9 i( t- p3 M
  6.   ER_IROM1 0x08000000 0x00020000  {  ; load address = execution address9 i" Y7 C$ R5 h% R! R
  7.    *.o (RESET, +First)
    / A& K1 F, `% t
  8.    *(InRoot$Sections)
    * z% g% U+ `$ R* k" v9 `. f( Z
  9.    .ANY (+RO)2 t, W- w) l4 J  I: J4 A
  10.    .ANY (+XO)
    . o+ g4 y+ c7 ~, l; C
  11.   }
    * k" t& h* b; b. }1 I1 Q" d
  12.   RW_IRAM1 0x20000000 0x00020000  {  ; RW data' D8 b4 N( c  r8 h$ L4 h) R& e9 Y  u
  13.    .ANY (+RW +ZI)
    1 ^3 [9 a" d4 q. Z3 G  T! N
  14.   }: V$ R. ]. _! _! J* Y, |* T- ^
  15.   RW_IRAM2 0x24000000 0x00080000  {7 p; O( F+ f6 V
  16.    .ANY (+RW +ZI)" X9 m+ F) [1 X) t" b( R8 u
  17.   }4 p+ M2 h1 V% y, I% w) J$ J3 U
  18. }
    9 _9 e. i+ o4 a+ ~5 G

  19. " Z9 m2 w. D: t; k
  20. LR_EROM1 0x90000000 0x01000000  {    ; load region size_region
    ' N$ A9 I; b7 P4 P5 ~6 C( S) b" n
  21.     ER_EROM1 0x90000000 0x01000000  {  ; load address = execution address
    7 q) {6 M# k( d  W+ \5 R
  22.   *.o (ExtFlashSection)
    0 D& z+ R$ u6 ]+ W
  23.   *.o (FontFlashSection)
    ) G# f$ W1 w5 b. L- S! C0 D
  24.   *.o (TextFlashSection)' v$ m3 ^; x5 F: g6 T
  25. }; g' D8 T7 s3 y- k
  26. }
复制代码
: E- v% a+ B' i+ C3 `+ B) b2 S

) d, Y, o! `" |2 ?' w+ \2 v

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


3 o6 c* E* Q" H, r/ x, Q+ P

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

  1. #define LOCATION_ATTRIBUTE(name) __attribute__((section(name))) __attribute__((aligned(4)))( Y% b- ?( U% z9 N. g# s
  2.   C- z1 y$ ^0 ]" r4 W
  3. KEEP extern const unsigned char image_watch_seconds[] LOCATION_ATTRIBUTE("ExtFlashSection") = // 4x202 ARGB8888 pixels.0 f3 K: \0 q' f) a
  4. {
    : ~- c5 H( D- N- E
  5.     0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00,2 P6 r- J+ Y1 v8 Q. o; Y
  6.     0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0xff,. [. E7 z4 L' }7 S8 C) n4 j
  7.     0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00,
    - J+ \3 Z! ^$ Y5 m1 b
  8.     0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0x00,% F( s' T! }6 @  c  J
  9.     0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0xff,
    7 }9 @4 A5 P% b" p) v/ X
  10.     0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0xff,/ U/ D4 z! e% D6 O6 k" P3 u
  11.     0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00,
    8 S: `6 W1 E, t) K2 @
  12.     0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0x00,# @3 e9 z0 Y' G
  13.     0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0xff,: r1 j& b* W# r( Z
  14.     0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0x00,/ I& x% _. u( q; x# ]+ D
  15.     0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0xff,6 E, x! m! V. h! K  o3 `& f$ d+ t" N
  16.     0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0xff,
    5 q/ q. d5 H' u: \, t  C: H
  17.     0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0x00,) j: c6 n: Y& \$ ?2 g" G
  18.     0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00,( ~/ S* t3 }0 b% {+ E( o; {5 V4 r
  19.     0xf8, 0xfc, 0xf8, 0x00' k) K. t+ A1 d
  20. };
复制代码
. V9 t' c- A& T8 n3 N/ ?  w

2 e1 Z. w/ V' e% S3.编译代码* R/ _$ w5 e8 @3 ~  q6 v* C% V

& P" y5 t$ [6 u) I
/ |+ b! q. U2 l, {1 J6 S
7M0~6]}WEV(W3{9CZ5I8_R5.png 1 Z) p$ Z' {+ A) S
1 }, C! n6 G8 F' O

/ x6 ]0 r( X6 W( Z0 `7 a1 Q' G

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

$ Y; E7 V1 C( Z0 {

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

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


* V' q! G% E4 |6 a% q* u

2算法程序中擦除操作执行流程7 i; \  s& ]+ N8 s
) L+ g( B4 x! M4 C% O
- |3 p* l8 L0 W' ]+ W+ J: S
SC~H`7SQW7MR4]WI)K{%RP5.png
$ a. s* U" R4 f3 y" y
8 m3 N: }$ {1 y* b. h3 v8 H/ N! q
6 m. R; j. W6 k# c! z) W
算法程序中擦除操作执行流程
  • 加载算法到芯片RAM。
  • 执行初始化函数Init。
  • 执行擦除操作,根据用户的MDK配置,这里可以选择整个芯片擦除或者扇区擦除。
  • 执行Uinit函数。
  • 操作完毕。* Z$ I; Q" A9 y! o

: b2 V. v8 Y7 J6 g3 t

; r8 ?& {& M# ], b% V1 A6 g  o3制作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 编程算法。
    , n; B1 Y! B6 M/ w

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


% g% B% R7 s% G" g

Part4三、使用STM32CubeMX新建工程. T" N; q* L: v9 Y" j) Q2 c
4新建工程

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

软件:   STM32CubeMX,MDK

选择MCU型号(STM32H750XBH6)* L# N1 F) l/ Y& j  W3 `4 O7 w1 P
5 a2 B1 K+ Q% ~
- S  |* G; O: d4 ]3 W# F! S
{FDY0OIRG(7AA96PX1%XO.png
. ?2 @# d) l' p1 _% h选择MCU型号" C2 Y, Y& n4 J+ @1 k' @7 {

' x/ \" s8 J/ p% l

3 O% ]9 {2 C6 I, H8 i% W4 b3 @配置SPI
: f. s+ C2 i5 V1 u9 {  _
3 p" T: w' \, d6 L  Z

3 a' r5 b7 @0 R) j9 {* Z 8 D2 U# Y3 E3 G( M7 n

' [  F# A8 X+ k8 @

1 J+ i& B" q5 L$ S/ O. `; E* P% B' N# T
: q6 `0 Z1 e* o0 X/ j
配置UART$ b' G8 j, ]6 y
4 ?0 s3 C" z; r# _; V2 [4 G8 F3 O6 |1 B
; ~4 w0 d( g. A% w
2OE4M$R`38~L@7F$}$RLA3B.png
1 X0 }/ R  Y; T; Q6 ~* U& o- @" |1 U* D( e' }

8 v$ X$ g( F; f1 g! R! z配置时钟树/ L9 d0 k9 }) c) p, ]2 p% k; {

2 b9 I+ d( d9 ~# @# @

* ^/ R* |( D% { ~0HV%~)P44TTQZEA3B[1JQC.png ( @$ D. C* q; I4 ^5 A7 e
8 m3 D" h3 p& Z/ E! j3 f: y8 j
1 F/ ^4 s6 F7 A2 [/ J+ L% S* m. _

: [* l' c; R! S/ n! e

$ E$ [: }' s" v" T5 S9 q设置调试接口
6 g+ r) \+ K3 g+ I$ N
- g) g" ]3 D1 c" b, f- @  I& k/ e+ u

! b% A5 i8 z! J" a$ S" S 1ZJX$BP9O0GEJAAZ(ALW2$M.png
+ m7 U. L+ J$ {) @" _
5 x0 B, W2 ]( D, X" w4 p

6 E  h1 ?9 [) M设置工程并生成工程
5 p/ K3 W+ S5 Q2 b, l6 h% p/ N$ Q( G. U9 r

/ E' X  ^8 e- T: a D48WYLW`EFGMDK8D[[{5E7K.png # ~% q; I9 e" T* r# X1 W5 C1 e

; D; V, A, G  f" l- E: v9 q, ~6 @

0 }# t, x  H: O4 M: d52. 移植SFUD串行 Flash 通用驱动库
8 O, S* r" {$ {, tSFUD 是什么

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

  • 主要特点:支持 SPI/QSPI 接口、面向对象(同时支持多个 Flash 对象)、可灵活裁剪、扩展性强、支持 4 字节地址
  • 资源占用& O) i/ s: i9 ~8 P
    • 标准占用:RAM:0.2KB ROM:5.5KB
    • 最小占用:RAM:0.1KB ROM:3.6KB, s$ v1 R' L# d4 S% v. t' ^6 [8 H' s
  • 设计思路:
    - E" H( ]5 R# \) n- `* `
    • 什么是 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 的全部操作。
      2 d0 [1 W' L2 i, \' j
# D& n) D8 O/ C7 c/ M  x
/ L) }1 W1 Y+ A3 ~; w
移植SFUD

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

9 W) \2 D$ Y9 P2 r) ]! V! a

CS_RO6]$RS7@YZOD_2GK649.png

8 D3 J$ i0 |( J5 k

将sfud添加到工程目录:


8 s& V2 i$ @9 y) z4 B1 P7 g. E

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

, ^& |8 {; M, c6 d# S/ j

修改sfud_port.c文件:

  1. #include <string.h>
    . ~* B% g" z& S/ E1 P
  2. #include <sfud.h>  p/ N$ P$ G" P9 M; ^1 N6 C
  3. #include <stdarg.h>, z: o0 N( J6 C/ W
  4. #include "gpio.h"
    % Z5 a' F! e; e6 \6 ~5 ?
  5. #include "spi.h"6 x! I# O: g* X5 q

  6. + |! E. |) B3 O% Q
  7. typedef struct {
    7 j* g+ G" N; C. d/ w
  8.     SPI_HandleTypeDef *spix;) D3 E( J; U2 i1 _4 r
  9.     GPIO_TypeDef *cs_gpiox;3 s1 |7 D" l! i' a/ E- |: t
  10.     uint16_t cs_gpio_pin;
    9 Q, n/ x5 D8 |" S8 K
  11. } spi_user_data, *spi_user_data_t;
    * Z7 Y% b* E9 D' s  b+ _
  12. , q# @; O: i+ Q- I5 v3 t+ c4 O
  13. static spi_user_data spi1;% M8 }2 h: @+ L. C% ]
  14. static char log_buf[256];; J5 X7 w5 A! C0 u) T1 H" l
  15. void sfud_log_debug(const char *file, const long line, const char *format, ...);
    % g$ b( l% F: F1 n* o: B" z
  16. extern int rt_vsnprintf(char *buf, int size, const char *fmt, va_list args);
    0 S, Z- o% e. }( P
  17. extern int rt_kprintf(const char *fmt, ...);) k& C2 u# w# _0 t4 e5 R
  18. static void spi_lock(const sfud_spi *spi)  m) y; o( Q1 e
  19. {# N9 m0 @- \1 U) A! }8 ~$ s# e" i

  20. ; Y) {& u/ ^; a9 |* j2 y
  21. }0 S% M& z/ j+ S7 i: f/ a

  22. / E9 W2 z% h# T
  23. static void spi_unlock(const sfud_spi *spi)5 I6 Y* f2 d; F$ Y
  24. {  i: V' c* s8 A8 l1 H
  25. , ]# f* L9 {) |" V# k
  26. }5 C6 ~* Q& j# i8 _' Q
  27. /* about 100 microsecond delay */
    6 V9 \% Y1 s+ Q# M/ \8 R; V
  28. static void delay_100us(void) {4 Z5 [; u* n6 J4 \6 [2 i$ e$ L/ t
  29.     uint32_t delay = 2000;
    6 d6 F5 A2 n. F7 k6 e$ {' M+ ]0 I( U4 S9 u
  30.     while(delay--);
    2 L1 Q% M8 ~- L& u' a
  31. }' t, I7 S0 l% O: l' {$ }
  32. /**
    " T8 p  G; J5 A! m+ s
  33. * SPI write data then read data
    8 J' Q- C2 W  N. b4 [* G( q$ W! X
  34. */2 h& A' R$ [2 h7 A7 O
  35. static sfud_err spi_write_read(const sfud_spi *spi, const uint8_t *write_buf, size_t write_size, uint8_t *read_buf,
    2 u0 H7 O0 z/ r4 W# }6 Q
  36.                                size_t read_size)
    1 n, F9 H/ l; h( m; w  j/ v6 i
  37. {8 Y" V5 ~: A( q2 L2 h& R1 \, ]
  38.     sfud_err result = SFUD_SUCCESS;
    9 y* n' L1 S/ h9 H% \
  39.     /**
    ( K* E1 @- ~3 F3 J+ F+ b( g
  40.      * add your spi write and read code
    6 j9 V* {- ~$ {9 M5 b7 a
  41.      */( N5 c& h6 t+ G. [6 h  z
  42.     spi_user_data_t spi_dev = (spi_user_data_t) spi->user_data;
    ( c9 A: e: H" q) e0 z( y
  43. ! R" r# k$ c( E9 i% K- P
  44.     HAL_GPIO_WritePin(spi_dev->cs_gpiox, spi_dev->cs_gpio_pin,GPIO_PIN_RESET);
    2 g8 h1 h. b) u7 F, y
  45.     if (write_size) {3 u; U7 K( @* Z. }) [3 s+ T
  46.         HAL_SPI_Transmit(spi_dev->spix, (uint8_t *)write_buf,write_size,1);! L; M" ~; ]& i6 d5 X! ^6 a* @
  47.     }, K0 z; q/ ~# g; A0 r# J
  48.     if (read_size) {
    ) M1 s9 P3 ~# T: J0 ], ~' Q
  49.         HAL_SPI_Receive(spi_dev->spix, read_buf,read_size,1);
    5 T# C1 B" v5 D  g; y% R% |
  50.     }
    2 [+ E, G! R: K
  51. exit:. B) n4 e. x6 B) T% ^& q$ u5 ~7 p
  52.     HAL_GPIO_WritePin(spi_dev->cs_gpiox, spi_dev->cs_gpio_pin,GPIO_PIN_SET);
    , I  i  Q, H( R# E
  53.     return result;7 E) e# P  X5 [: A7 ~/ V
  54. }
    4 ~7 w1 G8 ]/ A( Y' J. _0 T3 {

  55. : S. W# x$ [. U  i. w: o
  56. sfud_err sfud_spi_port_init(sfud_flash *flash)9 G) M7 w; }* ^+ K9 D
  57. {, _4 E9 _, s+ k( B
  58.     sfud_err result = SFUD_SUCCESS;
    $ g( @/ a7 z* N& F+ ~

  59. 4 i1 M* g; p/ C' h
  60.     switch (flash->index) {
    * {! f. {1 h6 ^+ r! r
  61.         case SFUD_W25Q128_DEVICE_INDEX: {$ H. i( u) X% {' F/ n) a* n
  62.             spi1.spix = &hspi1;1 I0 Y3 @1 p/ z+ G5 s
  63.             spi1.cs_gpiox = GPIOA;3 m/ i+ v' `3 _3 u
  64.             spi1.cs_gpio_pin = GPIO_PIN_4;
    ' i. ?- d6 o" v! X5 x" I& |. ?
  65.             /* 同步 Flash 移植所需的接口及数据 */1 Q* A! u, h6 Q& @( K' P
  66.             flash->spi.wr = spi_write_read;
    ' h; d  a+ m$ ]- l' H1 n* p$ U  F
  67.             flash->spi.lock = spi_lock;
    3 B/ }( \1 _$ N- n
  68.             flash->spi.unlock = spi_unlock;
    . ~$ |- i/ I. g( \! f! u
  69.             flash->spi.user_data = &spi1;9 o5 y' [  J8 d# y5 b/ z( g& l
  70.             /* about 100 microsecond delay */! J6 X( f( w$ S9 ^
  71.             flash->retry.delay = delay_100us;4 w4 v2 j& m! e  K  ?0 G
  72.             /* adout 60 seconds timeout */  v( ]5 @' x0 ]0 `" S+ y
  73.             flash->retry.times = 60 * 10000;
    ( z& M5 j. _+ Z& t) |# W

  74. 8 @$ k4 Y8 Y( w$ f7 T; w8 o
  75.             break;4 @6 n/ E5 Q: o# R
  76.         }+ I& k" f0 @9 t
  77.     }) i# Q) q: z, F' q  f5 v  q, I
  78. ; p6 e. V* c. G7 q, R' J5 j
  79.     return result;
    6 P+ ^  W. y# Q8 h. a1 Y) W( `: k
  80. }" `- x: K$ u% O. z5 k

  81. * E4 g& Y0 f- o, {' A6 n" s/ d9 D. M
  82. void sfud_log_debug(const char *file, const long line, const char *format, ...) {
    5 X7 {* Y  S  @0 _# _3 X( Q
  83.     va_list args;
    , P2 c$ ]' y" f- l5 b
  84. : e* g7 l0 |( ^3 v
  85.     /* args point to the first variable parameter */
    . h( G* Y9 N: |5 K: u
  86.     va_start(args, format);+ R" Q) b/ p) D! S; g
  87.     rt_kprintf("[SFUD](%s:%ld) ", file, line);
    7 M) G, y+ k9 G1 b8 w9 y! z; [( E
  88.     /* must use vprintf to print */
    2 j0 U( g- _0 z. q8 s" p$ ^8 ~
  89.     rt_vsnprintf(log_buf, sizeof(log_buf), format, args);& K/ B* A9 o; b2 c. w  q$ s
  90.     rt_kprintf("%s\r\n", log_buf);6 j7 }# ~1 x$ L  u" f* \! w2 I: U' n
  91.     va_end(args);
    & x: H4 n. B( i) l' r
  92. }4 M0 V9 N4 ?* U( ~% V

  93. , F1 a0 g8 q* r
  94. void sfud_log_info(const char *format, ...) {
    9 h2 Q* s6 d' H" H
  95.     va_list args;& f3 O9 ]- q0 b4 p/ S& V; u+ e

  96. & \" D7 K4 }$ Q) T' B0 k
  97.     /* args point to the first variable parameter */5 \$ i" @# X# K
  98.     va_start(args, format);
    - [4 y3 I! N0 B$ D
  99.     rt_kprintf("[SFUD]");) @- F# `9 ?2 ?& H3 Z, ~
  100.     /* must use vprintf to print */
    " Z/ w  r* C9 {2 i1 L* E. K
  101.     rt_vsnprintf(log_buf, sizeof(log_buf), format, args);5 O3 ?: W4 {! |) f8 R: h1 S
  102.     rt_kprintf("%s\r\n", log_buf);
    4 A5 P! q- \6 _2 ~: n
  103.     va_end(args);
    9 {4 p3 p6 a* G3 I7 g
  104. }6 _! |! K( P) W$ P6 Q) k
复制代码

9 @6 A' g2 F# Q
4 `- s* o. Y1 p
测试SFUD

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

  1. /* USER CODE END Header */
    1 Y3 q% R2 u% ]1 h, d
  2. /* Includes ------------------------------------------------------------------*/, U' k3 ?- s! U8 C% G$ L
  3. #include "main.h"
    4 O# d& M1 z1 I$ u+ `0 C6 I1 `
  4. #include "spi.h"
    ! D, x7 p9 O+ n6 d; h/ W2 u
  5. #include "usart.h"1 ?' }$ [8 z! I2 q! b1 F" p" V
  6. #include "gpio.h"
    / q( S) @$ Q( `: |7 C1 j7 K

  7. 9 K" @' U+ y8 g, O
  8. /* Private function prototypes -----------------------------------------------*/1 D: a' j- E6 o/ _" N! l
  9. void SystemClock_Config(void);
    % u0 A2 y! u  B8 p" Z
  10. static void MPU_Config(void);
    0 }) O9 d! i7 h9 e* V% H# Y- O# l
  11. /* USER CODE BEGIN PFP */1 V; {/ V3 a$ O' F6 c, M
  12. extern int rt_kprintf(const char *fmt, ...);
    : l7 P. b: a, t
  13. #include "sfud.h"
    " @" b4 b# x! T( }- K$ f5 e4 M, _
  14. /* USER CODE END PFP */
    : {2 u. x% X: m& z% E& s) j
  15. / G: o7 q4 J+ z3 O1 ~: z
  16. /* Private user code ---------------------------------------------------------*/" r7 c. `* p5 ^; s! c9 G$ }  o' a
  17. /* USER CODE BEGIN 0 */
    5 r) W* Y; h0 D: F! {
  18. #define SFUD_DEMO_TEST_BUFFER_SIZE                     10245 u6 C, E. ?2 |0 q

  19. / }/ m# b7 ^1 y# f2 f8 F* g
  20. static uint8_t sfud_demo_test_buf[SFUD_DEMO_TEST_BUFFER_SIZE];
    0 C4 v/ N0 v! `9 i
  21. /**' J3 K2 N' w2 d' m
  22. * SFUD demo for the first flash device test.% y$ {  E- d0 Q. ~- }* F
  23. *$ u: p$ U* T4 a
  24. * @param addr flash start address
      H( W& ?" j% G5 Q; v! e7 Z# \
  25. * @param size test flash size
    5 m9 y7 E, z. {: d% ^# o
  26. * @param size test flash data buffer* L1 f' u" ?+ }& U7 f7 W, P! W% M- ~
  27. */
    1 l6 G5 l# l! J/ t" P( f
  28. static void sfud_demo(uint32_t addr, size_t size, uint8_t *data) {. q1 B) P9 |1 p2 K
  29.     sfud_err result = SFUD_SUCCESS;
    " w3 M) E' d, k3 G; q/ ~
  30.     const sfud_flash *flash = sfud_get_device_table() + 0;; [9 m  y. t6 B
  31.     size_t i;& L+ M2 X* n" T  L
  32.     /* prepare write data */, D& z1 P' X. E" J# S, m5 h
  33.     for (i = 0; i < size; i++) {
    # m* e3 l8 E$ [. p
  34.         data[i] = i;  ^; ?" r& L& o9 F
  35.     }& a' A) v7 y. @
  36.     /* erase test */
    5 P  T4 G6 }+ L' E4 y! p5 E
  37.     result = sfud_erase(flash, addr, size);! v6 D) L3 |# C4 t8 ]
  38.     if (result == SFUD_SUCCESS) {
    0 \' W, x. ~. U2 J; {1 b' ~3 ]
  39.         rt_kprintf("Erase the %s flash data finish. Start from 0x%08X, size is %d.\r\n", flash->name, addr,
    ) o0 X+ @  ^) d* Z
  40.                 size);5 C6 _0 i1 K. d9 q/ f0 }
  41.     } else {# X( F4 S: R+ z+ W4 N
  42.         rt_kprintf("Erase the %s flash data failed.\r\n", flash->name);0 P/ E, H7 z9 u" x7 _
  43.         return;
    ( v3 z: K, b7 J* o8 @
  44.     }
    / z' t. a+ k# o6 ~/ p' R) g( i
  45.     /* write test */9 h7 @6 F9 s/ k2 s# L# P
  46.     result = sfud_write(flash, addr, size, data);6 C- c9 |/ W* F, H! ^) c) W
  47.     if (result == SFUD_SUCCESS) {
    ) r% G# J' P: b: A4 X: ^4 m7 o
  48.         rt_kprintf("Write the %s flash data finish. Start from 0x%08X, size is %d.\r\n", flash->name, addr,' t" r( M! N5 C8 H  m, @
  49.                 size);
    % c$ ]) y: {6 T
  50.     } else {% V' m4 a# m5 K# h( d  \; b
  51.         rt_kprintf("Write the %s flash data failed.\r\n", flash->name);  S, V$ S9 ]9 I4 ~' I
  52.         return;
    1 d8 L+ L! B' L- }% I0 ~& w0 {% F
  53.     }
    + Y/ C/ q" e- `- N2 e' z& C
  54.     /* read test */" G- {# D; I) D! R; p4 m2 [
  55.     result = sfud_read(flash, addr, size, data);) ?; n! O) b. O; `, e" a' ~0 o
  56.     if (result == SFUD_SUCCESS) {
    3 Y8 @1 q1 I. z1 d
  57.         rt_kprintf("Read the %s flash data success. Start from 0x%08X, size is %d. The data is:\r\n", flash->name, addr,: `: Y( t3 _' i& p0 O( s: Q
  58.                 size);( n% H6 D2 D! C' v$ Q
  59.         rt_kprintf("Offset (h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\r\n");
    ! O. T3 o8 B* K% K1 i, J( N
  60.         for (i = 0; i < size; i++) {9 y- L- M1 o) Y) b
  61.             if (i % 16 == 0) {7 q! F9 P' U3 {' @' b. p0 V
  62.                 rt_kprintf("[%08X] ", addr + i);) i% A8 Y7 c1 }# Y  L) C& i  l
  63.             }
    3 ^8 f7 p4 k$ u( g; n
  64.             rt_kprintf("%02X ", data[i]);
    % V+ ?* e( n7 [6 s
  65.             if (((i + 1) % 16 == 0) || i == size - 1) {
    , ?# D2 I% H. I% ]2 _
  66.                 rt_kprintf("\r\n");
    1 \( p  }3 G! j. t$ ]2 u
  67.             }, g# [1 z% k* d/ I7 f
  68.         }( b" I* e& D, V
  69.         rt_kprintf("\r\n");
    ! M& ?7 z0 V  O0 x
  70.     } else {! c5 W$ O+ B: x' v. e& @; Z! r7 x
  71.         rt_kprintf("Read the %s flash data failed.\r\n", flash->name);
    " F/ a6 L: H; k, h& W8 g
  72.     }8 p' E) C' O1 O  z% y# [! l, Z* v
  73.     /* data check */! z8 x8 Z; t' [( e8 v: O
  74.     for (i = 0; i < size; i++) {
    - s6 O! V* O: A- [
  75.         if (data[i] != i % 256) {
    / P: ?7 a, b( l1 C% ], n5 c; H* O: A
  76.             rt_kprintf("Read and check write data has an error. Write the %s flash data failed.\r\n", flash->name);) L3 w4 p# C+ P9 [- |: Z/ L
  77.    break;
    7 o3 `  u9 t% o2 S+ m7 X
  78.         }  @! g! U( \! d4 N3 ]
  79.     }& M# O7 p! r, [1 L$ z: T) L
  80.     if (i == size) {
    1 }& d& V. {1 Z/ C# I4 P1 g& [. S
  81.         rt_kprintf("The %s flash test is success.\r\n", flash->name);0 R5 ~# ^3 k( H' G) K' N, Y/ n
  82.     }" F5 A, p7 l: Z0 t2 K. r
  83. }
    $ X, G4 ^! C2 }0 F/ C
  84. . I+ y$ B- l8 e
  85. /* USER CODE END 0 */
    0 W/ }" N( Z9 F: }% J: E/ K

  86. 2 B4 h' v, c0 m. }! @5 f
  87. int main(void)
    $ a% Y( E7 O9 p6 V3 G
  88. {3 L/ w! s* K  U% p$ ~9 `. i: U5 h

  89. $ w' m8 `- T) b0 x2 F9 w% y
  90.   /* MPU Configuration--------------------------------------------------------*/
    ( P- e( H" x9 W  p6 G+ j1 e) Q# u; G
  91.   MPU_Config();
    5 X, k6 I5 ?2 N1 o( b( X& k

  92. / o' ]) a% u3 q' }+ n
  93.   /* MCU Configuration--------------------------------------------------------*/: y: ]9 Z6 J" x' N
  94. + e, f( v7 D& T+ K9 d/ `; z
  95.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    / x9 p  ~& A" f, |
  96.   HAL_Init();
    9 d. r4 `" N7 ~1 \8 y
  97. , H% \- O, G) ]+ K1 o3 c
  98.   SystemClock_Config();
    ' v2 A6 Y* K' e$ D- L& y  `

  99. " X2 `! U9 q  r. A
  100.   MX_GPIO_Init();6 @3 |* w$ ^1 g7 x
  101.   MX_SPI1_Init();
    % l' L: b' {' J! ~$ A8 ?
  102.   MX_UART4_Init();
    / f5 J: u- h4 u8 s
  103.   /* USER CODE BEGIN 2 */- P5 F$ }% w6 N1 @$ _" V+ H& _
  104.   if (sfud_init() == SFUD_SUCCESS) {
    8 `, ]2 ~; a6 w$ i1 u+ Q
  105.       sfud_demo(0, sizeof(sfud_demo_test_buf), sfud_demo_test_buf);
    . X) m7 Y. v) ~# G% c1 W
  106.   }
    ) N8 n+ m; g& m" N! q0 @! q7 J
  107.   X( K# c9 T7 ?6 f7 o9 q  m
  108.   while (1)
    ( c% f) g) v; P9 S2 m
  109.   {
    7 K4 Z% Y2 K0 L8 Z+ @) M
  110. " J" I$ \( ~" Q0 @( s
  111.   }
    4 e% s. X7 p( ?

  112. " f+ R3 m7 f0 v4 T
  113. }
    8 A2 c  b# }, r6 ^2 O5 @0 }
  114. % x1 P. ]7 q! Q& ^% e+ S
  115. #endif /* USE_FULL_ASSERT */
复制代码

运行如下:

1 s0 \9 H5 n9 `8 }  j; v) E( v

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


1 r2 p2 [. Y- W4 ~$ J" a

63. 制作下载算法
1 d3 [" g, J, ~; w重新生成不带main函数的工程
5 U. z( x' K; G( r' b. S1 h( T5 Z" s6 A
FM5({[5%Y2KW1XJDT3ZR)N9.png * V8 T7 t3 V5 E) a" J
( c/ Z9 W! k- i# X% N
添加修改编程算法文件FlashPrg.c

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

  1. #include "FlashOS.H"/ V: l- n2 w! j' k3 Q: y' ?3 o
  2. #include "sfud.h"- H2 V( Y- }$ X- }! K2 }
  3. #include "gpio.h"0 X; U4 c# h% d% T: Q3 X
  4. #include "usart.h"
      ?. ^1 [. h, j( I/ Z
  5. #include "spi.h"6 O6 A  Z  E+ U$ _5 U$ m! Z7 c

  6. ( N- g7 r8 u5 N( G3 h! u
  7. static uint32_t base_adr;
    7 {6 T4 _7 W- {6 ]

  8. / P& ~# y; Z+ v- V
  9. /*
    # \4 y% ~, b1 V; }  c3 ^7 y( ~2 a: Q. V5 p
  10. *  Initialize Flash Programming Functions
    $ X4 F( Z% l3 W" X, ]" |
  11. *    Parameter:      adr:  Device Base Address* o( ]$ i$ l. u& Z
  12. *                    clk:  Clock Frequency (Hz)  ?: B, C+ }7 f, {0 c
  13. *                    fnc:  Function Code (1 - Erase, 2 - Program, 3 - Verify)# I4 h- C4 c  S) h3 e# a1 ^
  14. *    Return Value:   0 - OK,  1 - Failed
    ' C3 s0 h7 I- `/ o8 }
  15. */
    ) o* d  A' @' V
  16. 2 |; l7 K" p" i& h
  17. #if defined FLASH_MEM || defined FLASH_OTP
    6 y- Y1 V+ x% Z  H/ t! k, S5 b
  18. int Init (unsigned long adr, unsigned long clk, unsigned long fnc)
    8 Y/ E$ o# q1 F4 C' m' p
  19. {
    % n8 p+ u( j: P" Y* F5 Q0 P2 Z
  20.     MX_GPIO_Init();
    0 U8 T5 m) ?5 x4 A$ f; H! C
  21.     MX_UART4_Init();
      n% o5 s* A" x3 h7 {- o
  22.     MX_SPI1_Init();
    - Z! x4 A. m6 [. j, l6 Q! H
  23.     base_adr = adr;. f& n$ ^, o, f. [# ?1 a; _; j
  24.     if(sfud_init() == SFUD_SUCCESS) {: a7 m% r) |+ C3 [5 `" D5 m
  25.         return 0;4 p, ]- g7 Y7 ]4 m
  26.     } else {
    ; v6 \" _' H' V1 u3 t: i5 w9 V* T
  27.         return 1;
    6 g3 k' r5 U- X# |0 M: a
  28.     }- ^+ D; K# R  k; S& u6 A% Q
  29. }' \3 K: L# [1 C1 m! N
  30. #endif- m) J) _% J8 ]

  31. " o; l7 x0 w9 g" a) s: r, u
  32. $ n+ I$ v8 F  |* d
  33. /*/ Q& o1 D) ^$ M$ V, u1 D( z
  34. *  De-Initialize Flash Programming Functions
    1 |' M* @) l% N
  35. *    Parameter:      fnc:  Function Code (1 - Erase, 2 - Program, 3 - Verify)3 e& Z; i" k# p( \
  36. *    Return Value:   0 - OK,  1 - Failed
    9 B. z, n4 ^6 U! l8 Y3 E
  37. */, j1 n* h" ], D8 t* n! C
  38. 8 E4 J; O& c+ |; V0 f/ L5 p& E! r  L
  39. #if defined FLASH_MEM || defined FLASH_OTP
    + v3 h- X: H5 g' k3 V
  40. int UnInit (unsigned long fnc)
    / C- r( }  w( p, J
  41. {
    7 |5 }2 B5 W; p# Y, e
  42. 0 Q5 k8 c+ j* U) L6 f( @' ^
  43.     return (0);7 r; ?, _& D% o' I" J
  44. }7 s) @) D! n1 G( z0 v9 n, ?
  45. #endif
    " \$ [* A3 H7 a& h
  46.   c: W  Y3 }/ d
  47. /*( o5 F+ {/ C5 v2 R" ]: Z1 k" k; c. {
  48. *  Erase complete Flash Memory% F+ c) l, R; ?. ~' x
  49. *    Return Value:   0 - OK,  1 - Failed
    ) X+ b9 W& O6 g7 V6 v6 n: @* l
  50. */9 a6 s1 G  T0 ~$ W& E

  51. ( N0 I: {! {, K5 v5 n& l- q
  52. int EraseChip (void)# K8 _# a1 W# H5 D. ~
  53. {
    4 ~1 ]% ^5 c4 Z6 p/ F
  54.     int result = 0;) H! G3 _  l( U8 e; \
  55.     const sfud_flash *flash = sfud_get_device_table();' O. O/ [& X2 v) J  R& c2 y, G5 w) W* Y
  56.     /* Add your Code */
    & H8 H: C8 _) S; V+ J  I
  57.     result = sfud_erase (flash, 0, flash->chip.capacity);
    / f7 V3 b$ Y. C( j3 ^: V

  58. 8 i& P' `  Y( P- w& t" z% E) [
  59.     if (result == SFUD_SUCCESS)4 \2 F4 C3 B- f5 d$ f9 {$ X
  60.         return 0;
    : n0 a4 n- `  e  F0 C% R! p* @
  61.     else1 G) I* {4 S' n' o- F/ I2 T$ v
  62.         return result;                                  // Finished without Errors/ M9 A$ o# Y8 v2 Z# |0 A
  63. }9 m/ R' C7 p. Z/ \; ~5 t# ^( t/ m

  64. 0 @1 d# ]5 E8 A. a9 s
  65. /*% y# J- T, A  u  S; o' y
  66. *  Erase Sector in Flash Memory* H' v. u$ |0 F) e( p
  67. *    Parameter:      adr:  Sector Address
    1 U6 s! u; n% P5 X; h* s8 J
  68. *    Return Value:   0 - OK,  1 - Failed/ x! k( A8 G" k# d( {, O0 q8 }, @
  69. */( ^) M9 X; {4 p' f* O
  70. 6 Z( m1 G6 I: r
  71. #ifdef FLASH_MEM
    " t: y4 r# e( K6 i7 s# H- ^7 O6 r
  72. int EraseSector (unsigned long adr)! o+ x6 D6 _: N; g  c
  73. {2 D- b  ?+ K# |: T( r9 O4 A
  74.     int result = 0;
    0 x( V8 ~. I4 q7 e$ @- E
  75.     uint32_t block_start;
    4 U; T4 \! m( [4 X
  76.     const sfud_flash *flash;
    " R' D9 @' M3 C* `
  77.     flash  = sfud_get_device_table();
    ) Y; S$ h& t# {2 T" y7 _) ?
  78.     block_start  = adr - base_adr;
    2 R! \) ^4 {  u  q
  79.     result = sfud_erase (flash, block_start, 4096);
    3 n2 X  `% C4 j% H2 a. j3 n% X

  80. + I4 y) ], k- M2 {; M% G- z
  81.     if (result == SFUD_SUCCESS)+ {! ~0 X: P# _* T* X7 q
  82.         return 0;
    " g, z; A9 F+ N. N1 s
  83.     else
    ( ^6 ~6 _' }* o/ Z* w; r% |* k  X
  84.         return result;. S% @# J- z+ X8 x. n9 Y3 j6 _7 Q
  85. }
    . a' j, b1 v% N9 C' V% j) s
  86. #endif
    - S: A: A$ Q1 f5 m2 M, d

  87. . D( L  R7 t- S# A

  88. ( h( H( {$ j6 p( [+ n* x6 ]4 N" q
  89. /*
    : A. w$ Q+ h, z! y  f0 P2 u
  90. *  Program Page in Flash Memory
    ) S$ M1 |2 @! h2 `/ L1 ^
  91. *    Parameter:      adr:  Page Start Address5 _# l9 }/ A& M
  92. *                    sz:   Page Size( |' v, t3 t' s2 E
  93. *                    buf:  Page Data
    9 G0 o1 x( p# u  M
  94. *    Return Value:   0 - OK,  1 - Failed
    - B0 R# C* q% K- N4 _% P0 [7 j
  95. */
    9 p: w4 B0 G$ Z2 A0 U' ^6 ^/ D5 G

  96. 4 N1 E+ f  S3 k
  97. #if defined FLASH_MEM || defined FLASH_OTP
    4 l& C# u5 E  l: W6 Q
  98. int ProgramPage (unsigned long block_start, unsigned long size, unsigned char *buffer)
    7 W5 o9 a0 q$ M! g8 V
  99. {5 i. p) |3 V2 H2 t0 T, @) z
  100.     const sfud_flash *flash = sfud_get_device_table() + 0;
    , F$ W. F  U2 }5 ~5 i
  101.     uint32_t start_addr = block_start - base_adr;
    * [4 ~! M0 b- ?* \

  102. 9 b, C: O/ C" h- @
  103.     if(sfud_write(flash, start_addr, size, buffer) == SFUD_SUCCESS)
    / A! e! Y+ }5 f! I: w) Z
  104.         return 0;, G/ c5 @* s3 V
  105.     else( J1 G: Z- a$ e) o# }/ b
  106.         return 1;3 T7 x0 D& x! N2 w; N5 _
  107. }
    . }0 z9 B4 p1 a

  108. + g  r' e8 d8 y8 F) W' E8 a. b# p
  109. ) v, p3 Q* m  z* b
  110. #define PAGE_SIZE            40962 w0 m$ ^& U  ?- L. f6 H
  111. uint8_t aux_buf[PAGE_SIZE];0 @. @+ a0 h3 I9 O
  112. unsigned long Verify (unsigned long adr, unsigned long sz, unsigned char *buf)/ J# q4 N' z5 B. O" t* ?
  113. {
    , D. T% n" I8 Z; H$ y' g
  114.     int i;  Q# e6 k3 w8 Z- |$ u: F! ?
  115.     const sfud_flash *flash = sfud_get_device_table();
    1 s4 A# U2 R2 |$ B  i* {& O
  116.     sfud_read(flash, adr - base_adr, sz, aux_buf);# L! k# B0 G6 \% J5 ?

  117. 7 @8 m  u6 t! W+ C
  118.     for (i = 0; i < PAGE_SIZE; i++) {% ?" d; ]0 Y0 g, d3 q
  119.         if (aux_buf[i] != buf[i])
      w  c3 c  K5 b% u( t) J
  120.             return (adr + i);                 // Verification Failed (return address)8 ]8 Z% `0 W; X' a% e
  121.     }
    & Z! N( {: [' @: a& d

  122. , z" P$ V  E0 q8 K9 k8 W
  123.     return (adr + sz);                    // Done successfully
    . e) E5 {, N7 C9 q4 }: Q5 X( i0 R) N) h
  124. }4 A% M3 i  ]# s* k* l0 r! I7 [8 C! I
  125. 3 u3 E7 h+ T* p% v' P) {  L
  126. #endif
复制代码

+ A2 n! K  H+ d* i7 \! z) _6 |
0 `8 ^" c! \" B1 U) _( |( X6 h

在工程中定义FLASH_MEM宏

( E6 e; _" ?) r* X

微信图片_20230220211259.png


" O0 A  q# k+ ^( w1 n

添加修改配置文件FlashDev.c

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

  1. #include "FlashOS.H"        
    # Z- R& \, a; B- B

  2. - S, y: K! J# a2 Z$ C
  3. #ifdef FLASH_MEM% c1 A% I% h8 M' {2 @
  4. struct FlashDevice const FlashDevice  =  {
    % S# y1 V. `* Z" W
  5.    FLASH_DRV_VERS,             // Driver Version, do not modify!
    # j$ S1 g3 M1 q5 {2 e
  6.    "STM32H750-ARTPI",          // Device Name
    9 K; T1 O( Y) i& i
  7.    EXTSPI,                     // Device Type+ o1 G3 H& I) Y9 q5 t
  8.    0x90000000,                 // Device Start Address- d* s, M1 M6 e3 |% b3 ]. S
  9.    0x08000000,                 // Device Size in Bytes (128MB)
    & k6 I) r% ?# ~8 q! r
  10.    0x00001000,                 // Programming Page Size 4096 Bytes
    7 `& ^: w& i) t: d# ~8 f5 T8 }
  11.    0x00,                       // Reserved, must be 02 {, [( ?. C/ K
  12.    0xFF,                       // Initial Content of Erased Memory5 i! `! d2 j6 ?/ e& |2 a
  13.    10000,                      // Program Page Timeout 100 mSec% n( x# n& X4 F# ^. ^
  14.    6000,                       // Erase Sector Timeout 6000 mSec
    ' ^  ~* }: `1 n1 ?, G! ~

  15. ( ^' }0 k! g5 }/ u  Q
  16. // Specify Size and Address of Sectors
    ! m: h6 P- s/ A8 h
  17.    0x1000, 0x000000,            // Sector Size  4kB. l# l6 r# w1 W$ d) {4 A9 v2 E- P
  18.    SECTOR_END
    # {! Y, b# `1 y% _7 a' r4 E+ S2 _
  19. };
    8 g. a/ t% Y7 T$ C0 B
  20. #endif // FLASH_MEM
复制代码

( P  Q' R! Q; K7 R

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


/ Q/ i3 g) ^0 w# n3 T! p& m; q8 n

地址无关代码实现

C和汇编的配置勾选上:

0 X* f; Z7 P2 }4 E

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


& _% ^3 ~+ X$ K; E

ROPI地址无关实现

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

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

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

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


3 H, ^7 y+ ]! H" N- z/ _

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

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

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


: Q( h- a& Q* `% t6 U$ J0 W9 G1 c1 E- ]

特别注意:

  • 由于模块中不含中断向量表,所以程序中不要开启任何中断。
  • startup_stm32h750xx.s不再需要参与编译; ?( Q" |9 c0 ?( A; J) d
7 K( l5 y7 a3 T5 l" F) r
% N/ |8 Y$ ]  ~8 V
微信图片_20230220205842.png
% v1 x% i% G% P: Z5 k* A# w: Z. ]6 H, v7 e; R
9 P6 _' J9 Z: `, e" I! K* Y
修改分散加载文件

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

$ Y  j# Z) n3 i7 [; w

J2(7FVO7MLDYI5VA15HGJ(A.png

& F4 Y" E! }3 r* o8 b9 T

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

  1. ; Linker Control File (scatter-loading)% f3 d- l& d: _: g0 H
  2. ;
    $ A  S2 a$ k' ]+ b) y+ _$ y( H
  3. , I; j. i% Q/ ^8 J0 u3 _/ K  [
  4. PRG 0 PI               ; Programming Functions; V' F8 z; f7 Q" ?8 D) N% Y8 k
  5. {9 z3 _6 h7 ~# G; w! `
  6.   PrgCode +0           ; Code; ~! m1 |6 J, M( o- ~6 A. k
  7.   {
    * V' `8 u* a8 j9 P, G' c
  8.     * (+RO)! R* j# p4 P* l6 f" D  ]: ^
  9.   }
    5 d/ ]9 B( }% R- w
  10.   PrgData +0           ; Data
    9 _7 o4 N0 J' T* w  z
  11.   {
    + t/ ?4 A! m( K6 v, J( j( f, r) v
  12.     * (+RW,+ZI)/ |  C% \2 V# ?/ Z* m3 i; C
  13.   }0 ~8 w8 g$ S5 T" |& R% m
  14. }
    ; [, Q4 j) @* D: `1 V& E
  15. : l/ d6 I- v9 A1 d& O8 B* A
  16. DSCR +0                ; Device Description- o* p" @' x# `: p2 L
  17. {
    - J& m1 Y1 E: {
  18.   DevDscr +0
    $ e  r& W  Z" r
  19.   {9 W! C( H/ [) j5 @
  20.     FlashDev.o
      \0 V& s4 b7 J4 {9 D; ?
  21.   }
    6 D! h+ G. r* R( y! l6 @
  22. }
复制代码

  U5 Q( s8 ]9 m+ m8 ?
将程序可执行文件axf修改为flm格式

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

' T" r" h; N0 t+ m& L% j; C

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


7 P8 U4 k6 M& I& a0 v8 I$ C5 D

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


- Z' i7 S; v4 u7 F2 J" b完整版请查看:附件
8 ~  n; x6 e+ A* @, i* k1 @5 m* m) S* b5 r/ b
收藏 评论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 手机版