下面,我们看看关于NVIC寄存器的描述,都在哪些手册里面有提到 在使用STM32F10x standard peripheral library写有关于stm32中断的程序的时候,需要开启某个特定中断的控制位,除了对应外设的寄存器之外,还需要设置NVIC的相关寄存器的对应位。例如: - /****** STM32 specific Interrupt Numbers *********************************************************/
. L" L3 m/ |( J; T - WWDG_IRQn = 0, /*!< Window WatchDog Interrupt */, R' Z+ j0 q' b2 M0 \2 [3 [
- PVD_IRQn = 1, /*!< PVD through EXTI Line detection Interrupt */
- K* p- |8 _' |. g0 Z' g' e9 V - TAMPER_IRQn = 2, /*!< Tamper Interrupt */
/ s$ D6 w# P. { - RTC_IRQn = 3, /*!< RTC global Interrupt */. G* T: n2 [ Z" Q
- FLASH_IRQn = 4, /*!< FLASH global Interrupt */
9 u6 A) i v: P9 X; S - RCC_IRQn = 5, /*!< RCC global Interrupt */
* ~: E- A5 \" Z6 ?9 k: H) L. G - EXTI0_IRQn = 6, /*!< EXTI Line0 Interrupt */: [; \( F# u R3 C
- EXTI1_IRQn = 7, /*!< EXTI Line1 Interrupt *// l8 d" ]+ w3 G; b8 D& e5 n2 |
- EXTI2_IRQn = 8, /*!< EXTI Line2 Interrupt */
( v" F: ^4 a/ d - EXTI3_IRQn = 9, /*!< EXTI Line3 Interrupt */
. q4 Q4 C' E0 ` - EXTI4_IRQn = 10, /*!< EXTI Line4 Interrupt */
% D% k7 ^9 @: z, W0 O - DMA1_Channel1_IRQn = 11, /*!< DMA1 Channel 1 global Interrupt */
: k9 A/ _4 N7 i - DMA1_Channel2_IRQn = 12, /*!< DMA1 Channel 2 global Interrupt */
6 ?7 `6 r' g$ m( J' I3 i4 M. d - DMA1_Channel3_IRQn = 13, /*!< DMA1 Channel 3 global Interrupt */# i" n; ~' H% u7 x9 v
- DMA1_Channel4_IRQn = 14, /*!< DMA1 Channel 4 global Interrupt */
6 A- f: U4 F8 M( I - DMA1_Channel5_IRQn = 15, /*!< DMA1 Channel 5 global Interrupt */8 V3 k) t# i+ J7 Z: A4 R; F
- DMA1_Channel6_IRQn = 16, /*!< DMA1 Channel 6 global Interrupt */5 B' d) C& d$ ~( d8 Q+ Z7 \3 F
- DMA1_Channel7_IRQn = 17, /*!< DMA1 Channel 7 global Interrupt */% G6 [& }; W6 |
- - v) `6 O* V6 s9 f X
- NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
* f- D& X7 T# i$ c* E) t - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
! o+ [6 h$ F6 m& [4 B2 J - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;3 U# n5 G( I! ~7 Q# n8 B; d
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
( @ Y: \ P: R' O - NVIC_Init(&NVIC_InitStructure);
复制代码
: p' T7 o' a7 e4 d& M5 p0 i而NVIC_Init()这个函数: - /**+ ^* F( `" q2 z' r
- * @brief Initializes the NVIC peripheral according to the specified$ V) u: _# H/ c+ V E# @
- * parameters in the NVIC_InitStruct.
+ |0 i4 x/ m3 J; r7 Y2 L' b - * @param NVIC_InitStruct: pointer to a NVIC_InitTypeDef structure that contains
m: r+ O$ s# h( }# b - * the configuration information for the specified NVIC peripheral., D5 m- C7 c, z3 L3 v6 T! J
- * @retval None
% Q( O# s% ?# S* C! [ - */) d2 P7 n1 R) i. ?- N6 b. q) i
- void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)" q) m0 g" ^4 G
- {' f% J! F% G! d4 c+ ], o
- uint32_t tmppriority = 0x00, tmppre = 0x00, tmpsub = 0x0F;6 Y) @; \; e4 @
- 8 x+ m, Y. a$ A% S0 Q" X1 D8 J
- /* Check the parameters */
! z7 |& Y$ V& b& M - assert_param(IS_FUNCTIONAL_STATE(NVIC_InitStruct->NVIC_IRQChannelCmd));
) V7 s% m# N6 M/ e7 ], m& Q - assert_param(IS_NVIC_PREEMPTION_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority));
1 ?3 b, @3 D1 @1 Z - assert_param(IS_NVIC_SUB_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelSubPriority));
; B3 K! {( N! S+ r4 G -
$ L4 I" C/ o6 g; z - if (NVIC_InitStruct->NVIC_IRQChannelCmd != DISABLE)- Q n! T3 _ l: h% v5 X% \: S0 H" Z
- {$ v2 d4 k7 _- z, V, V
- /* Compute the Corresponding IRQ Priority --------------------------------*/ " Q' A6 s3 O: v2 R! f. B
- tmppriority = (0x700 - ((SCB->AIRCR) & (uint32_t)0x700))>> 0x08;
( n9 }8 y3 y; H; V- @* U - tmppre = (0x4 - tmppriority);
3 Z0 p- y+ \: a" P - tmpsub = tmpsub >> tmppriority;% ]5 i4 i' _) I% h2 Z; b
- # }% e2 o7 {; i* R
- tmppriority = (uint32_t)NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority << tmppre;1 z3 r5 G2 {- R% |+ o+ m8 g: X8 [
- tmppriority |= NVIC_InitStruct->NVIC_IRQChannelSubPriority & tmpsub;
! q l, ~9 w; b5 t+ { - tmppriority = tmppriority << 0x04;' i/ n1 F2 j2 [9 A3 z8 h. x) H
-
. q+ v1 \) d5 c8 k1 a - NVIC->IP[NVIC_InitStruct->NVIC_IRQChannel] = tmppriority;
0 y& H* D- X; T -
$ M% B: L, x! { - /* Enable the Selected IRQ Channels --------------------------------------*/
, C6 ]( J0 x2 E) _& C2 t# K; Z. D - NVIC->ISER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =5 N, U7 v' D5 z& M* [' M$ s9 [
- (uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);) e, W+ X/ S. A5 @: q Z7 T
- }; f l. L( ]/ b! j- S4 f2 Z
- else
* \, Q5 P0 g3 J! M - {
7 A% l+ H0 E# m$ o - /* Disable the Selected IRQ Channels -------------------------------------*/
! _8 V, l, `/ U - NVIC->ICER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =& Q E1 s" k5 E+ o) R8 u9 |& H
- (uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);
1 B5 [: M# w+ W' ]& ]! C+ ` - }
; D$ g- C P6 O, M5 n& X) x - }
复制代码 8 i1 I. x6 I4 l9 z
可以看到,它会去设置几个寄存器:NVIC的IP,ISER,ICER等等,NVIC是基址,为: - #define SCS_BASE (0xE000E000) /*!< System Control Space Base Address */
- e5 [4 c/ k+ c2 c7 } - #define NVIC_BASE (SCS_BASE + 0x0100) /*!< NVIC Base Address */
; t' ~+ z k+ U* n. n1 S: w - #define SCB_BASE (SCS_BASE + 0x0D00) /*!< System Control Block Base Address *// n1 _) {- g- I
" v2 f2 |4 x+ s% |
7 U) B- K7 P8 [2 `# j, U- #define NVIC ((NVIC_Type *) NVIC_BASE) /*!< NVIC configuration struct */
复制代码
3 }% Y1 K' e6 `* B4 X' B5 c( T y. ANVIC_Type为: - /** @addtogroup CMSIS_CM3_NVIC CMSIS CM3 NVIC7 N! b; A; C, J" j
- memory mapped structure for Nested Vectored Interrupt Controller (NVIC)
2 B! U9 I4 N. _* y# _5 Y - @{
! o7 p; o# E* i; s" L9 s - */
8 ?& R! }6 Z4 F9 t: x6 g - typedef struct
" C" |) V* s* |+ l5 i! i; ^0 Y - {
2 r7 p3 a/ _; }. b9 T4 \7 p# j - __IO uint32_t ISER[8]; /*!< Offset: 0x000 Interrupt Set Enable Register */
# K2 u) [0 C0 Z( ]& C - uint32_t RESERVED0[24]; 1 K1 x" {3 q! N% K1 ]1 h x
- __IO uint32_t ICER[8]; /*!< Offset: 0x080 Interrupt Clear Enable Register */* X4 G) S( j% _6 ?) r2 B
- uint32_t RSERVED1[24]; - o/ J' z3 |) h+ u
- __IO uint32_t ISPR[8]; /*!< Offset: 0x100 Interrupt Set Pending Register */
/ j0 `" N" s, b g4 o8 R# B - uint32_t RESERVED2[24];
# q; p0 c, {5 E$ c - __IO uint32_t ICPR[8]; /*!< Offset: 0x180 Interrupt Clear Pending Register */+ f: w' }/ d- v" p6 F
- uint32_t RESERVED3[24]; 6 m5 z5 \9 w1 \9 Q( d
- __IO uint32_t IABR[8]; /*!< Offset: 0x200 Interrupt Active bit Register */( _( l8 ~4 v$ j: Q* F6 Y
- uint32_t RESERVED4[56];
9 J6 R$ i) Q. b4 c0 @ - __IO uint8_t IP[240]; /*!< Offset: 0x300 Interrupt Priority Register (8Bit wide) */* Y4 Y5 k& o; O5 Q) h
- uint32_t RESERVED5[644]; * H- `. e, Q- F1 X# _
- __O uint32_t STIR; /*!< Offset: 0xE00 Software Trigger Interrupt Register */* ?% A7 [7 l( Q* A8 M
- } NVIC_Type; ' B) z1 J1 Q) q. s4 f' A6 p* J8 E5 j
- /*@}*/ /* end of group CMSIS_CM3_NVIC */
复制代码
) f; G% o3 T; n从上面可以了解到的是,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:
4 f0 ~4 Z* v' b+ m 0 x. p7 A- g5 _& v, N! O" G
以及:
9 H( l0 ]: l6 t$ S* f* |! V5 ~% b
* X- [' r3 r, O0 G& V
B3.4 Nested Vectored Interrupt Controller (NVIC)的相关说明,例如:
$ U; k: n' e* v
' K. Y, T% X$ ?
当然,你看权威指南也可以的,在其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的自己换算一下即可):
# v/ y* }/ Z5 k }* k: `
3 X" [) }" a E. @' K7 E: x
可以看到,STM32F10x standard peripheral library文件stm32f10x.h中的中断号的定义是能够与这里对应上的。 另外,stm32F103RB的Datasheet(CD00161566)里面的2.3.5 Nested vectored interrupt controller (NVIC)提到F103仅有43个可屏蔽中断,所以只需用到NVIC_ISER0和NVIC_ISER1来设置启用外设中断。
+ }8 G* F! x3 f |