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

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

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

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


* r2 P  _6 C' Q! S5 t2 [  u

微信图片_20230220210427.png

% L. [% D" {: t1 X. Q3 ~9 J2 c

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


8 s, w5 U  Z4 g5 U+ D" B! h

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

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

  • 通过MDK打开分散加载文件,配置“ExtFlashSection”段:" @+ a0 _' ^# m1 N+ T; U
  1. ; *************************************************************
    # R# M% J! J1 g
  2. ; *** Scatter-Loading Description File generated by uVision ***
    4 Q+ t, Y5 J3 s2 i2 S( d2 ^4 ^! K! V
  3. ; *************************************************************. X9 ^9 ^$ X# s' r) ?5 _

  4. & W" _$ @, q& W% t- w5 x
  5. LR_IROM1 0x08000000 0x00020000  {    ; load region size_region
    & G$ t, ?& t. D2 r5 ]; V3 ^
  6.   ER_IROM1 0x08000000 0x00020000  {  ; load address = execution address* I2 Q/ P- h2 `( B( O7 ~0 ]
  7.    *.o (RESET, +First)
    # b. T# V* c) @: H' Q4 M
  8.    *(InRoot$Sections)
    6 ^# G7 s4 i2 L
  9.    .ANY (+RO)
    * _) g; {# d0 ]) C6 o; ~; K
  10.    .ANY (+XO)
    & h0 |9 _4 p1 F) k  r! p- Y
  11.   }0 o% T, l6 s3 r
  12.   RW_IRAM1 0x20000000 0x00020000  {  ; RW data
    * ~3 d7 `% |) s6 w( I
  13.    .ANY (+RW +ZI)
    5 r2 ?. A7 V9 R4 G7 N# N; T% L
  14.   }6 F) X  M6 k; t5 n% m$ P' a8 D
  15.   RW_IRAM2 0x24000000 0x00080000  {
    % z6 S& {' q, l7 H6 r
  16.    .ANY (+RW +ZI)
    9 I7 e/ m0 c" L% P& o% [/ ^! D9 l1 B
  17.   }
    5 ~( R) `5 z! c; e- l& `+ D5 \& ]
  18. }
    9 b% J3 f4 J5 r( K) ~& i
  19. 8 z6 o( r5 V( {/ \* g
  20. LR_EROM1 0x90000000 0x01000000  {    ; load region size_region  j5 E) D* m1 }5 Q3 Q2 |+ J
  21.     ER_EROM1 0x90000000 0x01000000  {  ; load address = execution address0 n8 K6 ^( @! E+ B  D9 w% h
  22.   *.o (ExtFlashSection)
    # F* R' Q3 g) h( S7 h& m3 e
  23.   *.o (FontFlashSection)
    , d/ Y4 D) `& V, L4 x5 S
  24.   *.o (TextFlashSection)
    ! z: a/ V8 M+ N: |# w; s- `
  25. }6 j+ A- ]1 [1 C: X( f
  26. }
复制代码

4 p- j; f- V) u# D% U9 b: j3 S7 q( j* y1 T1 |- q

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

2 ~2 b* z# z; l/ n8 z$ P

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

  1. #define LOCATION_ATTRIBUTE(name) __attribute__((section(name))) __attribute__((aligned(4)))( `) m  R; h+ f7 v9 ^' @, d

  2. 4 m& y3 T' n8 a% ]
  3. KEEP extern const unsigned char image_watch_seconds[] LOCATION_ATTRIBUTE("ExtFlashSection") = // 4x202 ARGB8888 pixels.9 v; d' i! t1 C/ D: a- `* f4 k) M
  4. {- ?( O! s2 C. E* c! I
  5.     0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00,
    " S; J7 `4 H' i4 f+ }( j
  6.     0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0xff,
    8 l8 k* V) q; Q1 ?. D9 r5 o
  7.     0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00,
    9 V6 i8 H1 |: t" ?
  8.     0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0x00,
    8 v7 ?2 [+ c( s* A: S
  9.     0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0xff,
    # a' c+ x3 \* o% I9 m
  10.     0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0xff,
    # _1 @# l" @( n) ^' I! V
  11.     0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00,, G; o6 v: }& \' w! p# m
  12.     0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0x00,
    5 A# N; Y4 p6 I: e5 j9 y
  13.     0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0xff,
    6 C# L# e% n* x/ a: C6 F0 K
  14.     0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0x00,1 z# L5 X. {: n" ], v
  15.     0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0xff,
    ' d% G; w3 ?: g2 s7 N* Q$ x
  16.     0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0xff,9 }( Z5 V4 s; t( K
  17.     0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0x00,  _: Y& E+ o$ {+ O- o- L' i
  18.     0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00,0 M: f0 R$ g; c- @* ]. w
  19.     0xf8, 0xfc, 0xf8, 0x00
    8 e9 q1 _: w2 L$ n# c. ~
  20. };
复制代码
* p2 m. a6 d) d3 i1 z% x
3 E+ C) h3 `- m% W! H  Z1 f( Y7 X9 G2 z
3.编译代码
+ Q, @% }7 x# L# V$ L! k5 P
: f6 ~# T6 q9 |  g' ]( E4 N

. ~( S# o% [  E/ K& ]* g6 _. c' V 7M0~6]}WEV(W3{9CZ5I8_R5.png
; u  j9 n+ o" O. d- h! j/ M. N2 ?* Y& d) \2 ~! c* A
5 y0 f% i0 `. F

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


: u4 ]( ^! J3 q3 C0 \/ P- W

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

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


4 Z& g% l0 U% L  M& j- Z6 Z; k  C

2算法程序中擦除操作执行流程/ x6 C/ [# H( a6 j7 B
! t7 c& L% N3 Z/ b7 |

7 r9 C% n5 q# G; y SC~H`7SQW7MR4]WI)K{%RP5.png 3 ]1 C# {' J* d0 X" ~# A5 c. ?

) z& l( n5 i+ |; q2 T

, U4 u: S6 X& d- t1 C算法程序中擦除操作执行流程
  • 加载算法到芯片RAM。
  • 执行初始化函数Init。
  • 执行擦除操作,根据用户的MDK配置,这里可以选择整个芯片擦除或者扇区擦除。
  • 执行Uinit函数。
  • 操作完毕。
    , Q& ]$ K  W& K  U) W
