23.1 初学者重要提示
8 ]% x% d/ y+ P" [ 本章节主要是为下一章Cache的讲解做个铺垫,需要初学者把本章节涉及到的基础知识点掌握了。+ ^/ A2 o5 @. X( U& S6 g
初学MPU时,可能有些知识点无法一下子就搞明白,在后续章节的各种应用后,会有一个较深的认识。这个知识点基本会贯穿整个教程。" n1 U4 Q; e. U) @
23.2 MPU简介0 H& z. ]8 Z4 s4 J3 Q( ]2 l
MPU可以将memory map内存映射区分为多个具有一定访问规则的区域,通过这些规则可以实现如下功能:+ z2 {# \; r& J% F& j) L
: c7 z, k& v7 v4 M |: T& u
防止不受信任的应用程序访问受保护的内存区域。
9 `4 H. Z q6 D ? 防止用户应用程序破坏操作系统使用的数据。: _, R0 I4 y8 E
通过阻止任务访问其它任务的数据区。4 w0 w; ~2 { x& E
允许将内存区域定义为只读,以便保护重要数据。! R7 D7 a) ?8 ]& s0 p" D: V, j" y2 D; {
检测意外的内存访问。
+ j$ ] Y& P O% l6 c- n& Y. H简单的说就是内存保护、外设保护和代码访问保护。
# p( i1 I/ P! \% H8 v; J. a1 g1 G; _+ f. v) c7 @ O
内存映射
" X2 Z4 G+ t1 m. r2 i内存映射就是32位的CM7内核整体可以寻址的0 到2^32 -1共计4GB的寻址空间。通过这些地址可以访问RAM、Flash、外设等。下面是内存映射的轮廓图,IC厂家使用时,再做细分,添加相应的硬件功能。! L5 H) b9 I3 x, ^- |5 A
' E7 z$ i- Y* L* \4 J* `" S p8 e( @. i& Y+ x
" \ j3 M2 Z- }! g' g$ m# _
23.3 MPU的功能实现
' E$ P( f6 u- z' a; SMPU可以配置保护16个内存区域(这16个内存域是独立配置的),每个区域最小要求256字节,每个区域还可以配置为8个子区域。由于子区域一般都相同大小,这样每个子区域的大小就是32字节,正好跟Cache的Cache Line大小一样。
, W$ B3 m" {/ w/ j0 ?+ |# N$ W9 U
MPU可以配置的16个内存区的序号范围是0到15,还有默认区 default region,也叫作背景区,序号-1。由于这些内存区可以嵌套和重叠,所以这些区域在嵌套或者重叠的时候有个优先级的问题。序号15的优先级最高,以此递减,序号-1,即背景区的优先级最低。这些优先级是固定的。9 E$ R* H' K0 g: V3 B
4 [0 p. Y. f6 X6 l; F( }4 |
下面通过一个具体的实例帮助大家理解。如下所示共有7个区,背景区和序号0-5的区。内存区4跟内存区0和1有重叠部分,那么重叠部分将按照内存区4的配置规则执行;内存区5被完全包含在内存区3里面,那么这部分内存区将按照内存区5的配置规则执行。- W( T5 I* }+ _4 g) U
* `- Y" u9 i) ~( T3 {9 c: j' Q
4 L* q/ ?% N3 {# Q' t* P& _* j& K# b2 i
23.4 MPU可以配置的三种内存类型7 \# Y" V' _7 ~! i& D! p$ O
MPU可以配置的三种内存类型如下:
7 I! ?( U% D; I- N3 C
, Y% P) P* A9 i4 ~9 O Normal memory
* o& W" e# e# N
, t2 }' i1 L& u8 T; @CPU以最高效的方式加载和存储字节、半字和字,对于这种内存区,CPU的加载或存储不一定要按照程序列出的顺序执行。* x t$ L7 p( J- i3 j
' w5 n; k0 s$ x8 f' K4 ~0 V
Device memory' n) M3 R) Q6 {3 o8 ?8 p0 o6 u% x
1 t. a0 [3 j$ j. }+ B O对于这种类型的内存区,加载和存储要严格按照次序进行,这样是为了确保寄存器按照正确顺序设置。
8 @; x% t8 r1 ]0 a5 W* P9 d& u
/ G4 L% m$ X5 x0 [4 U3 i$ B Strongly ordered memory. F9 O% t3 i( C" `
8 a N/ W! |3 y+ Y! S
程序完全按照代码顺序执行,CPU需要等待当前的加载/存储指令执行完毕后才执行下一条指令。这样会导致性能下降。. I1 [6 [/ m$ r5 S3 r; C
0 o2 I- i/ f. D- U5 V. f( z" K- P5 c23.5 MPU的寄存器和对应的库参数
/ i6 {+ [0 W3 \+ j7 @7 h关于MPU的寄存器介绍在STM32H7的编程手册有专门的讲解说明,我们这里重点讲解寄存器MPU_RASR和控制寄存器,此寄存器的定义如下:
% P6 L/ k0 |7 ~6 [
\/ M% l7 t6 S2 Z9 [- b4 a$ T2 i/ d9 Y& z
" X6 L/ E- i; A2 d: x
23.5.1 RASR寄存器的XN位
2 d. ?+ Q, y% ~2 ]( g* _XN=0表示使能指令提取,即这块内存区可以执行程序代码,XN=1表示禁止指令提取,即这块内存区禁止执行程序代码。- G& v# J5 D9 {
: h; F1 p/ i/ w+ c
对应的HAL库MPU参数如下:
) M& B4 ]/ T/ ]3 ~0 W7 \, `8 {" @8 G0 ?8 a$ F, f
- /** @defgroup CORTEX_MPU_Instruction_Access CORTEX MPU Instruction Access# u' R5 \" v. \: h) a
- * @{
$ ^' r7 {5 R1 \. ^5 O9 G, Z - */
* z F$ u+ Q- G9 T+ l - #define MPU_INSTRUCTION_ACCESS_ENABLE ((uint8_t)0x00)7 k+ Z% {' ]& R
- #define MPU_INSTRUCTION_ACCESS_DISABLE ((uint8_t)0x01)
复制代码 0 V, g/ a7 @$ c. j
23.5.2 RASR寄存器的AP位8 l* [5 T9 V1 O! T6 k! N- d. ~2 K' u
AP的具体定义如下:$ M8 X% R4 V/ J1 ~
0 G4 y& D! K- Y
; p! h; G/ G5 \" b+ x6 V Q
0 c# D6 e8 u6 a. z8 u+ l# I: W7 }这几个参数对应的HAL库MPU参数如下:
U2 d+ ?+ G( F1 J& D
& {* z: e6 W% s& f# p, ]- /** @defgroup CORTEX_MPU_Region_Permission_Attributes CORTEX MPU Region Permission Attributes
h8 T( F$ }* j( d8 i% t/ s+ b2 b - * @{( _5 j- m, f& ^# r* P
- */' {6 j1 e( w7 o
- #define MPU_REGION_NO_ACCESS ((uint8_t)0x00)
e3 q- J+ ?; v - #define MPU_REGION_PRIV_RW ((uint8_t)0x01)
+ r `& C& Y9 i7 a# I' W4 | - #define MPU_REGION_PRIV_RW_URO ((uint8_t)0x02)6 X7 e% [3 I8 K7 t- \) o
- #define MPU_REGION_FULL_ACCESS ((uint8_t)0x03)
/ M' V5 p" `2 P1 Q - #define MPU_REGION_PRIV_RO ((uint8_t)0x05)& H0 J, l0 j" ]" A/ z1 b
- #define MPU_REGION_PRIV_RO_URO ((uint8_t)0x06)
复制代码
3 p% g3 Z3 w6 I" c9 S3 \2 a23.5.3 RASR寄存器的TEX,C,B和S位4 ]. ^) _: r. S& Q3 y \
(注,这几个位非常重要,当前先了解知识点即可,下个章节专门讲解具体的作用)
! a% S) `0 S+ Q7 `
6 O! K6 I! O0 h. iTEX,C,B和S的定义如下,这仅关注TEX = 0b000和0b001,其它的TEX配置基本用不到。
' d8 k! n7 H+ p4 h5 }" q# f7 E2 u! d. [7 w" D
) _% s) s P; C! w9 b/ b, r( p
% \0 l, u! F" A9 S1 n) R R* y
TEX用于配置Cache策略,支持如下四种情况,需要配合C和B位的配置才能实现。0 E" z5 x: B4 T- {6 `: F0 M0 }
# s, Z3 S- D9 V# {$ f+ P
2 j# s9 w0 t1 c( k& u; h" K' _7 O( f% s
& l5 V; f- L) c; w7 Y, h. rTEX对应的HAL库MPU参数给了三个,实际应用中仅用到前两个MPU_TEX_LEVEL0和MPU_TEX_LEVEL1
3 U& T4 e/ \7 P
B9 z; R. D! D3 ~- /** @defgroup CORTEX_MPU_TEX_Levels MPU TEX Levels
. d, \4 N# G. E; g1 S V - * @{
. L+ q& l9 y A- A; X+ P - */5 i5 j2 ]+ R0 n
- #define MPU_TEX_LEVEL0 ((uint8_t)0x00)
2 b# E9 C) k- L9 Z - #define MPU_TEX_LEVEL1 ((uint8_t)0x01)
% a& l# m# A; M, B3 l9 M - #define MPU_TEX_LEVEL2 ((uint8_t)0x02)
复制代码 % }: ^9 y r& U: U
C位对应的HAL库MPU参数如下,用于使能或者禁止Cache。$ i- l/ A5 ^% j, V G
$ Z: i& p# s$ m: M* Z! B! ?! e" L- /** @defgroup CORTEX_MPU_Access_Cacheable CORTEX MPU Instruction Access Cacheable
+ T0 d2 |+ [- l. [ - * @{
7 q2 c1 t8 |0 i, J# l - */+ ~2 T" f' q1 \$ s; X" T( H3 S
- #define MPU_ACCESS_CACHEABLE ((uint8_t)0x01)& e$ J: k* M) l; r# a/ H/ K
- #define MPU_ACCESS_NOT_CACHEABLE ((uint8_t)0x00)
复制代码
/ b6 x2 b' m y( z7 ^3 f$ zB位对应的HAL库MPU参数如下,用于配合C位实现Cache模式下是否使用缓冲。$ _1 p! j4 n! K# z! V
2 X, y) l7 v( p- /** @defgroup CORTEX_MPU_Access_Bufferable CORTEX MPU Instruction Access Bufferable# A, v' x! p4 T. f- S
- * @{
( }0 N+ @8 }2 W { - */9 O/ h0 o% b6 |9 V2 Z7 u: m# Y% w/ g
- #define MPU_ACCESS_BUFFERABLE ((uint8_t)0x01)1 K s _* v) Z* ]/ Y
- #define MPU_ACCESS_NOT_BUFFERABLE ((uint8_t)0x00)
复制代码
: Q% Z$ J2 |/ ^* ]2 Z b7 m6 XS位对应的HAL库MPU参数如下,用于解决多总线或者多核访问的共享问题。% {5 t% T/ a' u' ^& Z
0 I/ l3 r: R/ \0 m# R# ^
- /** @defgroup CORTEX_MPU_Access_Shareable CORTEX MPU Instruction Access Shareable; \. z3 e6 O5 V6 s$ Q0 @
- * @{
2 Q: j1 m# l6 v* ] - */
5 r* b- T+ G1 [& | - #define MPU_ACCESS_SHAREABLE ((uint8_t)0x01)
# b7 U; s& T* L0 h D B# L5 W - #define MPU_ACCESS_NOT_SHAREABLE ((uint8_t)0x00)
复制代码 - D, i& ^+ M3 `$ S. y' m
23.5.4 RASR寄存器的SRD位! n0 u0 B$ R3 j, N H, ?' y
这个位用于控制内存区的子区域,使用的是bit[15:8],共计8个bit,一个bit控制一个子区域,0表示使能此子区域,1表示禁止此子区域。* X, A4 ], k' r1 L$ x
: {, p# p) Q, _' Z
一般情况,基本不使用子区域的禁止功能,所以配置HAL库的SubRegionDisable参数时,直接取值0x00即可,表示8个子区域均使能。* S, g [7 v' E+ r: K
( \! w1 S m0 @" o- L, M23.5.5 RASR寄存器的SIZE位$ S" K P" o" _( _* g6 n' l1 @4 `" b: Z
SIZE位使用的是bit[5:1],共计5个bit,可以表示2^5 = 32种大小。 对应的HAL库给出了可以配置的28个参数:
6 a) ]$ _+ u v) z
* X: R Y7 n8 D4 I% v/ Y! v- /** @defgroup CORTEX_MPU_Region_Size CORTEX MPU Region Size
( ]1 \1 I* T. [3 l; O - * @{! i* ]* y- E. q4 M
- */
! ]4 m1 K4 r5 ]% y+ V: V' U - #define MPU_REGION_SIZE_32B ((uint8_t)0x04)
! v4 s, x! d9 L( E: c' J! m - #define MPU_REGION_SIZE_64B ((uint8_t)0x05)
9 Z* z' m& _" E& K9 O5 _2 g - #define MPU_REGION_SIZE_128B ((uint8_t)0x06): r4 ?" A' z6 p# l* R
- #define MPU_REGION_SIZE_256B ((uint8_t)0x07)- n" m1 w/ L- W& |& T# B' }
- #define MPU_REGION_SIZE_512B ((uint8_t)0x08). y. ^. X7 u' A, F
- #define MPU_REGION_SIZE_1KB ((uint8_t)0x09)
$ n; Z: e8 W8 N' G1 I - #define MPU_REGION_SIZE_2KB ((uint8_t)0x0A)- ~5 `/ N6 X7 N# L
- #define MPU_REGION_SIZE_4KB ((uint8_t)0x0B)
$ j" B+ [2 s8 ~3 p7 q- H - #define MPU_REGION_SIZE_8KB ((uint8_t)0x0C)
" C+ N* ]# m& x" R3 k1 \7 T0 F - #define MPU_REGION_SIZE_16KB ((uint8_t)0x0D)
8 `8 p5 e$ w2 w3 p. ]' g - #define MPU_REGION_SIZE_32KB ((uint8_t)0x0E)1 S% K7 k# H) r" ^8 S$ N X1 k
- #define MPU_REGION_SIZE_64KB ((uint8_t)0x0F)) `- W7 e, b8 d- O
- #define MPU_REGION_SIZE_128KB ((uint8_t)0x10)
7 {, N* D5 V3 I* b; `; [, k - #define MPU_REGION_SIZE_256KB ((uint8_t)0x11)
$ o% t+ G" y2 d' T - #define MPU_REGION_SIZE_512KB ((uint8_t)0x12)$ Y0 V* L2 C; W
- #define MPU_REGION_SIZE_1MB ((uint8_t)0x13)1 L. u$ ]% Z: \, F
- #define MPU_REGION_SIZE_2MB ((uint8_t)0x14)# Y4 P1 W( ^3 x% C3 v$ p3 g
- #define MPU_REGION_SIZE_4MB ((uint8_t)0x15)) l1 P5 C K, R; v _: x. P' ^
- #define MPU_REGION_SIZE_8MB ((uint8_t)0x16)
& {. g, b; m# _. x( B' y - #define MPU_REGION_SIZE_16MB ((uint8_t)0x17)
5 h7 e9 a, F, b( n4 q* z. C3 @3 {" C - #define MPU_REGION_SIZE_32MB ((uint8_t)0x18)4 S5 |1 ]- T# ~
- #define MPU_REGION_SIZE_64MB ((uint8_t)0x19); t# J; }# I: _; E; F. v
- #define MPU_REGION_SIZE_128MB ((uint8_t)0x1A)) z! G( W8 ~% K, l. |+ k/ R7 L
- #define MPU_REGION_SIZE_256MB ((uint8_t)0x1B)
/ w8 Q+ P8 ]7 P, p1 B- H+ @ - #define MPU_REGION_SIZE_512MB ((uint8_t)0x1C)- e/ i8 j9 O3 h
- #define MPU_REGION_SIZE_1GB ((uint8_t)0x1D)
$ X7 _( ]8 E' L, i2 J( } - #define MPU_REGION_SIZE_2GB ((uint8_t)0x1E)& k: D2 Z0 E$ v) z7 e" b4 \
- #define MPU_REGION_SIZE_4GB ((uint8_t)0x1F)
复制代码
* L3 w# y& g: N7 A% v9 C23.5.6 CTRL寄存器的各个位) n+ f3 j. n5 D, b
控制寄存器各个位定义如下如下:
/ [- y j; e, |! B& B1 {4 T/ _, P- W( G- _3 T, m
* m0 y+ g S( k+ O6 v U3 P0 H2 h
9 z7 x9 ]7 m8 x6 C23.6 MPU的配置函数
$ Q4 O% ?3 O. d; F$ j1 HHAL库的stm32h7xx_hal_cortex.c文件为MPU的配置提供了三个函数:
! E6 d4 ?' u2 Z' z: K2 O1 ]% ~- m
, n; }3 L6 x7 {; y0 H/ h HAL_MPU_Disable
2 Z- R/ t d' s- ~ HAL_MPU_Enable
) Y$ O( o: c; N( l+ |) B1 | HAL_MPU_ConfigRegion
Z7 ^. d, J2 S6 \6 M& R; T2 N
: p) G5 T1 y: W, ~. ]1 o2 P+ R3 B$ [4 Z
三个函数的使用都比较简单,但是要让配置的内存区最大限度的发挥性能是需要大量的经验积累和测试的。具体工程要具体分析。% K( `/ @( e0 c4 I7 H5 R
* [ L* G' j7 F. K+ r9 c% Q, L23.6.1 函数HAL_MPU_Disable8 V* u+ F+ `9 S9 ~- N
函数原型:9 C. L8 ?1 F% N
t) v0 y! v' Q c9 k- void HAL_MPU_Disable(void)
6 ^( ]$ h' S- v$ n. q - {! `( D9 E4 e v l9 ~ V8 T) p( P
- /* Make sure outstanding transfers are done */4 j8 b8 o4 ~$ p! z) y% ]# ~% p# f
- __DMB();
3 f! x _" J1 T3 M. z9 c' F
2 W: v: ^9 m8 x H# |) n/ r3 _ L4 M- /* Disable fault exceptions */
, c0 j! Y+ C1 d! ~/ q - SCB->SHCSR &= ~SCB_SHCSR_MEMFAULTENA_Msk;/ B4 v3 Y9 U3 a6 |1 n$ E. y. `8 A
/ P& V2 `3 |* O D9 T0 _& B/ W- t- /* Disable the MPU and clear the control register*/ {3 z, c: h. |1 M' R/ Q: p
- MPU->CTRL = 0;
: f, F% Z: I6 F) O' k - }
复制代码
$ L2 W! I% f$ Q# T* U9 ~函数描述:
+ X! m4 P% _9 U" _& X& }; l) S: D* t: U4 V1 t
此函数用于禁止MPU。配置MPU前要优先调用此函数禁止MPU,然后才可以配置。9 l1 u3 `/ i' W, A' O% b
+ ^( ` `8 |5 [+ y3 _% B9 S23.6.2 函数HAL_MPU_Enable
- U. s% |+ R! C2 g函数原型:
/ ?' K' t) |1 l- u$ [. s7 s& p7 L* z% c4 J
- void HAL_MPU_Enable(uint32_t MPU_Control) D: `4 g4 v3 n* L+ H
- {- W7 @" b' D g; A" j5 T R7 ~
- /* Enable the MPU */8 `" @6 i! v. D1 ?
- MPU->CTRL = MPU_Control | MPU_CTRL_ENABLE_Msk;! K7 d G- [3 S( z1 e
- 2 s$ H" Z D n. u
- /* Enable fault exceptions */
' P) _4 c/ e: I) l N& @) k - SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
: a$ o1 e8 @) o- _8 [4 W/ t* t - ) f2 G8 E: g7 x. u4 }
- /* Ensure MPU setting take effects */# `4 @: c. |# d8 \1 @( z
- __DSB();: m6 I# ^3 X, @, x
- __ISB();
9 d2 d! o6 l+ l0 i - }
复制代码
# y7 e" P1 V1 Z U6 i$ ~9 ^) F: i函数描述:
) s$ p$ {5 F) k$ g9 S' r3 x# F, ~/ c- D2 y: I
此函数用于使能MPU,一般情况使用参数MPU_PRIVILEGED_DEFAULT。
& }* a8 B8 [( d! l# \6 r9 @, n4 v( I
函数参数:
3 S6 P7 i; y7 \& O L! Z/ C% Y
" c7 l0 \8 M6 b4 m/ c此函数支持以下几个参数:# o; D* s+ a1 d
/ L2 A, u) M' c9 i1、 MPU_HFNMI_PRIVDEF_NONE ((uint32_t)0x00000000)
" p# b3 v( B8 z1 T- f4 X8 x- u6 Z" G( C A* { T' ^$ h5 F
此参数设置MPU的CTL控制寄存器的PRIVDEFENA位为0。7 q' b5 D9 m3 _6 M5 W9 W) T4 \; k
表示禁止了背景区,访问任何未使能MPU的区域均会造成内存异常MemFault。0 v3 F- s3 l$ s2 t
5 m; @/ x8 K6 a
此参数设置MPU的CTL控制寄存器的HFNMIENA位为0。9 j& U9 h/ b* }: C; j7 ~4 U
表示NMI不可屏蔽中断服务程序和硬件异常中断服务程序执行期间会关闭MPU。
1 T1 G( D \5 `
/ I9 `* A7 v' }% b- Q3 E z2、 MPU_HARDFAULT_NMI ((uint32_t)0x00000002)1 X6 W5 ^! [ R/ S: e2 u* @# T
7 d0 {& M6 N7 X' J5 P
此参数设置MPU的CTL控制寄存器的PRIVDEFENA位为0。
7 v |5 f9 `3 H: o1 f表示禁止了背景区,访问任何未使能MPU的区域均会造成内存异常MemFault。1 s, A, b! `3 @( _ x+ t$ \
3 Y! m. @9 e j7 X' ~ 此参数设置MPU的CTL控制寄存器的HFNMIENA位为1。; y; @; t, ?1 f* U7 l8 D
表示NMI不可屏蔽中断服务程序和硬件异常中断服务程序执行期间会保持继续开启MPU。
1 ^8 j; b7 `6 l
; `! Y) d% e7 S& D u3、 MPU_PRIVILEGED_DEFAULT ((uint32_t)0x00000004); N0 l7 \2 m- d, p
! q& J! z* Z' q0 P0 y: y) S( { 此参数设置MPU的CTL控制寄存器的PRIVDEFENA位为1。0 G$ t2 Q1 `3 c O1 C. l
表示使能了背景区,特权级模式可以正常访问任何未使能MPU的区域。
+ Y0 z( c7 O- F. n% \
+ H6 P: v& i+ B8 \7 I 此参数设置MPU的CTL控制寄存器的HFNMIENA位为0。
9 W& g Z9 S4 C! T6 T表示NMI不可屏蔽中断服务程序和硬件异常中断服务程序执行期间会关闭MPU。! N) f8 `; q: m, T$ Q
1 U9 _) }8 Z# { A4、 MPU_HFNMI_PRIVDEF ((uint32_t)0x00000006)2 k* k, Q) v' d: L2 T% Y( J k
( u/ c; k' b* O; P* F4 `
此参数设置MPU的CTL控制寄存器的PRIVDEFENA位为1。
! D7 l+ \; E- O. ^表示禁止了背景区,访问任何未使能MPU的区域均会造成内存异常MemFault。! A! u7 A% o2 h& ~
, B% ]1 Q/ ~7 ?8 Z! j 此参数设置MPU的CTL控制寄存器的HFNMIENA位为1。
% P7 q0 \/ o, E1 M- Q表示NMI不可屏蔽中断服务程序和硬件异常中断服务程序执行期间会保持继续开启MPU。
7 t* y8 g8 }- [2 g7 w+ q2 \4 t+ F7 t! }: \" ~
23.6.3 函数HAL_MPU_ConfigRegion) ?, n' \; J: d" T) e
函数原型:: S* U$ f, W# e; G+ J# ^
# h* F% C( X7 Y0 {( E$ {6 G
- void HAL_MPU_ConfigRegion(MPU_Region_InitTypeDef *MPU_Init)
$ V; N: w2 h: p5 i - {$ h, p. G% j) K! F% v& n- u% X
- /* Check the parameters */: z- V+ V2 i* n% Q6 ]9 \
- assert_param(IS_MPU_REGION_NUMBER(MPU_Init->Number));' ~/ D$ ?% y# }/ V% Z6 s
- assert_param(IS_MPU_REGION_ENABLE(MPU_Init->Enable));
]& ^( V; l2 u5 W
F2 o( f2 l/ |4 k2 A0 `9 E1 |- /* Set the Region number */* ]; U6 Q5 H1 ?8 D4 X+ }% S3 \
- MPU->RNR = MPU_Init->Number;1 z$ i! L% |. W9 h- E: |) @9 S
! q5 x; _* q6 w$ ~5 n# ?4 s- if ((MPU_Init->Enable) != RESET)
7 i3 J5 E! r4 f2 |) i3 k - {+ M9 I* }4 q) T" ?( D$ M. t
- /* Check the parameters */
& W2 |9 `7 L# _* o6 ?4 j Z - assert_param(IS_MPU_INSTRUCTION_ACCESS(MPU_Init->DisableExec));
( }/ V4 k! }$ ~8 _' } - assert_param(IS_MPU_REGION_PERMISSION_ATTRIBUTE(MPU_Init->AccessPermission));
$ n) |5 ]& t& U2 p5 w' S - assert_param(IS_MPU_TEX_LEVEL(MPU_Init->TypeExtField));5 L6 G- O7 i& ~; q2 I% f( X
- assert_param(IS_MPU_ACCESS_SHAREABLE(MPU_Init->IsShareable));
- v, \$ G9 _ r' g. C - assert_param(IS_MPU_ACCESS_CACHEABLE(MPU_Init->IsCacheable));6 P- o1 D, g3 f1 ?! h7 L9 _; f
- assert_param(IS_MPU_ACCESS_BUFFERABLE(MPU_Init->IsBufferable));3 @4 N$ h5 J, g, U5 H( c2 j
- assert_param(IS_MPU_SUB_REGION_DISABLE(MPU_Init->SubRegionDisable));! O) D9 }% t4 A. J; ~4 q
- assert_param(IS_MPU_REGION_SIZE(MPU_Init->Size));2 X9 v9 S2 Z3 L0 \& i
- 4 r+ X0 [. Z: h4 D9 l, S
- MPU->RBAR = MPU_Init->BaseAddress;/ P( L& a' h2 s% [; Y
- MPU->RASR = ((uint32_t)MPU_Init->DisableExec << MPU_RASR_XN_Pos) |$ [% w$ I* D# q. F7 P. f
- ((uint32_t)MPU_Init->AccessPermission << MPU_RASR_AP_Pos) |
/ q8 L/ r6 o/ F# K1 l4 ] - ((uint32_t)MPU_Init->TypeExtField << MPU_RASR_TEX_Pos) |
# @% x8 B! P- C8 G% b2 m6 Q# C- R& e - ((uint32_t)MPU_Init->IsShareable << MPU_RASR_S_Pos) |
$ n; W( a: q: ]3 k, D" X* ? - ((uint32_t)MPU_Init->IsCacheable << MPU_RASR_C_Pos) |
" L7 B8 M' S s - ((uint32_t)MPU_Init->IsBufferable << MPU_RASR_B_Pos) |6 e7 T6 y& h( Z* g& t" `( M: b
- ((uint32_t)MPU_Init->SubRegionDisable << MPU_RASR_SRD_Pos) |. g# `6 s( v% s9 R2 Z8 [
- ((uint32_t)MPU_Init->Size << MPU_RASR_SIZE_Pos) |" X" S3 D: J! K+ z
- ((uint32_t)MPU_Init->Enable << MPU_RASR_ENABLE_Pos);
/ X" L) Z3 W# G7 a% \2 X1 W( E - }8 h; s6 y9 h' x. w9 X; ^! Z
- else3 r, V) ?0 v+ q% C( s, A- {
- {3 u+ ^$ k9 C7 i
- MPU->RBAR = 0x00;
: P8 V/ u3 Z- h* }9 O9 n7 ~% [8 E - MPU->RASR = 0x00;
, p1 k/ O% N) t6 k8 L5 n - }4 u& q/ l H- T! T* Z
- }
复制代码 . F/ B) R0 A2 x# @# H
函数描述:. a( [! Y: w: r/ n9 T1 c
5 C4 M. d& i- l0 c' c
此函数用于配置MPU。# i. i* a! b" Y# b; F3 O7 R/ l
: W" s8 H+ X1 w5 \) o函数参数:3 z6 Z( N! Z7 j: Z* \
3 d: I9 i6 n3 S& w# j$ j1 c此函数的形参是一个MPU_Region_InitTypeDef类型的结构体变量,定义如下:' T6 e ^" Z; L4 f
1 S" F, a7 I7 y3 h
- typedef struct
5 n2 H9 @8 n$ g - {3 _2 X _& m# D) x. U3 P
- uint8_t Enable; ; ^* c8 @5 A( N3 |6 P
- uint8_t Number;
% U" M! M) X& c1 a, K - uint32_t BaseAddress; / m4 h$ A: f4 g' g k( m2 o- Q
- uint8_t Size; , F9 V9 e5 n1 [' ^8 V$ _/ J- @* g1 h" Y7 x
- uint8_t SubRegionDisable; & h4 S3 q7 Y. }' C5 c
- uint8_t TypeExtField;
* Q1 W6 x- B+ u# T a& l: g A7 e$ r - uint8_t AccessPermission;
3 |# @8 {7 Y1 |! [& {! z+ t - uint8_t DisableExec;
! p& ^) T& {0 Z2 G6 M - uint8_t IsShareable; 1 [2 W1 s7 ]. q8 B6 ]8 O3 {3 Z
- uint8_t IsCacheable;
1 z5 q$ d# Q8 [ - uint8_t IsBufferable; ' _+ R. ~# O+ ~& H7 y" [# Q
- }MPU_Region_InitTypeDef;
复制代码
, m3 b6 a7 x3 _除了参数Number和BaseAddress,其它几个参数在本章23.5小节进行了说明。- W6 O# c9 S/ e9 q; H( I
% o7 R: |/ Q. W9 g" m 结构体成员Number
' k0 N1 G7 S5 d: V9 a
$ ?6 X4 c, K7 a8 p4 u, Q这个成员是用来设置内存区序号的,用户配置的时候,推荐从Number0开始配置,最多到Number15,共计16个。对应的HAL库参数如下:% ^3 q: F' b3 @, Y4 m
; x4 |) M# m/ m6 T# T2 y
- /** @defgroup CORTEX_MPU_Region_Number CORTEX MPU Region Number2 ]7 X X9 Y8 n6 Z, }7 m- Q6 {+ _
- * @{
7 d+ K1 Q8 o( x% n; m, P1 n - */& B M4 q. _" q9 l% B
- #define MPU_REGION_NUMBER0 ((uint8_t)0x00)
8 R& p u L& l - #define MPU_REGION_NUMBER1 ((uint8_t)0x01)0 y; n3 }: z; E1 U
- #define MPU_REGION_NUMBER2 ((uint8_t)0x02)
( z# W, q% N3 c* u* R - #define MPU_REGION_NUMBER3 ((uint8_t)0x03). q \) V! w3 w- M" M2 p0 i1 C
- #define MPU_REGION_NUMBER4 ((uint8_t)0x04)/ N7 s( k5 N; Z& i( S( m
- #define MPU_REGION_NUMBER5 ((uint8_t)0x05)
, w; j0 y& k5 I9 r - #define MPU_REGION_NUMBER6 ((uint8_t)0x06)2 v! L' C; i$ Z: e, h& t/ z/ _# U
- #define MPU_REGION_NUMBER7 ((uint8_t)0x07)% Q- u) j% f2 g7 t4 D
- #define MPU_REGION_NUMBER8 ((uint8_t)0x08)' V, \/ T! D6 S
- #define MPU_REGION_NUMBER9 ((uint8_t)0x09)$ c0 v" m" r. Y- ]5 @, W
- #define MPU_REGION_NUMBER10 ((uint8_t)0x0A): r* T' Q$ e( u: y2 ^9 }9 b y1 [2 J
- #define MPU_REGION_NUMBER11 ((uint8_t)0x0B)8 \8 z9 @* Q( i) q% {, T
- #define MPU_REGION_NUMBER12 ((uint8_t)0x0C)5 {; O; R4 F S. D( y( \ C4 @, Z
- #define MPU_REGION_NUMBER13 ((uint8_t)0x0D); W8 b6 \$ T6 |, O, A
- #define MPU_REGION_NUMBER14 ((uint8_t)0x0E)
; L* T/ N; C4 s3 U& w) C% k) b# E - #define MPU_REGION_NUMBER15 ((uint8_t)0x0F)
复制代码 4 L% J# o3 k6 `9 s
结构体成员BaseAddress
) p1 e' y. Q. l- T; b
/ A4 u* ?& `' E2 C w4 [这个结构体成员用来设置内存区的首地址。这个参数跟结构体成员Size的配置是比较考究的,一定要保证首地址跟内存区的大小对齐,比如配置的是64KB大小的内存区,那么设置的首地址务必是64KB对齐的,也就是这个地址对64KB,即0x00010000求余数等于0,切记。
' r+ I0 V" W! d- b2 r* R
' ?$ K( s: W! m使用举例:
1 W; |- _* D7 b
% o$ f# y5 h6 v7 P9 G f S下面配置了两组。9 x. ]8 @* @0 \' E" P
! z1 |- q( v& V! F3 c, V- /*: G' Z+ ?) v1 J& e6 c$ n M
- *********************************************************************************************************
. g. `" y: [- E. M+ m6 } - * 函 数 名: MPU_Config& {0 h% [; H! x1 ?
- * 功能说明: 配置MPU; }( m1 p: G1 }/ t% N+ Q: e
- * 形 参: 无, \' P* D# E" i- R3 B5 s6 G5 T
- * 返 回 值: 无6 O. A0 B; ^. Y7 Z
- *********************************************************************************************************
@: j7 F2 m$ E# W - */
! {6 I% C/ L5 M9 z% s% r - static void MPU_Config( void )* K+ p6 [: L& U0 V7 {5 h$ v
- {
8 S( ~( X4 j+ F# F* ]' g8 {4 t - MPU_Region_InitTypeDef MPU_InitStruct;
6 W8 q2 i6 E2 e; p( H! N0 C* {0 g+ h - ! C- V4 n7 t0 z% v' j
- /* 禁止 MPU */
6 R$ G6 Z5 t' `- @ } - HAL_MPU_Disable();( R# `& Y+ u2 |1 }& v' c4 D n& T
1 u' W6 J: D* ^8 l" D- /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */
. y$ u1 O% z6 ]( H7 n4 e: E+ q - MPU_InitStruct.Enable = MPU_REGION_ENABLE;% i* F6 @. A1 K
- MPU_InitStruct.BaseAddress = 0x24000000;- s; p1 h0 R( U) L* k1 X
- MPU_InitStruct.Size = MPU_REGION_SIZE_512KB;
6 X; S9 s: @: V9 o+ f: R - MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
0 Y( v& i0 r, v q9 h* Z' e& p - MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;7 r. ] J1 ^7 |; [
- MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;& H$ _( A1 R" P; ~* Q& R, l: P8 g. t
- MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
2 t" l. j7 f( @ - MPU_InitStruct.Number = MPU_REGION_NUMBER0;
8 B, C1 g# i6 t( }; T: G$ Q - MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1; z2 [. p& F, n2 H
- MPU_InitStruct.SubRegionDisable = 0x00;
/ N2 O2 }; B4 x - MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
# A# _) u8 m( @) y" P4 f7 E9 H) ]& s3 v
$ a! q2 E! _1 {# N- HAL_MPU_ConfigRegion(&MPU_InitStruct);
6 y) t$ u }8 l5 b4 ` - & l7 s. `; [! s5 e) J4 O5 P
-
$ G6 k3 a- _9 @1 z0 t" M7 D5 _ - /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
3 x0 l1 c9 ]. Y+ y" s - MPU_InitStruct.Enable = MPU_REGION_ENABLE;6 Z/ K+ Z/ M) f$ d/ f- e; e7 }
- MPU_InitStruct.BaseAddress = 0x60000000;( ~! r1 n$ r) s. f" H
- MPU_InitStruct.Size = ARM_MPU_REGION_SIZE_64KB; ( ]$ v/ K V# {$ T% s$ @* @% `
- MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
# i/ t: t! o1 U+ a. E( i - MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;$ A: z3 P! b7 t3 S' B
- MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
: c; ^5 x1 k# L. j - MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;" g1 r& a3 j( ^
- MPU_InitStruct.Number = MPU_REGION_NUMBER1;! H' V% n) b3 c* _: B0 j1 X
- MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;, |7 q& \( \" E, {* i: E; l$ S
- MPU_InitStruct.SubRegionDisable = 0x00;0 m2 _7 D1 t! F3 W2 [3 b; I+ L- O
- MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;0 r4 m: V- T0 ] }
- ; \9 H7 I# y; p2 [& p# E
- HAL_MPU_ConfigRegion(&MPU_InitStruct);3 ^/ W ^2 r+ L$ B* U
- s! f: b7 |6 Y, `- /*使能 MPU */
; D4 p, m5 V' J y4 q, N - HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
3 \7 @0 I$ n& j* Z - }
复制代码 , J( m* D8 O! w! ^' W" v0 l; L
23.7 总结5 d+ I: T2 u, `% t8 m: i/ X+ U
本章节就为大家讲解这么多,还是本章开头那句话,可能有些知识点无法一下子就搞明白,在学习了后续章节的各种应用后,会有一个较深的认识。
. G' y) D- B; ]2 U" A1 e1 g# m+ `# C. |* j4 l# h# G8 A" t
/ d; c, j; Q: l2 N- Y
1 [$ x* c5 n# s% f! T1 Z* p
|