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

详解 stm32 在线 IAP 升级

[复制链接]
STMCU小助手 发布时间:2022-12-14 14:24
本文主要讲解在线升级IAP的基础知识, 主要是针对IAP从原理分析, 分区划分, 到代码编写和实验验证等过程阐述这一过程. 帮助大家加深对在线升级的认识。
+ V9 N  D0 O. k7 h4 W' R2 i$ z" {* k
1.在线升级知识  r+ y0 S$ O; k7 R7 X. b  b8 v
什么是BootLoader?  E# ^* {3 j; L' r8 C8 b, @# c
BootLoader可以理解成是引导程序, 它的作用是启动正式的App应用程序. 换言之, BootLoader是一个程序,App也是一个程序,BootLoader程序是用于启动App程序的.
& e  Y  t% c! L1 V
' P8 R3 q# j/ d2 z+ ySTM32中的程序在哪儿?9 O* ]2 T4 l3 j9 j( p/ q
正常情况下, 我们写的程序都是放在STM32片内Flash中(暂不考虑外扩Flash). 我们写的代码最终会变成二进制文件, 放进Flash中 感兴趣的话可以在Keil>>>Debug>>>Memory中查看, 右边Memory窗口存储的就是代码$ l4 r  s: L8 g; ?2 x

5 Q8 E5 ]" q& g4 ^) f1 q 微信图片_20221214142442.png
& A' d4 h/ |, R$ \
2 I0 b$ S2 E8 ?接下来就可以进入正题了.6 \% `# d3 J, [% Z
5 M5 j6 L$ e3 g4 P+ T6 G, N9 ?
进行分区

