首先需要使用STM32CubeProgrammer软件对芯片的模式进行配置。
`1 O, v0 }1 Z
) ?4 _: p2 [7 E1 B$ B) `
连接上芯片后,选择OB选型卡,找到User Configuration% j# I* O4 A. Q3 n: u
2 [4 w8 E1 M$ [
将其中的TZEN选项打上对号,使用Apply写入到芯片。* y8 H) L: u. ]) J; b9 A5 T& X
8 K& w- a8 g5 j X
- c/ C6 F# Z% ~: f, g+ S* J
如图所示配置Secure Area 1与Secure Area 2选项,使用Apply写入到芯片。
* W: o, w( t& O
. q. \5 C5 Y2 r0 Z3 p; n! D2 @0 ^; D0 G& b. k7 y: G
打开STM32CubeMX,找到STM32U585AI,这一次就要选择第二项开启TrustZone了。
7 w& A) A& i# ~" j$ t( K8 v
' E8 w: r8 \3 O! p7 |7 f. V4 g- Z8 o; b7 W3 m
看看新的外设界面,嗯,与之前大大不同啊。
: O% k5 p+ g5 H" u) D+ _
1 V8 \8 W; y, u# k
1 ^" m) n1 T f O% Q& G9 w简单配一下时钟。
% S: N d, T+ \8 w1 O
: a: H2 W5 p# U& ?
& s" P4 Z" i5 r* b* G3 ]7 W- C配一下SWD,这里就让他使用安全区域那边的初始化。
- e" R+ V3 O) q
4 U0 c1 J- C" I: H. s( I
" B3 |4 t8 R0 P& Y$ U3 |4 Y& A配一下IO,就是板子上的两个小灯,一个配置到安全区域、一个配置到非安全区域。
" u' A4 [7 l# A6 U0 E
G0 X/ c3 u7 [; I- z; t# Y
! ]/ X- X2 x* [! j) K4 [
生成代码,打开keil,嚯,两个工程啊(工程之间的区别以后再聊)。! F: ?+ H2 |; i, J, g5 f
, K# O! a2 t3 i$ `4 j( z3 ^6 ~& x4 s9 }* i0 o Y% d( _
右键可以切换选中工程。5 x6 y6 J8 x, S
- D5 @ d3 h/ g* h) G) c6 y
4 N7 N p' U# L" Q5 O& v9 ~看看代码8 s: h4 s O! _2 d- t: T. P! `
安全区域的GPIO初始化
5 A8 i$ N5 M7 |! q2 w- void MX_GPIO_Init(void)
" P0 B1 {/ l0 X% [ - {
4 J- [) w" k7 _6 p) ]& p - : c' O3 o; t3 i$ S6 p& D5 @
- GPIO_InitTypeDef GPIO_InitStruct = {0}; l: n3 q+ G/ p. B$ C' g4 t0 i3 z
- H+ ^* X3 M2 b3 h1 m0 y) M
- /* GPIO Ports Clock Enable */1 P3 g: o0 E7 K0 a
- __HAL_RCC_GPIOA_CLK_ENABLE();3 x5 a0 g8 \5 |4 B
- __HAL_RCC_GPIOH_CLK_ENABLE();/ ]6 X2 K4 Z! m% N, Z% g
- ! _- j9 l5 X" S
- /*Configure GPIO pin Output Level */
+ t/ ^4 Y+ J7 G - HAL_GPIO_WritePin(GPIOH, GPIO_PIN_7, GPIO_PIN_RESET);
$ R2 U" M2 B) h9 m! `) f' S7 W
% B- k4 m. B# x/ w g. o- /*IO attributes management functions */
/ t7 m. b4 o( R - HAL_GPIO_ConfigPinAttributes(GPIOH, GPIO_PIN_6, GPIO_PIN_NSEC);; k) i' x; S s5 |8 ~6 C
- # O0 ]' ?. t: T$ ~2 g9 g- b
- /*Configure GPIO pin : PH7 */ q: ?( N# n! x) i
- GPIO_InitStruct.Pin = GPIO_PIN_7;
/ c, l0 w( b- w+ T. T3 @* z* ^+ [ - GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;: D5 n( ~9 X7 G7 b5 t3 W0 i, {5 z( U
- GPIO_InitStruct.Pull = GPIO_NOPULL;8 x, Z* _6 n. B, N3 O9 _6 n% h4 d
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
( |9 m' K' F( w* S5 o - HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);8 r1 O' p4 o8 g! v; h
- 1 n) V1 M- c, _; i( ~5 Z
- }
复制代码 2 U1 ~+ Q' i6 `' T* E
非安全区域的GPIO初始化
- c- U' c A. y& }* ^# c' V- void MX_GPIO_Init(void)5 B! j! T4 [, H: Y0 _
- {; I8 }5 A5 C V7 r$ b0 Z$ o
- ! O. ^0 g; p' ]* ] Y D$ C
- GPIO_InitTypeDef GPIO_InitStruct = {0};
8 y5 [" H6 J' p$ W - + q( g+ Q* _5 l0 S- ?
- /* GPIO Ports Clock Enable */8 l; ?4 {1 {! Z9 M: z1 _
- __HAL_RCC_GPIOH_CLK_ENABLE();
: E6 g3 n1 v- ]% o
8 z; |9 r' x0 L3 n) T- /*Configure GPIO pin Output Level */# ~7 _! h( t0 e; z
- HAL_GPIO_WritePin(GPIOH, GPIO_PIN_6, GPIO_PIN_RESET);
! A7 Z1 I# ^/ R3 K- _1 H
9 f: V, R( I4 r+ p- /*Configure GPIO pin : PH6 *// V3 G1 n6 R' c4 O% O0 r
- GPIO_InitStruct.Pin = GPIO_PIN_6;: `2 B2 o2 @# o: o
- GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;" O- f& Q& j9 F' E) w
- GPIO_InitStruct.Pull = GPIO_NOPULL;/ \- d( e" ~' b; z7 @* c6 N! A! ?/ w5 J
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
" w" c7 w, K- p1 D' O P: m: ~9 F - HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);
. E" E* ?- U! E9 }' N8 d% ~3 Q% a - & b9 t2 S$ N. b' r6 N1 H; @
- }
复制代码
5 E$ ?- y+ {, |区分还是很明显的。
" z' }& _# u( s: s. P2 M
8 r4 Y# Y( ]& N! U9 E. H; Y接下来写写代码看看, B2 j4 F, [5 V4 [$ H
安全区域# d+ S, Y" A4 j7 a) d
- while (1)
9 g! H; @% f7 \) | - {
8 D8 ^) }: E% \0 n# F; b2 l9 e2 K* J - HAL_GPIO_TogglePin(GPIOH, GPIO_PIN_7);3 v5 A0 e1 l+ K% v4 K* T
- HAL_Delay(1000);
, }8 _+ L9 U6 h: b; f* ~1 U7 f - /* USER CODE END WHILE */
' p, n" s4 R t* {
8 M7 m+ R, \6 D5 G- /* USER CODE BEGIN 3 */
) @( O! v5 @- M* H& ~ - }
复制代码 ( G- U1 g+ m* v- Q+ T
非安全区域& [" \ J- H7 K: ~ s' _# ~
- while (1)
# L$ K5 l" d! i/ f+ `$ u - {' `% u. T: f5 ]0 ~2 u# s( T
- HAL_GPIO_TogglePin(GPIOH, GPIO_PIN_6);
( i3 T- x! I" \) o' g7 k - HAL_Delay(1000);, u1 _7 g2 Q! p
- /* USER CODE END WHILE */
" {) h2 c$ K7 }9 R
5 s5 T$ R+ f! z" d/ L* J- /* USER CODE BEGIN 3 */
5 O3 T2 [+ Q$ C/ D+ b - }
复制代码
- x! s: u+ g: @! L- n写了两个闪灯的程序,各自是各自的。看看会发生什么。把两个代码都下载到芯片内部。
F3 Z0 A, L/ V. a# k4 |6 C& x& f1 M) v$ h
结果是,非安全区的代码while(1)里面的代码正常执行,而安全区while(1)里面的代码没有正常执行。板卡红灯闪烁,而绿灯常亮(图片看不太出来)。( p' H! `+ L) V2 y) Z% k V, n5 p
! B3 X- j9 J7 D% D2 a u2 ?
原因也很简单,安全区代码是上电之后优先执行的,然后运行到NonSecure_Init,把非安全区堆栈初始化好,然后调用非安全区的复位函数(具体调用方式与逻辑请关注后续文章)。然后代码就跳转到非安全区了。
% R# p1 q& t3 U9 g* L% b
5 s) k; E9 t0 Z也就是说,两套代码,并不是真两个核,内部还是只有一个内核滴。+ T7 w9 m: E/ o0 _0 Y- `) b& s
1 o& z( N" M9 K$ c1 p8 |& i7 ? |
你有测试过吗?M33只是为了安全在NVIC、MPU、SYSTICK等资源提供了双份,本身控制还在在切换安全区与非安全区运行实现的。核心资源只会提供一份的。
- r/ l7 G5 c$ h0 l1 y3 _+ y
用过NXP的LPC55S69 里面有两个M33 ,理解错了
[md]嗯嗯,你说的这一颗芯片比较特殊,他虽然是双核M33,不过仅有第一个核是支持TrustZone的
- C7 f' P0 X" p, ~" J6 m
& I. N! g. ]( z5 x& n! r