下面,我们看看关于NVIC寄存器的描述,都在哪些手册里面有提到 在使用STM32F10x standard peripheral library写有关于stm32中断的程序的时候,需要开启某个特定中断的控制位,除了对应外设的寄存器之外,还需要设置NVIC的相关寄存器的对应位。例如: - /****** STM32 specific Interrupt Numbers *********************************************************/
3 \; w5 t5 t: P" ] - WWDG_IRQn = 0, /*!< Window WatchDog Interrupt */
) _ r3 ~7 Q; G( U& q/ c y3 z4 V - PVD_IRQn = 1, /*!< PVD through EXTI Line detection Interrupt */
' H; z& F% p% R - TAMPER_IRQn = 2, /*!< Tamper Interrupt *// X @! Y- [* h/ w+ ]( h6 }, x" E
- RTC_IRQn = 3, /*!< RTC global Interrupt */
; s4 D( s/ k# N - FLASH_IRQn = 4, /*!< FLASH global Interrupt */& \2 d1 ?0 S4 l
- RCC_IRQn = 5, /*!< RCC global Interrupt */
% _8 e( E0 T. x n5 ~7 q. L - EXTI0_IRQn = 6, /*!< EXTI Line0 Interrupt */( O8 Q# k+ Y. R
- EXTI1_IRQn = 7, /*!< EXTI Line1 Interrupt */
9 a' D5 ]8 O1 } t - EXTI2_IRQn = 8, /*!< EXTI Line2 Interrupt */
9 d2 ~1 o- X& [4 M; j - EXTI3_IRQn = 9, /*!< EXTI Line3 Interrupt */' K6 B+ m4 K2 l$ Q6 T) o& Q
- EXTI4_IRQn = 10, /*!< EXTI Line4 Interrupt */2 h$ u# s; s' q4 ~/ C3 \
- DMA1_Channel1_IRQn = 11, /*!< DMA1 Channel 1 global Interrupt */" | A1 o) e* u. f$ H q
- DMA1_Channel2_IRQn = 12, /*!< DMA1 Channel 2 global Interrupt */6 v7 A1 r0 }$ A/ }& p
- DMA1_Channel3_IRQn = 13, /*!< DMA1 Channel 3 global Interrupt */
8 [) L9 K& m9 \8 u: f+ R - DMA1_Channel4_IRQn = 14, /*!< DMA1 Channel 4 global Interrupt */
! Q p" ^7 s% H; c5 o" W - DMA1_Channel5_IRQn = 15, /*!< DMA1 Channel 5 global Interrupt */
3 {: v4 d3 N+ I! ]9 m& g9 Y - DMA1_Channel6_IRQn = 16, /*!< DMA1 Channel 6 global Interrupt */3 v$ L& m. G6 E: g; S2 H4 O
- DMA1_Channel7_IRQn = 17, /*!< DMA1 Channel 7 global Interrupt */* q6 @0 C* E! ?6 q2 b8 m: R, k
- Y! C3 ^0 x) E: I
- NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;3 `) j- `" T+ ?, K3 V7 J
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;, F$ T( H$ P* F* }, y8 q; \% K9 e8 G, E
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
9 _. G* u" y: B" T - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
$ k; Z# c$ g6 O9 h9 L* l - NVIC_Init(&NVIC_InitStructure);
复制代码
k' K2 O" s0 I! E {1 y而NVIC_Init()这个函数: - /**
! q. D8 Y! j" Z# O5 \) b. O - * @brief Initializes the NVIC peripheral according to the specified
8 w$ }% u% q; Z2 m h# [: j - * parameters in the NVIC_InitStruct. v% y8 z: R; G) ?$ y
- * @param NVIC_InitStruct: pointer to a NVIC_InitTypeDef structure that contains8 E; @$ ]' q/ d7 ?( x8 M1 B# P
- * the configuration information for the specified NVIC peripheral.
9 h+ W9 ?1 I+ A* D - * @retval None2 z2 X. B- |: q- k$ d5 ~/ q
- */
/ E" u b3 }0 M8 L - void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)
$ E1 O) U6 E1 `0 w" Y - {
% J8 O# }* t5 B& J1 } d$ O - uint32_t tmppriority = 0x00, tmppre = 0x00, tmpsub = 0x0F;
" |! j+ o D( X) K. A -
# Y! `8 J. `$ ]7 [4 E8 d# @9 ~ - /* Check the parameters */
2 ?9 \7 c7 v# @3 R$ f8 [2 j& ~ - assert_param(IS_FUNCTIONAL_STATE(NVIC_InitStruct->NVIC_IRQChannelCmd));9 `+ G3 K/ m+ p! k6 y, u$ u( T; O
- assert_param(IS_NVIC_PREEMPTION_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority));
2 }) A/ z* N# g) z - assert_param(IS_NVIC_SUB_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelSubPriority));
* Y7 c- k& Q5 H9 u/ P5 R# t s& T* _ -
' x, M, ^" j5 @% e1 s3 J, p - if (NVIC_InitStruct->NVIC_IRQChannelCmd != DISABLE)& x0 w2 `, l2 H* A! _
- {
d* E+ G) W6 I - /* Compute the Corresponding IRQ Priority --------------------------------*/ 4 {! c* S9 ]2 X! R% |1 n( n) G
- tmppriority = (0x700 - ((SCB->AIRCR) & (uint32_t)0x700))>> 0x08;
' q0 L% ^9 Q% T - tmppre = (0x4 - tmppriority);
' D0 p: t7 w5 F/ j+ K) } - tmpsub = tmpsub >> tmppriority;
h0 O, A4 ?8 r
! V% V0 g; ^0 S6 I; r* Y- N+ a5 y0 R- tmppriority = (uint32_t)NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority << tmppre;
1 I% `# e3 G) R1 W! R t - tmppriority |= NVIC_InitStruct->NVIC_IRQChannelSubPriority & tmpsub;
/ h" a; X; l6 K7 ]& ^$ Z6 G - tmppriority = tmppriority << 0x04;8 V8 v3 P; Y2 a
- ( y# J1 W5 f7 w' `/ ?
- NVIC->IP[NVIC_InitStruct->NVIC_IRQChannel] = tmppriority;
2 U& {: Z) G9 |' U+ l# A" G4 J1 x - . T! w! v) C5 ~( Q1 C: E' A
- /* Enable the Selected IRQ Channels --------------------------------------*/9 x; f7 @% t4 e3 P3 M
- NVIC->ISER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =
6 T- V& u5 X- z5 d3 N Y/ t% y - (uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);
) d/ e) p* |5 I$ d: O - }' n7 l- V0 f3 G3 O1 @
- else
7 H' p6 x3 {( }( C p, |9 a* O. l - {
7 {- K5 `; \) [" v3 [9 q% \; @ - /* Disable the Selected IRQ Channels -------------------------------------*/
. ^! T( Q: d+ M+ ?' I, @ - NVIC->ICER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] = c1 R4 R H5 T& S! c/ Q
- (uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);* X# t! G1 o1 t4 r5 ?
- }$ M" V( m) j+ b/ t/ | f( H
- }
复制代码 ) P; G8 x9 T1 L) L
可以看到,它会去设置几个寄存器:NVIC的IP,ISER,ICER等等,NVIC是基址,为: - #define SCS_BASE (0xE000E000) /*!< System Control Space Base Address */5 h" j( R& ?7 d* V
- #define NVIC_BASE (SCS_BASE + 0x0100) /*!< NVIC Base Address */0 G5 y$ Q2 v1 B" ]& Z
- #define SCB_BASE (SCS_BASE + 0x0D00) /*!< System Control Block Base Address */
0 \4 c5 I3 `/ ~+ h$ z
: i1 R& g0 t& ]2 K$ r/ z" E# c
4 G0 q D# m1 {; c) G- #define NVIC ((NVIC_Type *) NVIC_BASE) /*!< NVIC configuration struct */
复制代码 * O- v0 ?- |1 l( s" d
NVIC_Type为: - /** @addtogroup CMSIS_CM3_NVIC CMSIS CM3 NVIC
9 M( K M7 K9 Y C' z - memory mapped structure for Nested Vectored Interrupt Controller (NVIC)
2 m; h0 [3 a4 h9 x6 X1 [ - @{+ G0 M* f; s1 n3 N0 X
- */4 @ y) i2 C; Y5 l
- typedef struct1 r! G/ u" O! Q0 x
- {* r' A; E6 x3 ?/ _+ C$ ]
- __IO uint32_t ISER[8]; /*!< Offset: 0x000 Interrupt Set Enable Register */
1 b! S$ a2 Z+ x - uint32_t RESERVED0[24]; ) Q% U# A' E6 G0 s6 q( e9 m
- __IO uint32_t ICER[8]; /*!< Offset: 0x080 Interrupt Clear Enable Register */
( T T/ h( i( j [ - uint32_t RSERVED1[24]; 9 s- T8 g2 h2 @' y" ?( |& I
- __IO uint32_t ISPR[8]; /*!< Offset: 0x100 Interrupt Set Pending Register */
& U" {9 |+ p# v9 E - uint32_t RESERVED2[24];
7 E( K; A- y" s: L Y4 A - __IO uint32_t ICPR[8]; /*!< Offset: 0x180 Interrupt Clear Pending Register */3 N2 h0 p( i x, `$ X
- uint32_t RESERVED3[24]; 6 V& [, o9 A: z) {& u0 m# Q0 J/ h
- __IO uint32_t IABR[8]; /*!< Offset: 0x200 Interrupt Active bit Register */
: X1 @) A S( A: X - uint32_t RESERVED4[56]; 3 M3 G. ] v6 c; ?$ E, ]" D
- __IO uint8_t IP[240]; /*!< Offset: 0x300 Interrupt Priority Register (8Bit wide) *// X9 C1 j& z0 m" y& w
- uint32_t RESERVED5[644]; , V3 R; ?1 [) `4 a0 m. p; m
- __O uint32_t STIR; /*!< Offset: 0xE00 Software Trigger Interrupt Register */
2 ?& a" R& K7 c$ n" O+ b* l8 g - } NVIC_Type; 0 y( O1 j$ ?5 [% S2 B5 v$ l; r& ]
- /*@}*/ /* end of group CMSIS_CM3_NVIC */
复制代码 : Y( I) u! q( Z
从上面可以了解到的是,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:
7 \ x T+ I# g' [ 7 A9 r2 J4 z+ f6 Z" |- U
以及:
5 K/ j @5 L: K) x r0 b% F5 D% L
( t" F$ f% k5 y/ F
B3.4 Nested Vectored Interrupt Controller (NVIC)的相关说明,例如: - L/ n, B: l4 V& _3 b# a+ }
7 S' s$ o% ^) R! o; K
当然,你看权威指南也可以的,在其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的自己换算一下即可):
1 u7 y6 m3 b5 X
) r J- c) D, E5 U$ x ^2 \4 H. E
可以看到,STM32F10x standard peripheral library文件stm32f10x.h中的中断号的定义是能够与这里对应上的。 另外,stm32F103RB的Datasheet(CD00161566)里面的2.3.5 Nested vectored interrupt controller (NVIC)提到F103仅有43个可屏蔽中断,所以只需用到NVIC_ISER0和NVIC_ISER1来设置启用外设中断。 / _- F8 v& u9 y) l5 f, G1 z _
|