下面,我们看看关于NVIC寄存器的描述,都在哪些手册里面有提到 在使用STM32F10x standard peripheral library写有关于stm32中断的程序的时候,需要开启某个特定中断的控制位,除了对应外设的寄存器之外,还需要设置NVIC的相关寄存器的对应位。例如: - /****** STM32 specific Interrupt Numbers *********************************************************/5 T( p" ^* d- x6 X0 q
- WWDG_IRQn = 0, /*!< Window WatchDog Interrupt */7 O: Y! v0 p7 H+ Z
- PVD_IRQn = 1, /*!< PVD through EXTI Line detection Interrupt */7 E" U! L8 Y8 H$ {7 h
- TAMPER_IRQn = 2, /*!< Tamper Interrupt */' H9 o, R( o* f' I4 C7 \! i
- RTC_IRQn = 3, /*!< RTC global Interrupt */+ s$ {* D7 `* F2 M) p! B4 Y
- FLASH_IRQn = 4, /*!< FLASH global Interrupt */
0 T+ f: w1 [5 V9 o - RCC_IRQn = 5, /*!< RCC global Interrupt */
6 |% H% \ {$ G3 S5 H) T - EXTI0_IRQn = 6, /*!< EXTI Line0 Interrupt */" _0 I' e6 x. B" H" P( B
- EXTI1_IRQn = 7, /*!< EXTI Line1 Interrupt */1 |6 w8 }, _) t8 D2 B" w; ^
- EXTI2_IRQn = 8, /*!< EXTI Line2 Interrupt */
& y9 t g* X& d - EXTI3_IRQn = 9, /*!< EXTI Line3 Interrupt */6 z4 ?3 F( s: g: G
- EXTI4_IRQn = 10, /*!< EXTI Line4 Interrupt */' }3 C- l) l1 f& d7 w/ M
- DMA1_Channel1_IRQn = 11, /*!< DMA1 Channel 1 global Interrupt */
) l# x8 ?" `6 y9 m& ?+ ~ - DMA1_Channel2_IRQn = 12, /*!< DMA1 Channel 2 global Interrupt */* n1 I& `: @) F5 @0 A& k
- DMA1_Channel3_IRQn = 13, /*!< DMA1 Channel 3 global Interrupt */
- D: `, G8 y1 }, F - DMA1_Channel4_IRQn = 14, /*!< DMA1 Channel 4 global Interrupt */
- x, s9 @& ~+ Z1 x' Q - DMA1_Channel5_IRQn = 15, /*!< DMA1 Channel 5 global Interrupt */; P# `( e, [3 L
- DMA1_Channel6_IRQn = 16, /*!< DMA1 Channel 6 global Interrupt */
2 n! W( S$ U% }# z& g, j8 S - DMA1_Channel7_IRQn = 17, /*!< DMA1 Channel 7 global Interrupt */
! O2 ]% P1 `* i7 z: Q - ! } ^9 j' G: y7 S" C, a; I: a
- NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
+ C7 W [/ q# h9 Z( X$ [ - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
& I* V( L" F9 [( A9 n - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;* C) w5 r' T) b- @* G9 x8 ^
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
Q7 e$ |; _% }7 J3 q8 P0 T& F - NVIC_Init(&NVIC_InitStructure);
复制代码
9 H c& c1 q8 _4 o7 v而NVIC_Init()这个函数: - /**
+ k. P/ v" p; f8 h5 k - * @brief Initializes the NVIC peripheral according to the specified
- I+ g" F5 H1 g& y1 U# b1 d - * parameters in the NVIC_InitStruct.
: A) `$ Z m/ T( I - * @param NVIC_InitStruct: pointer to a NVIC_InitTypeDef structure that contains
8 N) a& p y5 z - * the configuration information for the specified NVIC peripheral.
7 j$ q% ~" j# J' I - * @retval None8 }+ o1 Y$ D: n, D& S" L
- */
! C7 c0 m; a! d6 ^# c - void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)% c8 b0 |' N' P! {6 A. N( N1 K
- {
: M3 m4 A" H- Q2 i2 F - uint32_t tmppriority = 0x00, tmppre = 0x00, tmpsub = 0x0F;
1 I( |$ _+ a$ U! f) m9 } -
' N5 e# Q% H& u. X5 C: u' T5 I - /* Check the parameters */* h2 l3 {5 H% W" P! M
- assert_param(IS_FUNCTIONAL_STATE(NVIC_InitStruct->NVIC_IRQChannelCmd));! J- v& s6 _9 l$ Z" d
- assert_param(IS_NVIC_PREEMPTION_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority)); 8 i% e, X( q* d3 \
- assert_param(IS_NVIC_SUB_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelSubPriority));
9 K) \* J3 c! u5 G+ T6 S" m) E2 m& c- e - ' u7 q! \$ o* m- W P* ~
- if (NVIC_InitStruct->NVIC_IRQChannelCmd != DISABLE)+ Y4 n- t) J$ `& b2 @
- {/ K1 U2 d1 r- \1 r
- /* Compute the Corresponding IRQ Priority --------------------------------*/ l8 }# g% C& T. Y* Q/ C
- tmppriority = (0x700 - ((SCB->AIRCR) & (uint32_t)0x700))>> 0x08;
/ [4 L( q! i- ] j' m+ I; w+ t' h; k- x - tmppre = (0x4 - tmppriority);
, ]" [& V, n0 u( Y0 |$ { - tmpsub = tmpsub >> tmppriority;
1 ~- W. m- R# x& Q( i
) v" s% ^: T1 T( W; A1 h# U+ k- tmppriority = (uint32_t)NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority << tmppre;
3 s* f+ e. }8 V - tmppriority |= NVIC_InitStruct->NVIC_IRQChannelSubPriority & tmpsub;
) n7 C( t) M6 w1 a+ F) |4 o: E - tmppriority = tmppriority << 0x04;
7 `0 f( B$ c% O - ' V7 x4 y7 l" N x7 y4 G
- NVIC->IP[NVIC_InitStruct->NVIC_IRQChannel] = tmppriority;# j* a0 q6 ]- X7 G# a
- 7 \& c" ]& b2 a
- /* Enable the Selected IRQ Channels --------------------------------------*/* z6 j. a- ^3 E; V
- NVIC->ISER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =
+ M+ d$ E% y8 ?2 c" p+ r$ ] - (uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);5 G' B( d) O1 s& @! ]
- }
: K v- `: @. w. u* Z/ g, k! u - else" W k8 [* t; @% b6 r
- {
" Z% _$ ~" p( t1 [* U K- ?5 Q - /* Disable the Selected IRQ Channels -------------------------------------*/0 l; p; v) e% T' G0 i, j) K4 m- l! ~
- NVIC->ICER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =$ y( g5 y8 ?8 ]- _4 `! }- D
- (uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);
: l- ^4 s) ]+ u- t( X - }
8 Y4 {7 A8 u% z7 c8 m* I& N - }
复制代码 1 A9 t5 ?0 P6 K
可以看到,它会去设置几个寄存器:NVIC的IP,ISER,ICER等等,NVIC是基址,为: - #define SCS_BASE (0xE000E000) /*!< System Control Space Base Address */
2 ]) c/ Y8 D$ N/ d - #define NVIC_BASE (SCS_BASE + 0x0100) /*!< NVIC Base Address */ r t3 A5 _$ _6 K) T0 r
- #define SCB_BASE (SCS_BASE + 0x0D00) /*!< System Control Block Base Address */
2 O2 w5 I6 E& b6 u$ S& A - : {; T {2 _# H# w' Z0 E8 N2 R- _
- 9 r/ s" r0 i0 x, z2 ~& c; s
- #define NVIC ((NVIC_Type *) NVIC_BASE) /*!< NVIC configuration struct */
复制代码 T' [- n4 g* l1 R
NVIC_Type为: - /** @addtogroup CMSIS_CM3_NVIC CMSIS CM3 NVIC# \# C {4 @, i V k
- memory mapped structure for Nested Vectored Interrupt Controller (NVIC)6 D! j- V3 E! f( ^5 _ a, k
- @{5 \2 w, x6 k" m3 ~/ y" E {0 h
- */
1 n9 T2 O' d# C6 `2 Z/ Y, x5 o - typedef struct! f8 n5 J& n1 h3 F; p
- {
4 D8 Q4 i. i2 u K - __IO uint32_t ISER[8]; /*!< Offset: 0x000 Interrupt Set Enable Register */
5 p) [, ~4 |0 y. ]0 ^7 @& H - uint32_t RESERVED0[24];
2 O8 }' L d6 T. F - __IO uint32_t ICER[8]; /*!< Offset: 0x080 Interrupt Clear Enable Register */. x/ \" F( l3 i; q& R4 S. }
- uint32_t RSERVED1[24];
7 ]) a- A$ O- ? L - __IO uint32_t ISPR[8]; /*!< Offset: 0x100 Interrupt Set Pending Register */# Q( h7 y' R, B, ~6 }) w
- uint32_t RESERVED2[24];
8 Q; L) W) L0 J' o, \! U, L7 ~* n2 q - __IO uint32_t ICPR[8]; /*!< Offset: 0x180 Interrupt Clear Pending Register */$ c/ p, L: _. f! \
- uint32_t RESERVED3[24];
2 `" I3 z) D' V6 ^5 k9 V" o( W# T- \ - __IO uint32_t IABR[8]; /*!< Offset: 0x200 Interrupt Active bit Register */
* W8 K# ~- r9 g! g* S! _ - uint32_t RESERVED4[56];
7 K. t/ i- f( }5 w - __IO uint8_t IP[240]; /*!< Offset: 0x300 Interrupt Priority Register (8Bit wide) */* H4 S( a. X' O
- uint32_t RESERVED5[644];
4 o) w& i1 t/ B7 S - __O uint32_t STIR; /*!< Offset: 0xE00 Software Trigger Interrupt Register */. _' C+ p" A$ P5 t- q4 I; `* O/ n
- } NVIC_Type; i8 T& B1 A0 {' y
- /*@}*/ /* end of group CMSIS_CM3_NVIC */
复制代码
, Y0 m: J; W6 ~5 ^+ v3 _ d从上面可以了解到的是,NVIC的寄存器的基址是没有错的,《The Definitive Guide to the ARM Cortex-M3》 85页有个比较详细的内存图;或者查看《Cortex-M3 Technical Reference Manual Revision r1p1》3.4 System address map,6.3 NVIC programmers model: E, I8 X$ k0 E* _4 ^2 c
% i3 a5 k0 t4 C5 p6 \以及:
! p& i6 o) c! }$ o+ B
) \& g/ r) L' M' m( G
B3.4 Nested Vectored Interrupt Controller (NVIC)的相关说明,例如: % e- N* l) j6 U {0 F
) q3 P8 a1 w! J, u/ B
当然,你看权威指南也可以的,在其APPENDIX D:NVIC Registers Quick Reference里面也有所描述。 但还有一个问题,我怎么知道这个Interrupt Set-Enable Registers寄存器的哪个位对应哪个中断呢?例如NVIC_ISER0的第0位对应哪个呢,其实,上面的表B3-31的说明已经说了,每一位对应一个中断号,所以我们还得看看stm32F103对应的中断号,可以查阅《RM0008:Reference manual》的第10章,Interrupts and events中的中断向量表,找到对应MD容量的那个表Table 63. Vector table for other STM32F10xxx devices,前面16个M3内核的中断,不可以从这个寄存器里控制,所以不管,我们从WWDG开始,可以看到这个表中的第一列即对应于寄存器中的某位(超过31的自己换算一下即可): 6 B& K9 x0 b7 T4 i5 d
1 p6 X0 x5 s9 @4 o
可以看到,STM32F10x standard peripheral library文件stm32f10x.h中的中断号的定义是能够与这里对应上的。 另外,stm32F103RB的Datasheet(CD00161566)里面的2.3.5 Nested vectored interrupt controller (NVIC)提到F103仅有43个可屏蔽中断,所以只需用到NVIC_ISER0和NVIC_ISER1来设置启用外设中断。
5 T1 U! m- a: l0 ~ p" S |