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:

  1. 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
    
  2. 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
    
  3. 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
    
  4. 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
    
  5. 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.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *