5.14 NVIC Guide
This chapter describes the file composition and the 5 public functions of the NVIC driver in the N32G41x standard peripheral library: interrupt priority grouping and interrupt channel configuration, vector table relocation, low-power mode condition selection and SysTick clock source selection; the demo section covers the three examples NVIC_IRQ_Mask, NVIC_IRQ_Priority and NVIC_VectorTable_Relocation. Read the interrupt channels, vector table, priority grouping and SysTick calibration value together with the “Interrupts and events” chapter of the user manual, and take the errata sheet as the authority on known chip issues.
5.14.1 Related files
| Relative path | Purpose |
|---|---|
firmware/n32g41x_std_periph_driver/inc/misc.h |
Defines the NVIC_InitType structure, the priority grouping and pre-emption and subpriority value macros, the vector table base and low-power mode macros, and declares 5 public functions in the two sections NVIC configuration and SysTick configuration |
firmware/n32g41x_std_periph_driver/src/misc.c |
Implements those 5 functions: writing SCB->AIRCR to set the priority grouping, packing the two priority levels into an 8-bit priority written to NVIC->IP together with NVIC->ISER and NVIC->ICER to enable or close a channel, writing SCB->VTOR to relocate the vector table, and modifying SCB->SCR and SysTick->CTRL |
projects/n32g41x_EVAL/examples/NVIC/ |
NVIC example root directory, with 3 examples: NVIC_IRQ_Mask, NVIC_IRQ_Priority, NVIC_VectorTable_Relocation |
projects/n32g41x_EVAL/examples/NVIC/NVIC_IRQ_Mask/ |
Directory composition of that example: MDK-ARM/, EWARM/, inc/, src/, readme.txt |
projects/n32g41x_EVAL/bsp/ |
Board support files shared by the three examples: evaluation board key macros and the serial log interface |
5.14.2 API reference
The following 5 public functions are listed in the declaration order of misc.h in 2 groups; each entry gives a summary and the original comment above the function in misc.c.
NVIC configuration
NVIC_PriorityGroupConfig, NVIC_Init, NVIC_SetVectorTable, NVIC_SystemLPConfig
SysTick configuration
SysTick_CLKSourceConfig
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)Configures the priority grouping: pre-emption priority and subpriority.
name NVIC_PriorityGroupConfig
fun Configures the priority grouping: pre-emption priority and subpriority.
param NVIC_PriorityGroup :
- NVIC_PriorityGroup_0 0 bits for pre-emption priority 4 bits for subpriority
- NVIC_PriorityGroup_1 1 bits for pre-emption priority 3 bits for subpriority
- NVIC_PriorityGroup_2 2 bits for pre-emption priority 2 bits for subpriority
- NVIC_PriorityGroup_3 3 bits for pre-emption priority 1 bits for subpriority
- NVIC_PriorityGroup_4 4 bits for pre-emption priority 0 bits for subpriority
return none
Use note: The implementation ORs NVIC_PriorityGroup with the access key 0x05FA0000 and writes the result to SCB->AIRCR, so a single write also supplies the priority grouping.
void NVIC_Init(const NVIC_InitType *NVIC_InitStruct)Initializes the NVIC peripheral according to the specified parameters in the NVIC_structure_initializes.
name NVIC_Init
fun Initializes the NVIC peripheral according to the specified parameters in the NVIC_structure_initializes.
param NVIC_InitStruct :
- NVIC_IRQChannel :
- IRQn_Type Interrupt Number Definition
if NVIC_PriorityGroup is NVIC_PriorityGroup_0 :
- NVIC_IRQChannelPreemptionPriority :
- NVIC_PRE_PRIORITY_0
- NVIC_IRQChannelSubPriority :
- NVIC_SUB_PRIORITY_0
- NVIC_SUB_PRIORITY_1
- NVIC_SUB_PRIORITY_2
- NVIC_SUB_PRIORITY_3
- NVIC_SUB_PRIORITY_4
- NVIC_SUB_PRIORITY_5
- NVIC_SUB_PRIORITY_6
- NVIC_SUB_PRIORITY_7
- NVIC_SUB_PRIORITY_8
- NVIC_SUB_PRIORITY_9
- NVIC_SUB_PRIORITY_10
- NVIC_SUB_PRIORITY_11
- NVIC_SUB_PRIORITY_12
- NVIC_SUB_PRIORITY_13
- NVIC_SUB_PRIORITY_14
- NVIC_SUB_PRIORITY_15
if NVIC_PriorityGroup is NVIC_PriorityGroup_1 :
- NVIC_IRQChannelPreemptionPriority :
- NVIC_PRE_PRIORITY_0
- NVIC_PRE_PRIORITY_1
- NVIC_IRQChannelSubPriority :
- NVIC_SUB_PRIORITY_0 to NVIC_SUB_PRIORITY_7
if NVIC_PriorityGroup is NVIC_PriorityGroup_2 :
- NVIC_IRQChannelPreemptionPriority :
- NVIC_PRE_PRIORITY_0 to NVIC_PRE_PRIORITY_3
- NVIC_IRQChannelSubPriority :
- NVIC_SUB_PRIORITY_0 to NVIC_SUB_PRIORITY_3
if NVIC_PriorityGroup is NVIC_PriorityGroup_3 :
- NVIC_IRQChannelPreemptionPriority :
- NVIC_PRE_PRIORITY_0 to NVIC_PRE_PRIORITY_7
- NVIC_IRQChannelSubPriority :
- NVIC_SUB_PRIORITY_0
- NVIC_SUB_PRIORITY_1
if NVIC_PriorityGroup is NVIC_PriorityGroup_4 :
- NVIC_IRQChannelPreemptionPriority :
- NVIC_PRE_PRIORITY_0
- NVIC_PRE_PRIORITY_1
- NVIC_PRE_PRIORITY_2
- NVIC_PRE_PRIORITY_3
- NVIC_PRE_PRIORITY_4
- NVIC_PRE_PRIORITY_5
- NVIC_PRE_PRIORITY_6
- NVIC_PRE_PRIORITY_7
- NVIC_PRE_PRIORITY_8
- NVIC_PRE_PRIORITY_9
- NVIC_PRE_PRIORITY_10
- NVIC_PRE_PRIORITY_11
- NVIC_PRE_PRIORITY_12
- NVIC_PRE_PRIORITY_13
- NVIC_PRE_PRIORITY_14
- NVIC_PRE_PRIORITY_15
- NVIC_IRQChannelSubPriority :
- NVIC_SUB_PRIORITY_0
- NVIC_IRQChannelCmd :
- ENABLE
- DISABLE
return none
Use note: The implementation packs the pre-emption priority and the subpriority into an 8-bit priority according to the priority grouping in SCB->AIRCR and writes it to NVIC->IP; when NVIC_IRQChannelCmd is DISABLE it only writes NVIC->ICER to close the channel and does not update the priority.
void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset)Sets the vector table location and Offset.
name NVIC_SetVectorTable
fun Sets the vector table location and Offset.
param NVIC_vecter_table specifies if the vector table is in RAM or FLASH memory.
This parameter can be one of the following values:
- NVIC_VectTab_RAM
- NVIC_VectTab_FLASH
param offset Vector Table base offset field. This value must be a multiple of 0x200.
return none
Use note: The implementation writes NVIC_VectTab ORed with Offset masked by 0x1FFFFF00 into SCB->VTOR, clearing only the low 8 bits; the 0x200 multiple required by the comment is not enforced by the implementation.
void NVIC_SystemLPConfig(uint8_t LowPowerMode, FunctionalState Cmd)Selects the condition for the system to enter low power mode.
name NVIC_SystemLPConfig
fun Selects the condition for the system to enter low power mode.
param LowPowerMode Specifies the new mode for the system to enter low power mode.
This parameter can be one of the following values:
- NVIC_LP_SEVONPEND
- NVIC_LP_SLEEPDEEP
- NVIC_LP_SLEEPONEXIT
param - Cmd :
- ENABLE
- DISABLE
return none
Use note: When Cmd is not DISABLE the implementation ORs LowPowerMode into SCB->SCR, otherwise it clears those bits; several NVIC_LP_* macros can be passed as one bitwise OR.
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)Configures the SysTick clock source.
name SysTick_CLKSourceConfig
fun Configures the SysTick clock source.
param SysTick_CLKSource :
- SysTick_CLKSource_HCLK_Div8 External clock selected as SysTick clock source.
- SysTick_CLKSource_HCLK AHB clock selected as SysTick clock source.
return none
Use note: The implementation sets the CLKSOURCE bit of SysTick->CTRL only when the argument equals SysTick_CLKSource_HCLK; any other value clears that bit and selects HCLK/8.
5.14.3 Demo descriptions
This section describes the 3 NVIC examples: NVIC_IRQ_Mask uses the global interrupt switch to show how interrupt masking affects the timer and key interrupts, NVIC_IRQ_Priority uses the pre-emption relationship between the key interrupt and the SysTick interrupt to show how priorities are configured and adjusted at run time, and NVIC_VectorTable_Relocation relocates the interrupt vector table from FLASH to SRAM.
5.14.3.1 NVIC_IRQ_Mask interrupt masking
Example directory: projects/n32g41x_EVAL/examples/NVIC/NVIC_IRQ_Mask/
Enable the GPIO and GTIM3 clocks and configure the key external interrupt→Set the pre-emption and subpriority of the GTIM3 and key interrupts→The main loop waits for the key interrupt to toggle the enable flag→Masking the global interrupt stops the timer interrupt printing→A key press and release restores the global interrupt
| Item | Source analysis |
|---|---|
| Function | Uses __disable_irq and __enable_irq to control the global interrupt switch and shows the effect of interrupt masking on the GTIM3 periodic interrupt and the key EXTI4 interrupt. |
| Source files | src/main.c: main, KeyInputExtiInit, TIM_Config and the Key_Status definition;inc/main.h: key pin and EXTI4 channel macros and function declarations;src/n32g41x_it.c, inc/n32g41x_it.h: interrupt service functions such as EXTI4_IRQHandler and GTIM3_IRQHandler;readme.txt: function, environment and usage;MDK-ARM/, EWARM/: Keil and IAR projects. |
| Key configuration | Clock source HSI+PLL, 80 MHz for N32G412 and 96 MHz for N32G415; KEY1 is PA4 in GPIO_MODE_INPUT with GPIO_PULL_UP, mapped to EXTI_LINE4 with falling-edge trigger;the priority grouping is NVIC_PriorityGroup_2;EXTI4_IRQn uses pre-emption priority 1 and subpriority 0;GTIM3_IRQn uses pre-emption priority 0 and subpriority 0.The GTIM3 period register is 49999 and the prescaler is RCC_Clocks.HclkFreq / 50000 - 1, with the counter counting up. |
| Program and data path | main calls log_init and prints NVIC IRQ Mask, sets the priority grouping first and then configures GTIM3 and the key EXTI;GTIM3_IRQHandler prints GTIM3 IRQHandler on every update interrupt;a key press makes EXTI4_IRQHandler toggle Key_Status between ENABLE and DISABLE, and once the main loop reads ENABLE it calls __disable_irq and calls __enable_irq after the key is pressed and released again. |
| Main APIs | NVIC_PriorityGroupConfig, NVIC_Init, GPIO_InitPeripheral, GPIO_ConfigEXTILine, EXTI_InitPeripheral, TIM_InitTimeBase, TIM_ConfigPrescaler, TIM_ConfigInt, TIM_Enable |
| Verification | After a reset the serial port prints GTIM3 IRQHandler periodically;pressing KEY1 prints EXTI4 IRQHandler Start, EXTI4 IRQHandler End and Disable irq, and the timer printing stops;pressing and releasing KEY1 again prints enable irq and the timer printing resumes. |
| Use note | Supports the N32G412 and N32G415 chips; the development environment is KEIL MDK-ARM V5.34 or IAR EWARM 8.50.1; the key is KEY1 (PA4) on the evaluation board and its pressed level is Bit_RESET. |
Core-code walkthrough and porting
The example fixes the priority grouping first, then configures the interrupt priorities of the key and of GTIM3, and finally verifies the masking effect from the main loop with the global interrupt switch.
Data path: main → NVIC_PriorityGroupConfig writes SCB->AIRCR → NVIC_Init writes NVIC->IP and NVIC->ISER → EXTI4_IRQHandler toggles Key_Status → the main loop calls __disable_irq and __enable_irq → serial printing stops and resumes
1. Fix the priority grouping first. NVIC_PriorityGroupConfig writes the PRIGROUP field of SCB->AIRCR; this example uses NVIC_PriorityGroup_2, that is 2 bits for the pre-emption priority and 2 bits for the subpriority. NVIC_Init then packs the two priority levels into 8 bits according to that grouping, so a changed grouping needs the values of every interrupt reviewed again.
/* Configure two bits for preemption priority */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
2. Give the key interrupt the lower pre-emption priority. KeyInputExtiInit fills in the NVIC_InitType fields and calls NVIC_Init to set EXTI4_IRQn to pre-emption 1 and subpriority 0 and to enable the channel.
/* Set key input interrupt priority */
NVIC_InitStructure.NVIC_IRQChannel = KEY_INPUT_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = NVIC_PRE_PRIORITY_1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = NVIC_SUB_PRIORITY_0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
When the key pin or the interrupt line changes, NVIC_IRQChannel must stay consistent with KEY_INPUT_IRQn in inc/main.h.
3. Give GTIM3 the higher pre-emption priority. TIM_Config sets GTIM3_IRQn to pre-emption 0 and subpriority 0, so its pre-emption priority is higher than that of the key interrupt.
/* Set GTIM3 interrupt priority */
NVIC_InitStructure.NVIC_IRQChannel = GTIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = NVIC_PRE_PRIORITY_0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = NVIC_SUB_PRIORITY_0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
To change which of the two interrupts pre-empts the other, edit the NVIC_PRE_PRIORITY_* value in both places rather than only one of them.
4. Verify masking from the main loop with the global interrupt switch. Once Key_Status has been set by EXTI4_IRQHandler, the main loop calls __disable_irq, waits for the key to be pressed and released again, and then calls __enable_irq; during that window the GTIM3 interrupt no longer prints.
while (1)
{
while (Key_Status == DISABLE) {}
log_info("Disable irq \r\n");
__disable_irq();
while(GPIO_ReadInputDataBit(KEY_INPUT_PORT, KEY_INPUT_PIN) == RESET) {}
while(GPIO_ReadInputDataBit(KEY_INPUT_PORT, KEY_INPUT_PIN) == SET) {}
log_info("enable irq \r\n");
__enable_irq();
}
__disable_irq and __enable_irq only touch PRIMASK, so an interrupt that became pending during the masked window is still serviced after the interrupt is re-enabled; leaving the mask requires the key to be pressed and then released.
Corresponding source files: src/main.c, inc/main.h
5.14.3.2 NVIC_IRQ_Priority interrupt priority
Example directory: projects/n32g41x_EVAL/examples/NVIC/NVIC_IRQ_Priority/
Enable the GPIO clock and set KEY1 as an input with falling-edge external interrupt→Set the key EXTI4 pre-emption priority to 1 and the SysTick pre-emption priority to 0→A key press makes the EXTI4 interrupt pend the SysTick exception→The SysTick interrupt reads the active state of EXTI4 and sets Key_Status→The main loop changes the SysTick pre-emption priority to 2
| Item | Source analysis |
|---|---|
| Function | Uses the pre-emption relationship between the key external interrupt and SysTick to show how interrupt priorities are configured and adjusted at run time: the key interrupt pends the SysTick exception, SysTick_Handler uses NVIC_GetActive to tell whether the key interrupt was pre-empted, and the main loop changes the SysTick pre-emption priority accordingly. |
| Source files | src/main.c: main, KeyInputExtiInit, Delay and the PreemptionPriorityValue and Key_Status definitions;inc/main.h: key pin and EXTI4 channel macros and function declarations;src/n32g41x_it.c, inc/n32g41x_it.h: interrupt service functions such as SysTick_Handler and EXTI4_IRQHandler;readme.txt: function, environment and usage;MDK-ARM/, EWARM/: Keil and IAR projects. |
| Key configuration | Clock source HSI+PLL, 80 MHz for N32G412 and 96 MHz for N32G415; KEY1 is PA4 in GPIO_MODE_INPUT with GPIO_PULL_UP, mapped to EXTI_LINE4 with falling-edge trigger;the priority grouping is NVIC_PriorityGroup_2;EXTI4_IRQn uses pre-emption priority 1 and subpriority 0;SysTick_IRQn starts at pre-emption priority 0 and is changed to pre-emption priority 2 while Key_Status is 1;the main loop inserts its delay with Delay(0x8FFFFF). |
| Program and data path | main prints NVIC IRQ Priority and calls KeyInputExtiInit, then uses NVIC_SetPriority to set the SysTick_IRQn pre-emption priority to 0;the main loop prints the state from Key_Status and, when it is 1, changes the SysTick pre-emption priority to PreemptionPriorityValue + 2;EXTI4_IRQHandler writes the PENDSTSET bit of SCB->ICSR to pend the SysTick exception, and SysTick_Handler uses NVIC_GetActive to tell whether EXTI4 is still executing, setting Key_Status to 1 if so and to 2 otherwise. |
| Main APIs | NVIC_PriorityGroupConfig, NVIC_Init, NVIC_SetPriority, NVIC_EncodePriority, NVIC_GetPriorityGrouping, NVIC_GetActive, GPIO_InitPeripheral, GPIO_ConfigEXTILine, EXTI_InitPeripheral |
| Verification | During operation the serial port prints the SysTick interrupt information and the Key_Status state;after a press on KEY1 triggers the external interrupt, a simultaneous EXTI4 and SysTick trigger changes the SysTick pre-emption priority to 2 and the serial port prints Key_Status = 1 and NVIC IRQ Priority Test End. |
| Use note | Supports the N32G412 and N32G415 chips; the development environment is KEIL MDK-ARM V5.34 or IAR EWARM 8.50.1; the key is KEY1 (PA4) on the evaluation board. |
Core-code walkthrough and porting
The example puts the priority grouping inside the key initialization, uses the CMSIS priority interfaces to set the SysTick pre-emption priority, and passes the pre-emption result between the interrupts and the main loop through a state variable.
Data path: KeyInputExtiInit → NVIC_PriorityGroupConfig and NVIC_Init set the key priority → NVIC_SetPriority writes the SysTick priority with NVIC_EncodePriority and NVIC_GetPriorityGrouping → EXTI4_IRQHandler writes SCB->ICSR to pend SysTick → SysTick_Handler samples with NVIC_GetActive and sets Key_Status → the main loop calls NVIC_SetPriority again according to the state
1. Set the SysTick priority through the CMSIS interfaces. After initializing the key interrupt, main reads the current grouping with NVIC_GetPriorityGrouping, encodes the pre-emption priority and the subpriority with NVIC_EncodePriority and hands the result to NVIC_SetPriority; the pre-emption priority variable starts at 0.
KeyInputExtiInit(KEY_INPUT_PORT, KEY_INPUT_PIN);
/* Configure the SysTick Handler Priority: Preemption priority(0) and subpriority */
NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), PreemptionPriorityValue, 0));
NVIC_GetPriorityGrouping and NVIC_EncodePriority keep the encoding consistent with the actual grouping; the grouping should not be rewritten by another initialization before NVIC_SetPriority is used to change a priority.
2. Raise the SysTick pre-emption priority at run time according to the state. The main loop re-reads Key_Status on every pass: at 1 it changes the SysTick pre-emption priority to PreemptionPriorityValue + 2, at 2 it prints the end of the test, and otherwise it prints Key_Status = 0.
while (1)
{
if (Key_Status == 1)
{
log_info("Key_Status = 1 \r\n");
/* Configure the SysTick Handler Priority: Preemption priority(2) and subpriority */
NVIC_SetPriority(SysTick_IRQn,
NVIC_EncodePriority(NVIC_GetPriorityGrouping(), PreemptionPriorityValue + 2, 0));
}
else if (Key_Status == 2)
{
log_info("NVIC IRQ Priority Test End \r\n");
}
else
{
log_info("Key_Status = 0 \r\n");
}
/* Insert delay Time */
Delay(0x8FFFFF);
}
A smaller pre-emption priority number means a higher priority, so the + 2 lowers the SysTick pre-emption priority; the subpriority is always passed as 0 because the key interrupt subpriority is 0 as well.
3. Pend the SysTick exception from the key interrupt. After confirming that EXTI4 is pending, EXTI4_IRQHandler writes the PENDSTSET bit of SCB->ICSR so that the SysTick exception is pended before the key interrupt returns, and then clears the EXTI pending bit.
if (EXTI_GetStatusFlag(KEY_INPUT_EXTI_LINE) != RESET)
{
/* Generate SysTick exception */
SCB->ICSR |= 0x04000000;
/* Clears the SEL Button EXTI line pending bits */
EXTI_ClrStatusFlag(KEY_INPUT_EXTI_LINE);
}
Writing the PENDSTSET bit of SCB->ICSR only makes the SysTick exception pending; whether it pre-empts immediately depends on the pre-emption priority of SysTick relative to the interrupt being serviced.
4. Judge the pre-emption relationship inside the SysTick interrupt. SysTick_Handler uses NVIC_GetActive to read whether the key interrupt is still active: still active means the key interrupt was pre-empted by SysTick, so it sets Key_Status to 1, and otherwise to 2, for the main loop to read.
/* If the EXTI4 IRQ Handler was preempted by SysTick Handler */
if (NVIC_GetActive(KEY_INPUT_IRQn) != 0)
{
Key_Status = 1;
}
else
{
Key_Status = 2;
}
NVIC_GetActive reads the active state of an interrupt rather than its pending state; polling it from the main loop would be disturbed by the changing pre-emption relationship, so the example only uses the sample taken inside the interrupt.
Corresponding source files: src/main.c, src/n32g41x_it.c, inc/main.h
5.14.3.3 NVIC_VectorTable_Relocation vector table relocation
Example directory: projects/n32g41x_EVAL/examples/NVIC/NVIC_VectorTable_Relocation/
Enable the GPIO clock and configure the key external interrupt→Set the EXTI4 pre-emption priority and subpriority→A key press triggers the external interrupt and sets Key_Status→The main loop relocates the interrupt vector table from FLASH to SRAM→The program stays in an empty loop after the relocation
| Item | Source analysis |
|---|---|
| Function | Demonstrates interrupt vector table relocation: after a key press triggers the PA4 external interrupt, the interrupt vector table is relocated from FLASH to SRAM and the relocation is reported over the serial port. |
| Source files | src/main.c: main, KeyInputExtiInit and the Key_Status definition;inc/main.h: VECT_TAB_FLASH_OFFSET, VECT_TAB_SRAM_OFFSET and the key pin and EXTI4 channel macros;src/n32g41x_it.c, inc/n32g41x_it.h: interrupt service functions such as EXTI4_IRQHandler;readme.txt: function, environment and usage;MDK-ARM/, EWARM/: Keil and IAR projects. |
| Key configuration | Clock source HSI+PLL, 80 MHz for N32G412 and 96 MHz for N32G415; KEY1 is PA4 in GPIO_MODE_INPUT with GPIO_PULL_UP, mapped to EXTI_LINE4 with falling-edge trigger;the priority grouping is NVIC_PriorityGroup_2;EXTI4_IRQn uses pre-emption priority 0 and subpriority 0;the relocation target is NVIC_VectTab_RAM plus the offset VECT_TAB_SRAM_OFFSET (0x00010000). |
| Program and data path | main prints NVIC VectorTable Relocation and calls KeyInputExtiInit to configure the key EXTI and its interrupt priority;the main loop polls Key_Status and, once it becomes ENABLE, prints the notice, calls NVIC_SetVectorTable to write SCB->VTOR and enters an empty while(1) loop;EXTI4_IRQHandler sets Key_Status to ENABLE and clears the EXTI pending bit while the project does not define VECT_TAB_SRAM. |
| Main APIs | NVIC_PriorityGroupConfig, NVIC_Init, NVIC_SetVectorTable, GPIO_InitPeripheral, GPIO_ConfigEXTILine, EXTI_InitPeripheral |
| Verification | After a reset the interrupt vector table is initially in FLASH; after a press on KEY1 triggers the external interrupt, the serial port prints EXTI4 IRQHandler Start, EXTI4 IRQHandler is executed(FLASH) (the project does not define VECT_TAB_SRAM) and Sets the vector table location and Offset, and the program then stays in the empty loop. |
| Use note | Supports the N32G412 and N32G415 chips; the development environment is KEIL MDK-ARM V5.34 or IAR EWARM 8.50.1; the key is KEY1 (PA4) on the evaluation board. |
Core-code walkthrough and porting
The example uses the key interrupt as the trigger condition, calls the vector table relocation interface from the main loop, and then stays in an empty loop without returning.
Data path: main → KeyInputExtiInit configures the key EXTI and its priority → EXTI4_IRQHandler sets Key_Status to ENABLE → the main loop calls NVIC_SetVectorTable to write SCB->VTOR → the program enters the empty loop
1. Read the offset macros first. inc/main.h gives the FLASH and the SRAM vector table offsets as two macros; the example uses only the SRAM offset, whose value is 0x00010000.
#define VECT_TAB_FLASH_OFFSET ((uint32_t)0x00000000)
#define VECT_TAB_SRAM_OFFSET ((uint32_t)0x00010000)
2. Give the key interrupt priority in the initialization. KeyInputExtiInit configures the grouping first and then sets EXTI4_IRQn to pre-emption 0 and subpriority 0.
/* Configure two bits for preemption priority */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
/* Set key input interrupt priority */
NVIC_InitStructure.NVIC_IRQChannel = KEY_INPUT_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = NVIC_PRE_PRIORITY_0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = NVIC_SUB_PRIORITY_0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
3. The interrupt service function has two branches selected by a macro. EXTI4_IRQHandler uses conditional compilation to give different behaviour depending on whether VECT_TAB_SRAM is defined: when it is defined only the SRAM branch notice is printed, and when it is not defined Key_Status is set to ENABLE; the project target macros are N32G412 and N32G415, VECT_TAB_SRAM is not defined, so the #else branch runs.
#ifdef VECT_TAB_SRAM
log_info("EXTI4 IRQHandler is executed(SRAM) \r\n");
#else
/* Key_Status */
Key_Status = ENABLE;
log_info("EXTI4 IRQHandler is executed(FLASH) \r\n");
#endif
4. The main loop performs the relocation and then stops. Once Key_Status has become ENABLE, main calls NVIC_SetVectorTable to change the vector table base to NVIC_VectTab_RAM plus the offset, and then enters an empty loop that never returns.
if (Key_Status == ENABLE)
{
log_info("Sets the vector table location and Offset \r\n");
/* Vector Table Relocation in Internal SRAM. */
NVIC_SetVectorTable(NVIC_VectTab_RAM, VECT_TAB_SRAM_OFFSET);
while (1)
;
}
After the relocation the interrupt vectors come from the table in SRAM; the offset argument of NVIC_SetVectorTable should be a multiple of 0x200 as its comment requires, so a changed offset value needs to respect that alignment.
Corresponding source files: src/main.c, src/n32g41x_it.c, inc/main.h
5.14.4 Notes and troubleshooting
| Scenario | Check & action | Source |
|---|---|---|
| A peripheral interrupt gets no response | The interrupts and events chapter of the user manual states that generating an interrupt requires the NVIC interrupt channel of the corresponding line to be configured and enabled; setting only the peripheral or EXTI interrupt enable bit without opening the matching NVIC channel leaves the interrupt unserviced by the core. |
User manual |
| Interrupt channel and priority range | The user manual states that the device has 47 maskable interrupt channels (excluding the 16 ARM Cortex-M4 interrupts) and supports 16 interrupt priority levels;NVIC_IRQChannel and the pre-emption and subpriority values must stay within that range. |
User manual |
| Fixed core exception priorities | The vector table in the user manual lists Reset, NMI and HardFault with a fixed priority type (priorities -3, -2 and -1 respectively) that is not affected by the priority grouping setting or by NVIC_Init. |
User manual |
| The 1 ms SysTick time base | The user manual states that the SysTick calibration value is fixed at 8000 and that a 1 ms time base is produced when the SysTick clock is set to 8 MHz (the maximum HCLK/8); use that combination when timing with SysTick or configuring its period. |
User manual |
The N32G412 and N32G415 series errata sheet V1.0.0 (2026.6.30) lists a single row for revision A chips with an empty errata link column, and gives no NVIC-related entries.