9 X  X1 \0 R4 P& u
1 O: H& ?+ Y1 a8 J
3制作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 编程算法。# g  h* _7 g. j; k/ \& h

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


7 I" q. b" ]: F" ]% s* U( _

Part4三、使用STM32CubeMX新建工程
" q1 W" o4 }; n$ Z7 D8 a* u) {4新建工程

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

软件:   STM32CubeMX,MDK

选择MCU型号(STM32H750XBH6)
6 Q2 U' W0 w( l: u% a% ^1 F/ {  T% I1 c" p+ y

  f5 Z2 n5 {+ ~2 o0 H* \, j {FDY0OIRG(7AA96PX1%XO.png
+ m' Y$ a7 ?1 F" k6 d选择MCU型号
6 y" }. a- I' c: o5 J5 L- ~1 g
, F* c. {1 z0 g; n( @6 [. y+ g) i" G

0 P  b* }' ]1 P  w" w0 V配置SPI) c: l5 R# J  R0 W; V+ R& \& P) C9 B
! N% G  L5 s# v- n6 d

, B" f; q# z' e, i! e, N
2 `; D5 L& H# d) ^
. T2 B. Q5 p# y4 w& W9 r( ~$ H
  s" V; k5 d6 {/ j

) R5 s" }# z& C0 m0 t

3 x6 b3 j& k* @2 |+ I$ B& O配置UART8 G( |! y) k! q: E" G

  P) z4 B& \0 S2 `- l

# a: I' x6 ?" U1 v/ ~2 |2 { 2OE4M$R`38~L@7F$}$RLA3B.png + L4 u5 \1 W0 E

/ x" }7 ?6 G% B# @4 G
9 i+ r/ t$ s" f, y
配置时钟树1 p$ r, `2 m- {8 u% ~
  C" ]- g' k" M; T2 w4 i- {
/ G+ q1 v4 p* z1 N  H, S# d! h2 S
~0HV%~)P44TTQZEA3B[1JQC.png 2 ]% r2 c& A* M) l$ {; q8 a, l

* @: X9 q# t- Y0 j; L
; A, J" ]" J" [+ s4 s1 R

1 \% F- J# f& X
$ G3 u$ c4 l) |2 z1 A( w
设置调试接口  b5 h0 |. }# G* E( J$ }- N
* Y7 S+ c, E  k6 z4 r( i" K( i( B

; D, ^2 d; E% H6 S. A( h' p0 Q+ E 1ZJX$BP9O0GEJAAZ(ALW2$M.png ; o" \" q; h0 f$ A, Z7 D, k

9 E1 Y0 `$ n3 z6 B) _: I
9 U3 n; z/ i7 C+ Z1 ?( u/ F% V3 |- ~8 Z
设置工程并生成工程5 A$ V$ d# |% f  T  K
# b2 \( z: a% t& B

" Y! d, K3 ~1 L% J) j8 | D48WYLW`EFGMDK8D[[{5E7K.png * O9 f. E  ~+ j# X2 I9 a, W( t
9 D6 d/ K$ U6 k; \2 R6 W2 a! w* b

  w1 v& \1 w/ W9 Q52. 移植SFUD串行 Flash 通用驱动库# u- b" }$ i/ G% e/ W- [5 p
SFUD 是什么

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

  • 主要特点:支持 SPI/QSPI 接口、面向对象(同时支持多个 Flash 对象)、可灵活裁剪、扩展性强、支持 4 字节地址
  • 资源占用
    9 y! F1 l! v$ n: P
    • 标准占用:RAM:0.2KB ROM:5.5KB
    • 最小占用:RAM:0.1KB ROM:3.6KB
      ; {! p% I' i+ [- G6 @
  • 设计思路:
    2 [; p5 m# f& W: k) n' v) Y" k
    • 什么是 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 的全部操作。
      1 S$ a' \* K9 n+ v  ~9 |; a
. }' F$ @" _& j0 g
  E+ v8 _: f5 @( v; s; W& [
移植SFUD

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

, C4 J- c( K0 T  K3 Q6 v

CS_RO6]$RS7@YZOD_2GK649.png


  m/ g9 J& ^( |9 x% M) ?) c

将sfud添加到工程目录:


: c  O3 D4 a5 Z

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


( d; T. Q7 n5 U% n6 I7 Y

修改sfud_port.c文件:

  1. #include <string.h>. J5 l% q, X2 h( S6 A% ?( Q
  2. #include <sfud.h>
    - q, \! _0 x# M) `* W3 r
  3. #include <stdarg.h>) c0 F) p+ c9 l1 Q+ r' ?! O3 L  i
  4. #include "gpio.h"6 [& w0 P8 `/ R% ~0 X. j# a
  5. #include "spi.h"% p3 ?! [6 F; v) {1 C

  6. . Z) R& D. Y" T  ~8 A3 Q. l
  7. typedef struct {/ @3 F% N( p1 N5 T6 }
  8.     SPI_HandleTypeDef *spix;
    ; D$ `" m1 E# h- g9 P+ [6 |
  9.     GPIO_TypeDef *cs_gpiox;  ]9 f1 K: j  G) c' O$ a  C; X) B
  10.     uint16_t cs_gpio_pin;( U# X2 L! f& ~. [$ M- t6 O
  11. } spi_user_data, *spi_user_data_t;/ g8 j( l/ r) c) T4 v* {9 K" `

  12. . Q# [! G- [2 [( q( ?
  13. static spi_user_data spi1;6 ]8 |6 |- J5 B1 W2 j; g
  14. static char log_buf[256];
    & k0 s: r+ }+ x& B
  15. void sfud_log_debug(const char *file, const long line, const char *format, ...);
    6 f: l+ I, J% s( n. i8 {
  16. extern int rt_vsnprintf(char *buf, int size, const char *fmt, va_list args);& }, X' b7 G( ~$ n
  17. extern int rt_kprintf(const char *fmt, ...);0 ^* q! \% }! r3 I4 d8 N
  18. static void spi_lock(const sfud_spi *spi)
    & C1 w0 \! N+ F) w% {$ v
  19. {; O1 F) |! T; v" r: k. o
  20. " a0 s. V: ~) J# e4 W. b
  21. }
    0 O5 o! r2 t- K+ b
  22. / B, W$ V* H" e/ n
  23. static void spi_unlock(const sfud_spi *spi)
    % z& _/ _3 L  C+ Y
  24. {+ h* _" I4 O1 c' z4 ^

  25. ( E/ j0 S$ }7 e
  26. }
    . V$ l9 x/ A3 U9 I: s4 \, Q
  27. /* about 100 microsecond delay */  _% w0 }% D, P. ]9 V: T
  28. static void delay_100us(void) {
    . s& f1 [' K2 u5 F* W
  29.     uint32_t delay = 2000;3 @: H$ j+ |, k8 c" {( z* }* L
  30.     while(delay--);* J& h& c  w; H8 G  ?
  31. }
    1 s1 J3 E  Z/ S2 [1 o
  32. /**) X" L, F' B1 k2 ?3 P
  33. * SPI write data then read data$ ]# y' U" \9 Q( ?( J) m4 Q! G3 ^
  34. */
    2 C8 s. k7 j& G6 A" L# x3 Y
  35. static sfud_err spi_write_read(const sfud_spi *spi, const uint8_t *write_buf, size_t write_size, uint8_t *read_buf,
    $ U! U6 x& r1 }$ G1 P, M( u* ~
  36.                                size_t read_size)8 B' k, F! j' ~  L
  37. {0 p% L, o1 c7 H! s" S
  38.     sfud_err result = SFUD_SUCCESS;/ n( k* e6 L$ B/ y0 T9 ^+ }' [8 o
  39.     /**
    $ a0 ~+ l6 Z* g1 W4 U( `: w- a
  40.      * add your spi write and read code
    2 S( ]1 u5 R3 p/ a! X. T: ?& G+ \7 \  t
  41.      */
    & n- _  @" W6 {
  42.     spi_user_data_t spi_dev = (spi_user_data_t) spi->user_data;0 K6 B% }8 P! U2 V
  43. 9 Z: C% d! i0 p
  44.     HAL_GPIO_WritePin(spi_dev->cs_gpiox, spi_dev->cs_gpio_pin,GPIO_PIN_RESET);
    , X1 F7 D/ q3 t8 \" s4 {
  45.     if (write_size) {8 j8 C5 X2 O" A
  46.         HAL_SPI_Transmit(spi_dev->spix, (uint8_t *)write_buf,write_size,1);
    7 ?0 y# `( ]) V0 ]- o
  47.     }
    & Z+ Y- R) C8 L$ A6 r  E2 Y
  48.     if (read_size) {. H4 f& b- N6 x: I; Q1 e
  49.         HAL_SPI_Receive(spi_dev->spix, read_buf,read_size,1);8 r3 J7 E  Y/ F+ i
  50.     }
    7 H( A# p; F5 A3 T
  51. exit:
    7 i/ P5 S0 q, q
  52.     HAL_GPIO_WritePin(spi_dev->cs_gpiox, spi_dev->cs_gpio_pin,GPIO_PIN_SET);6 e/ A0 S/ S# |0 F7 [
  53.     return result;( [, s. c$ j+ H- B7 n/ C- G$ G
  54. }! c9 _3 [8 [6 I- _1 v: p
  55. . Z7 F2 u, |! N1 l+ `
  56. sfud_err sfud_spi_port_init(sfud_flash *flash)
    2 `1 c% @1 O7 m8 g  x
  57. {
    8 |' C2 h, B; u
  58.     sfud_err result = SFUD_SUCCESS;
    3 X' @! ^0 D1 z3 I; {
  59. 3 N0 Q  x% y: C% e
  60.     switch (flash->index) {
    ! v6 i  I8 I9 \( l! S& Q) l( B5 W: x
  61.         case SFUD_W25Q128_DEVICE_INDEX: {: F  G- J6 h+ ]8 u5 T
  62.             spi1.spix = &hspi1;5 W4 g/ |/ b" ~  T+ P* C; z+ X9 s
  63.             spi1.cs_gpiox = GPIOA;
    ) Q6 E2 I* G# x: P; }
  64.             spi1.cs_gpio_pin = GPIO_PIN_4;, S* G1 g. A7 }  `% n9 v
  65.             /* 同步 Flash 移植所需的接口及数据 */8 ], ?, y" ?8 ?# w7 n6 ]
  66.             flash->spi.wr = spi_write_read;" ]2 a6 ?+ }1 E9 ?; P% H
  67.             flash->spi.lock = spi_lock;* q, K0 a% ~9 h' M3 h6 z/ J
  68.             flash->spi.unlock = spi_unlock;
    $ _7 w) k' Y6 {9 I7 n, R5 W9 C; e
  69.             flash->spi.user_data = &spi1;
    4 A( V9 R' X: p+ P
  70.             /* about 100 microsecond delay */( Z. w$ j8 t& g+ q, e) T6 p; x
  71.             flash->retry.delay = delay_100us;5 O% U7 V/ x* f. s
  72.             /* adout 60 seconds timeout */
    ; Q6 B  [- f) t/ I" s* Z
  73.             flash->retry.times = 60 * 10000;
    / n& ]( I0 e+ k7 b+ |1 ~
  74. ; }" e3 ]. v9 M; v+ N3 L
  75.             break;
    1 ]/ m- q% s6 Z  @3 B" t
  76.         }9 l- X2 b, P% |8 V  z% O/ [
  77.     }7 X  N* v4 j/ ]8 u4 O

  78. 1 C8 ^9 o: G# Z- f3 E* E
  79.     return result;- [7 h4 ^0 s" u8 w
  80. }# o& A. c" C9 {8 N

  81. ! h9 A# N& |% E8 d: r+ P
  82. void sfud_log_debug(const char *file, const long line, const char *format, ...) {9 F8 ~- y5 S" Y1 d
  83.     va_list args;- D# h: u2 u* Z, s& i& J3 f

  84. : W& e$ h* Q0 \: J/ G
  85.     /* args point to the first variable parameter */
    , @3 o; K# D& i% G( N9 u
  86.     va_start(args, format);! ]7 X3 \  U1 _  ]3 j, h5 G7 N% ~7 \
  87.     rt_kprintf("[SFUD](%s:%ld) ", file, line);! u- I# \( S. Q8 t) b! S
  88.     /* must use vprintf to print */: e  s7 A0 `( k7 c6 o
  89.     rt_vsnprintf(log_buf, sizeof(log_buf), format, args);
    * o% z: s+ a' U, B: ?. Z6 U. i( P$ u
  90.     rt_kprintf("%s\r\n", log_buf);& F3 n' E% B1 K
  91.     va_end(args);
    7 U+ U5 W6 F, }
  92. }
    * C8 h! S8 \  @4 \8 l
  93.   Z+ D0 b5 F/ C, L& r: S8 {$ X2 y, i
  94. void sfud_log_info(const char *format, ...) {# |2 q/ D& v, L
  95.     va_list args;
    / T: J$ |" q5 o9 ~" k" }) h9 F
  96. 6 W! ~" {+ Z2 P! N1 U/ p
  97.     /* args point to the first variable parameter */
    ) m$ m. i) S. c- i
  98.     va_start(args, format);& @/ z5 K: h  f- c. N5 A, Q
  99.     rt_kprintf("[SFUD]");
    * X, E: `' h7 [# b0 v$ V
  100.     /* must use vprintf to print */6 R5 ]1 S  _1 j5 k
  101.     rt_vsnprintf(log_buf, sizeof(log_buf), format, args);
    / x0 {( J+ ?# ]5 \
  102.     rt_kprintf("%s\r\n", log_buf);
    5 _! v. p/ v8 @0 r" f$ [: ^
  103.     va_end(args);
    6 q0 x7 e" \- A& r" `
  104. }
    & A3 C7 V0 M! G
复制代码
2 r0 u4 x! k2 ~$ G2 m2 w4 ^4 Z( t
$ a! n0 g2 {8 E" R& _. n+ p
测试SFUD

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

  1. /* USER CODE END Header */
    2 O: |; \- E  V. f7 [
  2. /* Includes ------------------------------------------------------------------*/9 u0 k  A, X6 ~* B7 b/ ]) w
  3. #include "main.h"1 l- L5 M- g2 @. `
  4. #include "spi.h"
    8 O, A1 m" @3 v" C; D) k6 o
  5. #include "usart.h"
    " k  r+ T# F; `: l( G
  6. #include "gpio.h"7 c" t$ {" w$ [3 m9 y6 T) V

  7. ' `; e3 d8 }( I' s2 r+ Q
  8. /* Private function prototypes -----------------------------------------------*/! c* Y6 l9 \) o* ~5 X
  9. void SystemClock_Config(void);) A  l! \6 y% [# H
  10. static void MPU_Config(void);( C, T( `1 X$ c
  11. /* USER CODE BEGIN PFP */
    2 E$ o6 f5 j* O) t
  12. extern int rt_kprintf(const char *fmt, ...);% J# `1 D% _- p
  13. #include "sfud.h"7 M( T  }2 W0 r. u& d% e7 }
  14. /* USER CODE END PFP */, b& n/ h" f# B* t5 q
  15. 2 o3 \" f* K, B0 r9 m
  16. /* Private user code ---------------------------------------------------------*// M8 f1 A# w% u0 ~  N0 g
  17. /* USER CODE BEGIN 0 */
    + M2 [1 c' o; {5 N: M
  18. #define SFUD_DEMO_TEST_BUFFER_SIZE                     1024: [6 X- u" t% T3 u0 f

  19. . t- {) @; U6 ~2 ^, a
  20. static uint8_t sfud_demo_test_buf[SFUD_DEMO_TEST_BUFFER_SIZE];
    ' w' I9 u# N8 w+ Z9 @  U
  21. /**
    9 m. \* d7 J2 g! u
  22. * SFUD demo for the first flash device test.5 f+ u, t* x5 C
  23. *+ w  L  D) S% K. I: Y0 _1 Q9 O
  24. * @param addr flash start address' {+ {9 t- L: Y
  25. * @param size test flash size
    " Q) E) i# W1 F. Q" Y
  26. * @param size test flash data buffer2 j# k  ]' p# u( ]
  27. */
    7 A7 s, V. G+ u7 A' }5 E
  28. static void sfud_demo(uint32_t addr, size_t size, uint8_t *data) {0 }+ E) N* h& r9 k& j
  29.     sfud_err result = SFUD_SUCCESS;( [* i) O: _) h) z* N" j
  30.     const sfud_flash *flash = sfud_get_device_table() + 0;
    6 L. [) k' a- ~8 `+ l, ?( u
  31.     size_t i;8 c7 a9 B" M9 R
  32.     /* prepare write data */
    . M# B2 m! d( \* f9 }
  33.     for (i = 0; i < size; i++) {- ~$ M; v2 D. R9 D  |8 {6 h
  34.         data[i] = i;
    3 d6 ^+ b0 X4 H0 g, u5 z* A( e
  35.     }
    $ r% r5 y3 \% [) L/ _/ k
  36.     /* erase test */5 P8 m' N5 @, V; {
  37.     result = sfud_erase(flash, addr, size);
    * ^* r% q0 P: y
  38.     if (result == SFUD_SUCCESS) {) l4 f" G9 V: ^
  39.         rt_kprintf("Erase the %s flash data finish. Start from 0x%08X, size is %d.\r\n", flash->name, addr,% R) Y) D' A- o: ~% {  z
  40.                 size);
    ) R! C/ W2 [& R, A% r# y9 {, r
  41.     } else {
    & G2 Z4 s+ N3 e: k: @( N5 d! j) l
  42.         rt_kprintf("Erase the %s flash data failed.\r\n", flash->name);
    5 f0 a7 P  b8 H( v
  43.         return;& h# q+ r4 |" B. O8 t/ S" d. H: X8 G) t
  44.     }
    $ o; m& R6 @+ b# {+ t
  45.     /* write test */
    7 i: S- d. R8 J$ Q8 V  F7 O
  46.     result = sfud_write(flash, addr, size, data);/ x6 @$ ^" Q$ k2 d4 F2 M- H
  47.     if (result == SFUD_SUCCESS) {8 L! C* A  J8 k
  48.         rt_kprintf("Write the %s flash data finish. Start from 0x%08X, size is %d.\r\n", flash->name, addr,& o% T0 Z5 D5 M* S
  49.                 size);
    8 B. z! n% K$ t  f' g
  50.     } else {
    ! B, m/ W- h: A& X' P9 u
  51.         rt_kprintf("Write the %s flash data failed.\r\n", flash->name);
    # h5 v+ ?! b0 X1 W: X$ l' f
  52.         return;
    7 O4 O( v$ Y* [. z+ H
  53.     }; U9 z) U$ t" U" d5 c' I
  54.     /* read test */
    7 _" v5 A4 K- _5 P
  55.     result = sfud_read(flash, addr, size, data);: Q2 F0 H7 R1 u8 f. t$ v
  56.     if (result == SFUD_SUCCESS) {
    4 |/ J  X8 O1 f4 W' l. X7 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,
    7 j7 S* }: M9 o. P% d- D. }- [
  58.                 size);7 j. h: {2 J+ U# H  `$ P
  59.         rt_kprintf("Offset (h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\r\n");1 |# e5 ~1 x; M  W- k
  60.         for (i = 0; i < size; i++) {
    3 d6 d- f) W7 \9 \* p' Z
  61.             if (i % 16 == 0) {! o6 M6 N' v; D8 U+ l# f; ~( l9 T: a
  62.                 rt_kprintf("[%08X] ", addr + i);" N; n. w1 T( c9 F6 f* d5 @3 ]
  63.             }/ P' {% ?: o% F; t8 F
  64.             rt_kprintf("%02X ", data[i]);
    * Y  t3 B3 A& q% Z8 w4 J
  65.             if (((i + 1) % 16 == 0) || i == size - 1) {5 \  |7 t$ |& {; w" f
  66.                 rt_kprintf("\r\n");
    4 }8 ?! f! H  v
  67.             }
    / [5 ], E: Z2 D& }; d, ?6 _$ f
  68.         }- g8 J  Y4 c' I( l6 W: k
  69.         rt_kprintf("\r\n");& z: \1 ?) V; `
  70.     } else {
    + D  q/ s# \: B
  71.         rt_kprintf("Read the %s flash data failed.\r\n", flash->name);
    7 M% b2 J0 U& M) Y" e
  72.     }+ O7 m# g: c1 @9 Q
  73.     /* data check */
    + t5 Q; z( i, Z
  74.     for (i = 0; i < size; i++) {
    & i- \* g) n/ r1 B' x* f2 F- Z  l% Q
  75.         if (data[i] != i % 256) {
    , H" o8 Q% f/ ]( M: m' D
  76.             rt_kprintf("Read and check write data has an error. Write the %s flash data failed.\r\n", flash->name);
    ! o/ E7 L  J+ v$ E  F; O
  77.    break;! _6 u% O9 g5 z  U' j
  78.         }
      L/ K% M& _* i- ?6 W2 V2 u9 g1 T
  79.     }
    2 u& ~# g. U& @/ a/ t4 R8 f9 U
  80.     if (i == size) {
    & t9 k% j4 c  l' ]2 C, I
  81.         rt_kprintf("The %s flash test is success.\r\n", flash->name);
    0 e% [, e# q# o/ p
  82.     }
      {4 D5 C6 u" n7 \/ Z  U
  83. }4 x+ r8 U! q2 c7 e9 w9 D

  84. 1 \2 L' a! }1 X' {9 w% A1 h1 a
  85. /* USER CODE END 0 */7 B* j0 T. n. ]; b  A# Z) u
  86. 6 B* U) V( p# m( V( n
  87. int main(void)
    $ ^1 c( T! K: n. I
  88. {) O9 Z8 ^, v" N6 @9 z

  89. 9 z2 K. ~. a. u5 a
  90.   /* MPU Configuration--------------------------------------------------------*/
    2 v. w% I8 i5 b; r
  91.   MPU_Config();; a/ G0 N& ^2 p7 B- s% L( q' L
  92. $ u: a( P" D9 ?
  93.   /* MCU Configuration--------------------------------------------------------*/
      ]" G) x* R" Z& \0 P3 P) m
  94. - \; R/ f" A: f+ W. S) J
  95.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    , B& P& _5 _" A1 [4 [+ @/ |5 g
  96.   HAL_Init();# n2 `; O" O# o( i5 n, n
  97. 9 t) \0 L3 H2 w- N" I
  98.   SystemClock_Config();
    9 w  ~4 \0 m: e$ k7 S, A

  99. 3 |) N- |& j, ~
  100.   MX_GPIO_Init();
    2 a5 A0 f+ {$ f: I
  101.   MX_SPI1_Init();
    8 c* T' c5 Z( i0 ?
  102.   MX_UART4_Init();# A1 t, D  N6 B% o4 M
  103.   /* USER CODE BEGIN 2 */3 P" R7 d& W4 d) N* ~6 r
  104.   if (sfud_init() == SFUD_SUCCESS) {2 Z9 o  D. f5 Z/ \! \% B* `
  105.       sfud_demo(0, sizeof(sfud_demo_test_buf), sfud_demo_test_buf);1 m; H# e& @. A
  106.   }% N; F; Y6 Y) ^

  107. 0 @" @5 A! H' B  V
  108.   while (1)
    . M2 }( G1 W  O4 {0 C
  109.   {
    ) D: e# {) w# Q: q
  110. 3 @) J% ?0 h3 p* b$ \9 A- j! G
  111.   }
    5 l: Q" }7 ^! m$ Y) C
  112. ; z8 t7 S% ^' X1 s3 f
  113. }% d3 D8 E* v) f) y: n( h; f( _

  114. + c" b: s  T) A- W8 P* w" r3 M2 h
  115. #endif /* USE_FULL_ASSERT */
复制代码

运行如下:


; K. T" T6 m) a1 Q

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


. y" t. L) q8 q' q( a

63. 制作下载算法
5 P7 c8 A9 `- J. r( ~重新生成不带main函数的工程
% G/ Z' \  U6 J' u: v/ Y$ p: i
9 e+ C) z$ m2 Z# ]( h
FM5({[5%Y2KW1XJDT3ZR)N9.png
- T' h; ?' w1 Z, G+ [; z& _% h9 Z( q: W2 N. @& A
添加修改编程算法文件FlashPrg.c

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

  1. #include "FlashOS.H"* v' l+ |; j  d7 h
  2. #include "sfud.h") \6 w6 n3 o5 k( [9 @
  3. #include "gpio.h"
    - k+ E8 ~; [" N  h/ W
  4. #include "usart.h"5 o: h. G* ]  ^2 u* L
  5. #include "spi.h"
    . B; |- b7 ~1 V; X: m+ V$ N  j

  6. ( ?! V- M) H" w  e  K1 A+ K
  7. static uint32_t base_adr;
      d  U  }/ q3 Y

  8. % o4 i5 Z6 t, k4 E. Q8 M+ q
  9. /** I' |# S3 m1 n3 k
  10. *  Initialize Flash Programming Functions
    % I4 m& N5 f1 C, x/ y* Z8 T0 j
  11. *    Parameter:      adr:  Device Base Address
    ' G1 Y' c' h9 w, `8 g* S
  12. *                    clk:  Clock Frequency (Hz)
    ! M1 x/ {, \$ {$ E8 D  J+ T
  13. *                    fnc:  Function Code (1 - Erase, 2 - Program, 3 - Verify)# l0 S2 K6 Y  P# M2 A9 V* `
  14. *    Return Value:   0 - OK,  1 - Failed
    * \. }: \5 v# f- a1 p5 S
  15. */5 ~1 }/ ^7 A* t" @( \6 v
  16. 5 u) `% F) F/ k# X& ?' k
  17. #if defined FLASH_MEM || defined FLASH_OTP6 G8 t; W* V$ j
  18. int Init (unsigned long adr, unsigned long clk, unsigned long fnc)
    + U! f2 V; f3 C5 K2 t% U
  19. {
    1 Z' D) n& r+ g
  20.     MX_GPIO_Init();
    # a* d5 N2 g+ p7 z. y. b2 \
  21.     MX_UART4_Init();& e# W3 U/ Q5 U: T) Y
  22.     MX_SPI1_Init();4 w% \7 Y, B; G: c2 h
  23.     base_adr = adr;5 y: p+ Y& D, V4 a! Q2 x9 K
  24.     if(sfud_init() == SFUD_SUCCESS) {" n0 [5 t2 |3 j; q0 k% y" q2 c  W
  25.         return 0;0 S' G( i$ D! l! E
  26.     } else {
    8 o, p4 k# D. e3 L6 g
  27.         return 1;7 |4 V- r7 v+ e7 N; }
  28.     }
    0 O  E. O1 }" x8 L. Z/ M$ P1 W( Y
  29. }( q3 e( U" N, O' w  X
  30. #endif
    ! N' ?2 b5 v- T1 y  W

  31. 3 @% F1 G, i8 A3 F3 i- G2 K
  32. ; t1 E0 C- e7 i& V8 n8 ], y3 b
  33. /*/ u2 v, n  i. o$ y% d
  34. *  De-Initialize Flash Programming Functions$ f: Q) W* o" m; O, o$ M$ C
  35. *    Parameter:      fnc:  Function Code (1 - Erase, 2 - Program, 3 - Verify), W' y' X) b. K
  36. *    Return Value:   0 - OK,  1 - Failed
    ! H) p8 i) N6 b' a/ d- a0 [2 |  g8 l
  37. */
    - k" D# I& P7 Y5 L' M5 ^3 u, |

  38. 3 w5 C3 c! a: G1 o
  39. #if defined FLASH_MEM || defined FLASH_OTP+ y) W6 S8 \5 T9 [
  40. int UnInit (unsigned long fnc)  }" O1 v/ W% s+ [+ b: P8 G
  41. {: M( m' W* S, X3 A0 `+ Z
  42. 3 L  K/ T$ L0 y$ {9 y
  43.     return (0);
    ' w' [' m" h) Z( v( Q7 l% @: U4 f
  44. }/ W4 n9 r& ~' I
  45. #endif
    6 [  Q  {8 A3 X, x

  46. ' r2 e; Q# \. `* W) H
  47. /*
    - H% V: k4 E  p
  48. *  Erase complete Flash Memory8 H4 y) r" g! j, e
  49. *    Return Value:   0 - OK,  1 - Failed
    2 b4 l4 n- |9 [5 ~8 `
  50. */, v" a0 {6 z$ G1 h

  51. ; a2 l8 P8 h4 \" m& b
  52. int EraseChip (void)
    ) P& x1 m) r& W1 i( h6 n
  53. {
    - P6 O/ B' B" Q; p: n2 Y7 q3 k
  54.     int result = 0;1 x2 ?* ?6 }+ E
  55.     const sfud_flash *flash = sfud_get_device_table();/ p/ }, C4 Z# E& K" u
  56.     /* Add your Code */
    : I' B. g1 B: H7 G; @
  57.     result = sfud_erase (flash, 0, flash->chip.capacity);) w0 l" z# l1 g

  58. ' Y" g+ y) N$ w2 i/ y5 e: j6 ~
  59.     if (result == SFUD_SUCCESS)
    9 d) a/ Y* Q2 f
  60.         return 0;4 t! q4 b7 u+ g  Z
  61.     else
    3 r; b* m" w9 m0 B2 b& R
  62.         return result;                                  // Finished without Errors0 c7 z1 n  @; [0 }: _5 T( e
  63. }
    ) s( t- Q; p# Z" a! d  m
  64. , x. _* ~2 S  i6 v% T  D, k" ?
  65. /*
    $ U" ^! A+ i2 G
  66. *  Erase Sector in Flash Memory0 O- P& a% [2 L/ C. s( H% c
  67. *    Parameter:      adr:  Sector Address0 o3 J3 |) ~( l8 x5 Y- }# W
  68. *    Return Value:   0 - OK,  1 - Failed8 ~1 I, {1 ~% U$ i& J7 C
  69. */
    % w6 @5 V; M$ `' l: U. A

  70. $ a7 q4 v4 q8 z, f; _
  71. #ifdef FLASH_MEM
    ' z0 |" j8 s' N* Q% W- @
  72. int EraseSector (unsigned long adr)
    . G7 s1 q$ i) V4 F& T* P
  73. {* o5 C, r' e' p8 @, l( F
  74.     int result = 0;
    + l! Y+ X( i# }4 K1 E
  75.     uint32_t block_start;- ~+ G# o- B2 M( U; p" H/ J+ F  }# W
  76.     const sfud_flash *flash;5 Z# L! u8 M& v+ p+ f% Q
  77.     flash  = sfud_get_device_table();
    $ {7 [- z! W0 K4 u, n9 h
  78.     block_start  = adr - base_adr;
    ; T' n- o2 Y& a' W
  79.     result = sfud_erase (flash, block_start, 4096);
    * s/ m; }8 @0 J3 e" `% p3 j9 O/ p

  80. 8 b$ ]( Q) Q. C; |' N4 ?
  81.     if (result == SFUD_SUCCESS)2 U1 T7 a7 p  X; M
  82.         return 0;
    - n$ h9 c  m6 }8 r1 q* o4 K( _
  83.     else! p; O7 c1 J8 s( I5 P
  84.         return result;4 j  v5 S! r; N5 A" D1 P, V
  85. }$ B$ T( ^0 ]+ P( i
  86. #endif
    $ b  f# O* L* _( o; a
  87. , L# ]8 F% e5 K) e. y

  88. 2 P% T' V  q5 s2 d1 z
  89. /*8 ?1 ^- {# ~% Y! p0 ~# a3 C
  90. *  Program Page in Flash Memory0 l5 i$ ^+ k  A8 G: n
  91. *    Parameter:      adr:  Page Start Address
    ! ~2 A7 u8 h0 N: |) E# j. L3 b
  92. *                    sz:   Page Size
    : y( Q, E: |& E. V; @
  93. *                    buf:  Page Data4 K* _4 i' |( r+ J. v! n- q4 N3 O
  94. *    Return Value:   0 - OK,  1 - Failed
    : z$ C) Q* Q9 @2 H  i
  95. */) w8 X* D7 k, N" d7 z

  96. 7 @& G  l1 f9 z8 O2 n; l1 j+ k
  97. #if defined FLASH_MEM || defined FLASH_OTP
    ) ]* [. H1 w5 |
  98. int ProgramPage (unsigned long block_start, unsigned long size, unsigned char *buffer)
    ' ^" }* k9 s2 q. Y' G9 ?; l. H( A; ^
  99. {1 Q. P+ B/ Q- k) Z6 i* \# I$ r+ Z( i
  100.     const sfud_flash *flash = sfud_get_device_table() + 0;. Z7 I1 y+ @3 K2 c- V
  101.     uint32_t start_addr = block_start - base_adr;2 @" d9 P( O% Z# j
  102. 4 e) m: J1 c" [* s9 ^. C" E
  103.     if(sfud_write(flash, start_addr, size, buffer) == SFUD_SUCCESS)
      ~3 T2 C7 w7 v
  104.         return 0;" }7 q+ w1 {7 {) |% g
  105.     else2 M# T! s" X7 I; a
  106.         return 1;' m. D2 ~$ f& [" D4 D2 M4 |
  107. }4 `# S9 y$ z0 x) P9 u, R

  108. 3 U8 I7 k. k  {/ u) d4 A

  109. 2 I+ I# m# Y  p' I- [
  110. #define PAGE_SIZE            4096
    & G- e9 @9 v# D+ o
  111. uint8_t aux_buf[PAGE_SIZE];& O/ ~0 o4 O% D1 _5 G, V1 n0 _
  112. unsigned long Verify (unsigned long adr, unsigned long sz, unsigned char *buf)
    0 X5 o$ S! ~% \
  113. {
    9 L* |  m, v# D1 k% ]$ r
  114.     int i;
    , I" D9 p' a) o7 [( w; u& w
  115.     const sfud_flash *flash = sfud_get_device_table();* T2 z- i% l3 |  A# L; O6 q
  116.     sfud_read(flash, adr - base_adr, sz, aux_buf);
    ( S  i/ r9 [* N# k; Y: y
  117. ) k3 p; g# T' Y& U9 j  u3 R5 m9 \
  118.     for (i = 0; i < PAGE_SIZE; i++) {
    ' \% Z. O/ ?- h( W  X, E; O
  119.         if (aux_buf[i] != buf[i])
    3 C/ v4 ~" ?  a) P. I
  120.             return (adr + i);                 // Verification Failed (return address)2 ?6 B& V1 {* Z2 r& q8 ?
  121.     }  r, p* K- G" c
  122. ' y. \' }' Z0 N; N' O" \7 V" a. B, M. Q
  123.     return (adr + sz);                    // Done successfully9 Q- @7 V  B5 c6 H7 f
  124. }
    1 H3 p' d9 r- V4 c; d: R
  125. % e: D2 W& R! k: B
  126. #endif
复制代码

( V2 [- P7 U3 b2 `. b2 Y: i9 i4 O
0 [1 @6 r$ A2 }; j) |0 y

在工程中定义FLASH_MEM宏


5 p" i7 m( c$ l# N9 \# X

微信图片_20230220211259.png

, i. ]4 R( I. e  M" j# G/ O

添加修改配置文件FlashDev.c

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

  1. #include "FlashOS.H"        - k) u# y2 L  M! B, j7 R3 J4 A2 C- l
  2. 0 {" Z; z' M8 f  x0 T2 i5 q8 i( u
  3. #ifdef FLASH_MEM& o# P- z5 V5 T
  4. struct FlashDevice const FlashDevice  =  {* j  k( G; C; B) L$ n' X. t
  5.    FLASH_DRV_VERS,             // Driver Version, do not modify!
    9 e/ Z& h( Q: t; m% p' ]
  6.    "STM32H750-ARTPI",          // Device Name 9 y% K% Y! ~2 n2 g1 |: Y
  7.    EXTSPI,                     // Device Type
    : f6 b5 z* h/ o' M" D
  8.    0x90000000,                 // Device Start Address3 A1 @9 j# K% d
  9.    0x08000000,                 // Device Size in Bytes (128MB)6 \# ], Z. M0 ~6 r+ U
  10.    0x00001000,                 // Programming Page Size 4096 Bytes- C+ h9 w; h. ?' L' u
  11.    0x00,                       // Reserved, must be 0
    + b6 A5 R  u- v5 D
  12.    0xFF,                       // Initial Content of Erased Memory
    " ~- S- U1 I. i( x: u* S* M1 k/ l
  13.    10000,                      // Program Page Timeout 100 mSec
    ' ]3 ]# F5 r6 t) h1 V/ J& l
  14.    6000,                       // Erase Sector Timeout 6000 mSec
    , u* y; {. {) k8 ?* d; O$ B2 D$ K

  15. - ?% l" ]8 {2 C! D5 C# K5 N; _, {
  16. // Specify Size and Address of Sectors; d5 [2 o9 M: [& R- d7 h5 T: V
  17.    0x1000, 0x000000,            // Sector Size  4kB
    1 f" R2 R  a7 P& N0 {
  18.    SECTOR_END
    - O- o6 B% t) ~( r" n4 D
  19. };
    $ x' j; _  X+ L
  20. #endif // FLASH_MEM
复制代码

# Q' ^6 W/ {" X- F* L$ i+ C+ E

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

, W& E9 Z2 o# T: I' ?; c4 i9 r) o

地址无关代码实现

C和汇编的配置勾选上:

! O' q8 J& d  R) f

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

9 n) i6 y6 d5 |' z1 n) P' B

ROPI地址无关实现

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

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

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

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

2 O. z7 e9 X4 e. @5 Q+ j% [

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

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

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


( h' C1 S# W" l& N& ?! L

特别注意:

  • 由于模块中不含中断向量表,所以程序中不要开启任何中断。
  • startup_stm32h750xx.s不再需要参与编译2 ]. c- Z3 {/ \- I& G/ i! ]0 p
% ]& h- H8 K  M
& `; \% d7 f' s: q6 b+ A4 u
微信图片_20230220205842.png % K5 u% h1 [3 K8 Z! S: w7 r+ {. p3 b
* g5 R+ K' a. n% `
  y- A1 u# {& |, t  o3 j# r
修改分散加载文件

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


, x) j% e( o# c/ ^: y# f/ ?

J2(7FVO7MLDYI5VA15HGJ(A.png

7 }! c/ e, r9 f7 z

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

  1. ; Linker Control File (scatter-loading)" B4 j( S+ B# S( V1 u. M  Y# J
  2. ;7 N2 d2 Y- l* P8 @
  3. 2 w5 T6 P1 u% ]* O1 [
  4. PRG 0 PI               ; Programming Functions
    8 L/ a4 r2 Z( D/ M( T( \% k  p% p
  5. {
    0 x7 H3 O+ H7 L2 a8 f' D
  6.   PrgCode +0           ; Code; C! e5 N: e* H8 k, o8 E) W3 Y
  7.   {
    . n( [2 F. }& I. {
  8.     * (+RO)& W6 p- G4 g; U! [" b3 L
  9.   }
    * s! \0 V) Q. v, m5 Z: l
  10.   PrgData +0           ; Data8 {' l* L+ P2 D* X6 \
  11.   {" t& q0 d* j( ?' D( Q) d
  12.     * (+RW,+ZI)
    8 k8 ?0 Q" q+ [" v# ]# T
  13.   }" `6 m+ s4 n/ x) `3 D
  14. }
    # h' ^6 C8 ^( c8 R% E

  15. ! n9 h0 n3 K: M  \  _9 l
  16. DSCR +0                ; Device Description
    & e# B, D, K7 I) p
  17. {2 C! ~6 Y% \6 W
  18.   DevDscr +0. P0 ?# i; }* k1 C
  19.   {% J$ Y/ _( h7 T1 C# z5 n
  20.     FlashDev.o
    ! h1 z( ?6 n0 G6 Q( x. b  ^5 v
  21.   }
    - [; ~# s; k: n, k# j' I
  22. }
复制代码

3 O" ]0 b- V# n
将程序可执行文件axf修改为flm格式

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

: ^6 l: |# H, N) a( @+ u' z

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

5 S+ \! q% P; ?( S- u% y( C, Y/ v4 I" Z

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

; [' s+ W$ J. Z- ^: L6 }% z
完整版请查看:附件6 j0 K, u; _: n# }5 y  n9 l& d3 k

9 }( \* i# c/ X: q  c& M9 K
赞 收藏 评论1 发布时间:2023-2-20 21:04

举报

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

可以分享附件吗?

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版