Incorrect NVIC Configuration and Vector Table Handling on STM32F103
The core issue revolves around the misconfiguration of the Nested Vectored Interrupt Controller (NVIC) and improper handling of the vector table in an STM32F103 microcontroller. The user is attempting to configure Timer 6 (TIM6) interrupts but is encountering issues where the interrupts are not firing as expected. The root cause lies in the incorrect assumption about the vector table’s location and the improper use of the Vector Table Offset Register (VTOR). Additionally, the NVIC configuration for enabling the TIM6 interrupt is not correctly implemented, leading to a failure in interrupt handling.
The STM32F103 microcontroller uses the ARM Cortex-M3 core, which relies on a vector table to manage interrupt service routines (ISRs). The vector table is typically located at the start of the flash memory (0x08000000 for STM32 devices), but the user is attempting to write directly to an address (0x00000118) that is not valid for runtime modifications. This misunderstanding of the memory map and the role of the VTOR register is the primary source of the problem.
Misaligned Vector Table Address and Flash Memory Access
The user’s code attempts to write the address of the TIM6 interrupt handler directly to 0x00000118, which is incorrect for several reasons. First, the STM32F103 microcontroller has a bootloader located at the beginning of the memory map (0x00000000), and the actual flash memory starts at 0x08000000. The vector table is initially located at 0x00000000 but is remapped to 0x08000000 by the bootloader during startup. Writing to 0x00000118 does not modify the actual vector table in flash memory because flash memory cannot be directly written to during runtime without special procedures.
Furthermore, the user’s code does not account for the VTOR register, which is used to relocate the vector table to a different memory location, such as SRAM. The VTOR register (located at 0xE000ED08) must be configured to point to the new vector table location before any modifications to the vector table can take effect. The user’s initial approach of writing directly to 0x00000118 is invalid because it does not respect the memory map and the role of the VTOR register.
Proper VTOR Configuration and NVIC Initialization for TIM6 Interrupts
To resolve the issue, the following steps must be taken:
-
Relocate the Vector Table to SRAM: The vector table must be copied from flash memory to SRAM, and the VTOR register must be updated to point to the new location. This allows runtime modifications to the vector table. The following code demonstrates how to copy the vector table to SRAM and configure the VTOR register:
copy_vectors_table: mov32 r1, 0x08000000 @ Source address (flash vector table) mov32 r2, 0x20000000 @ Destination address (SRAM) mov32 r3, #76 @ Number of bytes to copy (76 bytes for Cortex-M3 vector table) cvt_l0: ldr r0, [r1], #4 @ Load word from flash str r0, [r2], #4 @ Store word to SRAM subs r3, #4 @ Decrement byte count bne cvt_l0 @ Repeat until all bytes are copied mov32 r1, 0xE000ED08 @ VTOR register address mov32 r0, 0x20000000 @ New vector table base address in SRAM str r0, [r1] @ Update VTOR
-
Configure the TIM6 Interrupt in the Relocated Vector Table: After relocating the vector table, the address of the TIM6 interrupt handler must be written to the correct offset in the new vector table. The TIM6 interrupt vector is located at offset 0x0118 in the vector table. The following code demonstrates how to set the TIM6 interrupt handler address:
mov32 r1, 0x20000118 @ TIM6 interrupt vector address in SRAM adr r0, tim6_interrupt_observer @ Address of TIM6 ISR str r0, [r1] @ Store ISR address in vector table
-
Enable the TIM6 Interrupt in the NVIC: The NVIC must be configured to enable the TIM6 interrupt. The TIM6 interrupt number is 54, and it is enabled by setting the corresponding bit in the NVIC Interrupt Set Enable Register (ISER1). The following code demonstrates how to enable the TIM6 interrupt:
mov32 r1, 0xE000E104 @ NVIC_ISER1 address ldr r0, [r1] @ Load current value of ISER1 orr r0, #0x00400000 @ Set bit 22 (TIM6 interrupt) str r0, [r1] @ Enable TIM6 interrupt
-
Configure TIM6 for Interrupt Generation: The TIM6 peripheral must be configured to generate update interrupts. This involves setting the prescaler, counter value, and enabling the update interrupt in the TIM6_DIER register. The following code demonstrates the TIM6 configuration:
mov32 r1, 0x40001028 @ TIM6_PSC address movw r0, 0x270F @ Set prescaler to 9999 strh r0, [r1] @ Write prescaler value mov32 r1, 0x40001024 @ TIM6_CNT address movw r0, 0x0707 @ Set counter value strh r0, [r1] @ Write counter value mov32 r1, 0x4000100C @ TIM6_DIER address movw r0, 0x0001 @ Enable update interrupt strh r0, [r1] @ Write DIER value mov32 r1, 0x40001000 @ TIM6_CR1 address ldrh r0, [r1] @ Load current CR1 value orr r0, #0x0001 @ Enable TIM6 counter strh r0, [r1] @ Write CR1 value
-
Implement the TIM6 Interrupt Handler: The TIM6 interrupt handler must clear the interrupt flag and perform the desired actions. The following code demonstrates a basic TIM6 interrupt handler:
tim6_interrupt_observer: mov32 r1, 0x40001010 @ TIM6_SR address movw r0, 0x0000 @ Clear interrupt flag strh r0, [r1] @ Write SR value @ Add additional logic here (e.g., toggle GPIO pin) bx lr @ Return from interrupt
By following these steps, the TIM6 interrupt will be correctly configured, and the vector table will be properly relocated to SRAM, allowing runtime modifications. This ensures that the TIM6 interrupt handler is invoked as expected when the timer generates an update event.
Summary of Key Points
Step | Description |
---|---|
Relocate Vector Table to SRAM | Copy the vector table from flash to SRAM and update the VTOR register. |
Configure TIM6 Interrupt Vector | Write the TIM6 interrupt handler address to the correct offset in the vector table. |
Enable TIM6 Interrupt in NVIC | Set the corresponding bit in NVIC_ISER1 to enable the TIM6 interrupt. |
Configure TIM6 Peripheral | Set the prescaler, counter value, and enable the update interrupt in TIM6_DIER. |
Implement TIM6 Interrupt Handler | Clear the interrupt flag and perform the desired actions in the ISR. |
This troubleshooting guide provides a comprehensive solution to the issues encountered with NVIC configuration and vector table handling on the STM32F103 microcontroller. By addressing the root causes and providing detailed steps for resolution, the TIM6 interrupt can be successfully implemented and tested.