/ q; E- q" @, K* m) m( X( q0 o既然我们写的程序都会变成二进制文件存放到Flash中, 那么我们就可以进一步对我们程序进行分区. 我使用的是F103RB-NUCLEO开发板,他的Flash一共128页, 每页1K.见下图:
  h: @0 c% K& Z- C$ \: |: [' ?6 p$ }: X, r- j1 O/ _
微信图片_20221214142437.png - _9 `, n, `7 v* _5 g7 c: I
+ S, K( i( v' Q1 C
以它为例, 我将它分为三个区.BootLoader区、 App1区、App2区(备份区)具体划分如下图:
( x. K, U: G  @  x# X$ M7 JBootLoader区存放启动代码1 L4 {6 K; j1 L
App1区存放应用代码
* S' t9 z7 l* I' _0 e% wApp2区存放暂存的升级代码1 ]& ^5 [# T3 x0 S* Q) Z; Y

, h& U( x) |! g+ b
微信图片_20221214142434.png 2 m& j2 W3 h/ L; w/ Y. g: n" z

/ K" _% |+ z! x' o3 g" _5 T总体流程图
& C* k# ^* O5 k! g3 u
先执行BootLoader程序, 先去检查APP2区有没有程序, 如果有就将App2区(备份区)的程序拷贝到App1区, 然后再跳转去执行App1的程序.
' B& Z2 N# N% ]) v然后执行App1程序, 因为BootLoader和App1这两个程序的向量表不一样, 所以跳转到App1之后第一步是先去更改程序的向量表. 然后再去执行其他的应用程序.
1 A& Y, x+ a! J. m: Q/ V5 W9 l在应用程序里面会加入程序升级的部分, 这部分主要工作是拿到升级程序, 然后将他们放到App2区(备份区), 以便下次启动的时候通过BootLoader更新App1的程序. 流程图如下图所示:
6 _+ r' B6 J, s% @& Q( u( h1 o. k/ G1 |$ n9 b+ B/ n
微信图片_20221214142430.png
7 O: C  s/ `+ m5 r9 G1 H' ~  g. }4 E
% |" s. m; ~; h0 ]; \

9 }2 \1 ?, \4 ]' [2. BootLoader的编写
5 k/ K* T2 r4 R& s  t7 Y; z本节主要讲解在线升级的BooLoader的编写,我将以我例程的BootLoader为例, 讲解BootLoader(文末会提供免费的代码下载链接),其他的大体上原理都差不多。6 l3 ]5 Z1 Q5 [7 H3 R
# Q, M" K% L2 m: o1 {8 O# M
流程图分析2 N9 e5 @# Q+ Z: g; O  a) b
以我例程的BootLoader为例:& e6 c5 b. g$ f$ I8 q4 s% J9 r: K7 l
1 r+ G  w5 N  ~& X/ J
我将App2区的最后一个字节(0x0801FFFC)用来表示App2区是否有升级程序, STM32在擦除之后Flash的数据存放的都是0xFFFFFFFF, 如果有, 我们将这个地址存放0xAAAAAAAA. 具体的流程图见下图所示% ^( a/ S9 o; l$ ?4 Z
) {" K! E5 g- E3 U
微信图片_20221214142425.png ) i. w" W0 J$ h: d, P7 X) ]. _

$ I' _8 l& i. _( r6 e+ ?! V) f
$ Z- o" L6 r! E  X+ @. N- @  m
程序编写和分析* N9 E  Z# n/ o2 d; k; }% t- S
所需STM32的资源有:6 y" t6 w7 Z; F0 U, r
发送USART数据和printf重定向
7 m, W4 ?4 X& v! ^7 W0 s# zFlash的读写4 I% [1 f' T! ]5 Y, O* ]5 }
程序跳转指令,可以参考如下代码:
$ q. h; c1 z' o
' P/ {7 W# I* q# F* a
  1. /* 采用汇编设置栈的值 */, F6 X6 ~6 {- @# H3 {, m2 \
  2. __asm void MSR_MSP (uint32_t ulAddr)  O" n4 b  s3 q- m
  3. {
    , I- E3 a9 o" F" {6 q$ b
  4.     MSR MSP, r0   //设置Main Stack的值) m, e6 A6 ?+ Z; I0 j8 [+ q: |! J
  5.     BX r14
    4 c3 N; \3 \( K& X/ b: p
  6. }
    2 @" j1 D8 X+ k+ u! |. Z& P2 \

  7. 6 m8 l$ `( E5 m5 F( I
  8. /* 程序跳转函数 */. v& }, ^( C5 Q2 e+ N* U. S% l
  9. typedef void (*Jump_Fun)(void);
    9 ~- z" G1 l: p- Z- W
  10. void IAP_ExecuteApp (uint32_t App_Addr)8 R& u: `1 j( h, b) B
  11. {0 D6 J$ v) a# b6 F( e$ @
  12.     Jump_Fun JumpToApp;- v7 C% L" q: D- E5 V

  13. 6 ?9 m/ L. y; ^; r% O
  14.     if ( ( ( * ( __IO uint32_t * ) App_Addr ) & 0x2FFE0000 ) == 0x20000000 )  //检查栈顶地址是否合法.  E3 w) U, ^0 B$ ]. o, m
  15.     {4 M' ~0 l, h4 b; x1 f' [
  16.         JumpToApp = (Jump_Fun) * ( __IO uint32_t *)(App_Addr + 4);  //用户代码区第二个字为程序开始地址(复位地址)
    1 `: k  n( R9 I0 e) s  Z3 J
  17.         MSR_MSP( * ( __IO uint32_t * ) App_Addr );                  //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
    1 Z* {4 N3 W; r
  18.         JumpToApp();                                                //跳转到APP.
    - m5 r( j0 B! E# G- U1 Y' g2 V  ^; n
  19.     }
    & h0 k; l, D" ?' k# M
  20. }
复制代码
. o0 a- Y! `" _4 K; E" b4 D! r
在需要跳转的地方执行这个函数就可以了IAP_ExecuteApp(Application_1_Addr);
. B9 e' j1 @5 K/ D% z. I) |其他的代码请参考BootLoader源代码
9 G9 y, N1 B1 v1 J1 s- I8 A
3. APP的编写
7 H1 h  Y. x5 R' y
本节主要讲解在线升级(OTA)的App1的编写以及整个流程的说明,我将以我例程的App为例, 采用Ymodem协议进行串口传输,讲解App的编写(后面会提供免费的代码下载链接), 其他的协议原理大体上都差不多, 都是通过某种协议拿到升级的代码。# ^( }# s6 u! j/ |6 q" O# H

& W; b: J. p6 L流程图分析
9 M, I3 _2 D6 {4 N& q" U5 e7 C以我例程的App1为例:' ]+ N) b' ^4 M* {% ?0 X$ {& R

" {7 R- p1 U1 E
微信图片_20221214142419.png
9 ]2 T6 l8 j& i* N9 ~  p

# W" Y4 S/ V+ a( C2 c# D% }& q4 G先修改向量表, 因为本程序是由BootLoader跳转过来的, 不修改向量表后面会出现问题;7 U4 ?; c# F6 w) a/ k
打印版本信息, 方便查看不同的App版本;8 [  X! u2 r" y
本例程的升级程序采用串口的Ymoderm协议进行传输bin文件. 具体的流程图见下图所示:
' F) U, ]( Z4 a( ]" M" X  y1 {) K8 b6 k
程序编写和分析
. ]+ Y+ t5 Y3 F" i所需STM32的资源有:
, N, \% k; \' Y( P. }发送USART数据和printf重定向. l8 K" a! s" c  h* P3 r
Flash的读写6 d, Q1 A  Z5 y! u" n5 _9 }
串口的DMA收发6 N. ^9 ?* Q# H- A3 o
YModem协议相关; {6 ?" x* \, Q5 z" `. b9 Y
Ymodem协议
' v6 w# }- R% v8 z/ Z( z' L: X& j8 N百度百科[Ymodem协议]* a- P% d' t/ o, c3 c+ l
具体流程可自行查找相关文档, 这儿提供一个我找到的 XYmodem.pdf(文末和源码一起提供).
& r; x. r: F. p" F- [Ymodem协议相关介绍可参考我的这篇教程 YModem介绍
7 ^4 W, N4 y' _2 j! R, a

# d# j/ g; _0 I. Y- {代码分析3 z7 v) J( t5 k+ n' o: R2 r1 I+ A5 u
代码大多数都是通过串口实现Ymodem协议的接收, 这儿就不详细说明' K! L, w( V' e6 |, @4 F) y
' w" v' f4 a  p( P7 n
后面放了我的源代码, 详情请参考我的源代码." g5 T7 P0 c$ V! x' H
: U1 v6 l. o' q9 W
主函数添加修改向量表的指令- l9 W9 _: r+ N$ M! }
0 W  Y6 [: [6 [$ Y) u8 a
0 ~  T% A+ t( `
微信图片_20221214142329.png
( O  |- }, }$ H
4 ~, _, Z1 W# ~5 {
打印版本信息以及跳转指令3 G% _5 R) `* M$ E: ~/ I8 T. d, \

* E& s# z0 g- ]; v 微信图片_20221214142322.png % e, Y/ G9 R( j0 _9 `
% k6 L9 S$ X+ l9 o
YModem相关的文件接收部分
0 r3 D: `/ p% d: u
  1. /**& d6 G& Q5 P& q9 \7 y- ~
  2. * @bieaf YModem升级! o( l! d. C! C$ Q% Y& H
  3. *
    3 A: W4 g9 ^& J0 e
  4. * @param none* j" I. G  N9 m$ p
  5. * @return none' v$ f# a' [- N  j
  6. */8 i# A" B8 N% _& x* a7 x2 ?0 m
  7. void ymodem_fun(void)3 v( F4 |, c5 g5 R
  8. {' D; G4 T: \- W! `
  9.     int i;
    + O* K5 L. C$ |! l1 U9 T
  10.     if(Get_state()==TO_START)
    ! {% t: Q$ O$ U# h- K
  11.     {
    - i5 C. Y4 g. B$ l# k+ T
  12.         send_command(CCC);4 Q% m, l6 t7 z( k! J! m! g/ c
  13.         HAL_Delay(1000);
      \6 L9 c( N6 V$ ?" x$ w+ s
  14.     }
    ( d6 h8 }/ b# c$ m% o& Z; {
  15.     if(Rx_Flag)        // Receive flag; E9 x6 v; X2 c7 @
  16.     {
    . m3 x1 ?! T( k+ ^; o: d6 P7 h) Z/ `7 @
  17.         Rx_Flag=0;    // clean flag' E! @+ u( p' v# Z2 Q" O4 O

  18. - w0 H: s9 z, e2 ?: k- k: U: b
  19.         /* 拷贝 */% N; s8 b3 P3 A, v0 I
  20.         temp_len = Rx_Len;/ t9 D; E5 v! E& c  z; ^
  21.         for(i = 0; i < temp_len; i++)2 ^, |) R) [6 e- S3 M' y
  22.         {
    % R) J) ~8 Q3 @
  23.             temp_buf[i] = Rx_Buf[i];
    % O* u) m5 m, v. I2 m4 }' c
  24.         }" O+ c/ _0 I! ^9 I) W7 `

  25. * i* Y0 J0 }& d) y5 N( n. \
  26.         switch(temp_buf[0])2 D6 o1 H# ]5 h8 c6 d: O$ `
  27.         {7 h/ K, n& X% C) q0 n# h
  28.             case SOH:///<数据包开始
    7 u  V# [( P6 N4 p  W( ~
  29.             {
    $ b* H3 M. i& x6 g2 Q
  30.                 static unsigned char data_state = 0;* S1 c$ Q8 N. a2 C# {* f! x+ t* s
  31.                 static unsigned int app2_size = 0;
    6 k8 q, z6 _  L7 |! R1 y* d
  32.                 if(Check_CRC(temp_buf, temp_len)==1)///< 通过CRC16校验
    & v* n2 y8 X, f# ]: u
  33.                 {
      L8 y+ y4 h7 A0 d) y+ a  I: d
  34.                     if((Get_state()==TO_START)&&(temp_buf[1] == 0x00)&&(temp_buf[2] == (unsigned char)(~temp_buf[1])))///< 开始( ~! Z# @- T6 s) c6 _2 i+ P) A/ E
  35.                     {1 v' a) c9 n5 {# E7 i8 m
  36.                         printf("> Receive start...\r\n");
    6 X( J7 g0 \: t. V/ L

  37. . V% b! ~- [: P5 ^! H
  38.                         Set_state(TO_RECEIVE_DATA);
    * ^' a. _4 q4 ^/ n1 ^/ s
  39.                         data_state = 0x01;
    - g4 u; `. k/ d5 V! W
  40.                         send_command(ACK);7 v9 \! |. C6 H8 C8 m) [
  41.                         send_command(CCC);
    7 W! ?2 s& V% Q1 M- w! p; q( V

  42. 7 f; y* N+ ^- ^: ~
  43.                         /* 擦除App2 */: W8 o9 }- x6 c+ h! `( Z
  44.                         Erase_page(Application_2_Addr, 40);
    7 C! ~3 D% f5 m2 L0 J7 d$ L4 c
  45.                     }0 D* U- ^% s* W- T, h/ X6 T
  46.                     else if((Get_state()==TO_RECEIVE_END)&&(temp_buf[1] == 0x00)&&(temp_buf[2] == (unsigned char)(~temp_buf[1])))///< 结束0 W) @' W" B' a; c" h5 D
  47.                     {
    ' \, H2 K1 z' }2 I' O
  48.                         printf("> Receive end...\r\n");0 S/ |5 w) B; @- i7 V. v6 C
  49. . g  ^$ R  W8 V
  50.                         Set_Update_Down();
    ' k+ {) w! g6 h8 A! [: X9 A
  51.                         Set_state(TO_START);; F2 |& p6 z! u# ~6 q7 S) V4 t
  52.                         send_command(ACK);* t8 y$ K0 t1 \1 O" J6 H& g3 ]
  53.                         HAL_NVIC_SystemReset();4 C5 B% w& {1 `3 {  R0 m
  54.                     }
    , ^  U; k, Z+ X# U
  55.                     else if((Get_state()==TO_RECEIVE_DATA)&&(temp_buf[1] == data_state)&&(temp_buf[2] == (unsigned char)(~temp_buf[1])))///< 接收数据/ b; H" o0 d2 t1 F6 ^
  56.                     {
    ) o- S( I# O5 w2 t4 r2 F
  57.                         printf("> Receive data bag:%d byte\r\n",data_state * 128);; K( U- R& `+ O; F+ Q+ p" t& ~
  58. 9 I5 _: E8 s1 p- p2 U
  59.                         /* 烧录程序 */+ |4 X9 z0 S+ k1 c# g5 Z! F" n- {
  60.                         WriteFlash((Application_2_Addr + (data_state-1) * 128), (uint32_t *)(&temp_buf[3]), 32);
    8 I, e- }' X' p$ Q9 _* w
  61.                         data_state++;
    4 k' p, Y. v' `6 |$ z

  62. " _3 u$ E7 ^% O0 o
  63.                         send_command(ACK);; D  R; _6 S: ~9 E2 _3 X; U& B7 M' j
  64.                     }
    # G; P* i# G; @. A+ O
  65.                 }9 P6 d- e# o, c4 e- l! o3 \
  66.                 else8 N1 }" M8 D# l  o
  67.                 {
    " n( B3 q& l; V: V# \2 O" j
  68.                     printf("> Notpass crc\r\n");
    # q  a. j' C: q: ]5 g0 {
  69.                 }; G% E/ Z$ }' d5 |  a( [& h

  70. # y9 P6 F1 y% u. b$ |2 ]5 R) F% i
  71.             }break;
      l  l4 ?: i4 e& c6 ?) ^; P; H
  72.             case EOT://数据包开始
    ' j6 [; t8 a0 K! z* q
  73.             {
    ( e; w8 C! f9 k
  74.                 if(Get_state()==TO_RECEIVE_DATA)
    3 K  M7 I6 a/ J9 r) h- c' P
  75.                 {
    - b+ J, P8 {/ g3 W
  76.                     printf("> Receive EOT1...\r\n");) l3 j# B" k$ K3 h+ L2 a; I$ Y

  77. ( j4 i5 s- |! N! ~+ B2 t
  78.                     Set_state(TO_RECEIVE_EOT2);
      Q. M" I4 w5 r" `) b$ h- u2 b
  79.                     send_command(NACK);( v4 [) v. o; u
  80.                 }! \4 X7 z. R, G, @- J9 j5 R" j
  81.                 else if(Get_state()==TO_RECEIVE_EOT2)
    ( a& @( a! G# w* s: c7 s4 B
  82.                 {6 h9 B1 ^+ h6 R! w
  83.                     printf("> Receive EOT2...\r\n");
    ( \% v0 m6 P1 T: y, _* j
  84. % {7 k, @( u. w/ F
  85.                     Set_state(TO_RECEIVE_END);
    0 w1 U  V5 b+ n( J% E
  86.                     send_command(ACK);4 |( |2 P, f% G: g
  87.                     send_command(CCC);
    . L1 @7 _; O! W
  88.                 }! v# H8 q# o1 H1 L- B
  89.                 else
    2 f/ E9 W* ^2 t8 R- N
  90.                 {
    / N5 h( r: r- d
  91.                     printf("> Receive EOT, But error...\r\n");' e4 n7 n9 \$ P& P7 `1 {& P6 G
  92.                 }% m! }: J3 ]2 j$ [! e$ h3 Z
  93.             }break;
    * W' O' K/ L$ @6 _
  94.         }
    " K! V% q- ^" E0 S- G" `8 U
  95.     }6 Z- t/ y" m- |, }5 a- R4 r
  96. }
复制代码
* p6 N3 i$ ]& f* B- I
其中部分函数未在以上代码中展现, 详情请参看文末给出的源码链接.& F! W% i6 x: n7 B) X( k. Y0 J' }
( }6 e2 U) O! I% ?+ g) I
4. 整体测试2 a9 q6 _: Q) D6 N2 r
本节主要对前三节的教程做测试验证 BootLoader + App的升级功能。
  L% X9 E2 b* l1 w6 D. Y
6 u7 X. f+ |5 E6 Y" J; ?7 I: u8 f代码的下载
/ x8 |/ `/ _7 x) ]0 @2 T: Q由下图可知两份代码的下载区域是不一样的,所以他们「下载的区域也不一样」。6 @- k" X  n. n6 f$ e! p0 |

, c5 W; W) C, v* v0 h. g
微信图片_20221214142309.png
  L) j6 V) I7 o3 L* }0 _

- R. b' }4 @5 G1 L' ^& tBootLoader的下载& }* `# W6 y, N3 Z- ~; D
BootLoader的代码默认是最开始的所以不需要特别设置代码的下载位置
" X; c0 X" n6 o7 V4 B/ K按照下图, 修改擦除方式为Erase Sectors, 大小限制在0X5000(20K). k$ R; ]8 I, x! ]8 a; F
2 B, C/ Y9 y( z/ Z* Y5 w% v' H9 [* N
微信图片_20221214142249.png
% [$ j4 }, P5 R5 M, n4 S1 `- O& i+ ]0 V% Y, ~" u6 z, ]
烧录代码
; |0 X+ F/ Q- h% U运行, 通过串口1打印输出, 会看到以下打印消息9 |' |! n- n& j& C
说明BootLoader已经成功运行$ y$ n, `: e" P  W

/ U- _: `- D7 k" C6 Q0 | 微信图片_20221214142234.png 5 W/ [" g4 i: y

" [. O; h4 ~: @) ^! R) }App1的下载
  g# @! w/ C* o. a) V) _9 gApp1稍微复杂一点, 需要将代码的起始位置设置为0x08005000
6 {  a: k! G5 X& c. M% v同时也要修改擦除方式为Erase Sectors, 见下图( a6 w# n5 h9 f. [8 Y8 a

$ [+ a  L0 ?2 Y/ f6 P
微信图片_20221214142224.png
8 k' E+ Y2 G- S# Q8 ?+ C
1 z% O- O7 N7 |8 K# w. ^: Q: q
微信图片_20221214142220.png
; M! x$ Q2 R7 @2 R1 L
3 h- r+ j9 b; \! {, Y# v烧录代码1 H: o/ B: H! ^# V
运行, 通过串口1打印输出, 会看到以下打印消息! [/ s+ G) J) k: {- I/ x
说明BootLoader已经成功跳转到版本号为0.0.1的App1$ k' H* {' k9 T. J
/ e! |0 K5 d9 Y( _7 _/ U
微信图片_20221214142153.png
/ o1 g; P+ D7 n9 g  W- R/ v( U

4 G2 x' A/ Y2 d" j+ L: n生成App2的.bin文件7 s6 \5 }- P! V- c
修改代码, 把版本号改为0.0.2, 并且编译并且生成.bin文件( t9 W$ G4 m2 o! v4 U; ]

+ H! H$ }! Q4 D: n+ L) C生成好之后你会得到一个.bin结尾的文件, 这就是我们待会儿YModem要传输的文件5 J0 C) q9 \, C% x1 b7 H

- N! V% B9 d1 H( B 微信图片_20221214142148.png 7 ^7 ]! t) }$ Z( F% U7 d0 I5 J

$ t- r$ I0 R5 v' k- s; A3 T& m使用Xshell进行文件传输
7 l' G- [5 V6 b; Y$ R打开Xshell
( P3 S! O$ B9 h: J8 l代码中, 串口1进行调试信息的打印, 串口2进行YModem升级的. Y. C- b$ W$ z! p. J
所以使用Xshell打开串口2进行文件传输, 串口1则可以通过串口调试助手查看调试消息. k6 J" a  D+ X

  y* P- o2 m0 T. E3 L1 H; A# W 微信图片_20221214142114.png   ~$ R- E5 o( w' ?9 P9 m  q3 y

/ b" i0 ]+ Q7 H/ l6 O8 }你会看到App的版本成功升级到0.0.2了.% E& h$ _& N% \& B$ p
如果你到了这一步., E* j) r/ F4 _2 i: n0 H' O
那么恭喜你! 你已经能够使用在线升级了!
. m4 E; L! T$ e+ Q$ @9 x9 i
4 t9 D, a/ @2 |% Z0 ~5. 总结' D5 q) |+ Y7 K: k
通过本几节的教程,想必你已经会使用在线升级了,只要原理知道了其他的问题都可以迎刃而解了,除了使用YModem协议传输.bin文件,你还可以通过蓝牙、WIFI等其他协议传输,只要能够将.bin文件传输过去,那其他的部分原理都差不多。- n! `- z# [. `4 `3 a* f% Q4 X
2 s5 {# {0 M8 ?& \- ^, ]0 G
$ N) k8 e0 V' e3 R# T. ~5 Q$ R$ ~, R

7 y4 \5 `/ U; {3 Y/ o转载自:混说Linux
* f: r0 M) Q, \9 k3 I" T4 O3 g0 p1 e3 {
( J! D2 P2 Y, `  G. D. ?
赞 收藏 评论1 发布时间:2022-12-14 14:24

举报

1个回答
1+1=2 回答时间:2022-12-14 21:07:32
帖子分析的挺好的,但是有些地方好像没有说,比如从boot跳转到APP1的时候是否需要关中断?在APP1初始化的时候,除了修改栈地址,还需要做其他的吗?  A8 f3 Q9 F6 A- z* [

所属标签

相似技术帖

官网相关资源

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