The vector table is a key component in Cortex-M0 microcontrollers that contains the reset and exception vectors needed for the system to operate. By default, the vector table resides at the start of flash memory in these controllers. However, you may want to relocate it for several reasons – to place other code at the start of flash, to place it in RAM for faster exception handling, or to allow booting from an external memory device. Relocating the vector table requires configuring the Vector Table Offset Register (VTOR) and updating linker scatter files. This guide will walk through the steps needed to successfully relocate the vector table in Cortex-M0 based microcontrollers.
Introduction to the Vector Table
The vector table contains the initial stack pointer value and reset vector used on power up or reset. It also contains exception vector entries for handling events like interrupts, faults, and traps. For Cortex-M0, the vector table resides at address 0x00000000 in flash memory after reset. Each vector is 4 bytes long, so the full vector table occupies the first 256 bytes of flash.
Here is the default layout of the Cortex-M0 vector table:
- 0x00: Initial stack pointer value
- 0x04: Reset vector – points to reset handler code
- 0x08: NMI vector – points to NMI handler code
- 0x0C: HardFault vector – points to HardFault handler code
- 0x10: Reserved vector
- 0x14: Reserved vector
- 0x18: Reserved vector
- 0x1C: Reserved vector
- 0x20: SVCall vector – points to SVCall handler code
- 0x24: Reserved vector
- …
The vector table is a key part of exception handling in Cortex-M0. When an exception occurs like an interrupt or fault, the processor will jump to the corresponding vector entry to run the associated handler code. So relocating the vector table requires retaining this table structure and updating the code locations.
Reasons to Relocate the Vector Table
There are several common reasons you may want to relocate the vector table in Cortex-M0:
- Place other code at the start of flash – The vector table occupies the first 256 bytes of flash memory by default. You may want to place other code like main() at address 0x00000000 instead.
- Locate it in RAM for faster exception handling – Storing the vector table in RAM can allow faster jumps to exception handlers since flash has longer access times.
- Boot from external memory – Relocating the vector table is required if you want to boot from an external memory device.
- Security reasons – Spreading out code over memory can make some vulnerabilities harder to exploit.
The steps needed to actually relocate the vector table are covered next.
Relocating the Vector Table
Here are the key steps required to relocate the vector table in Cortex-M0 based microcontrollers:
- Select a new location – First decide on the new address for the vector table, either in flash or RAM. Ensure no other code uses that space.
- Set the VTOR register – The Vector Table Offset Register (VTOR) holds the vector table base address. Update this register with the new vector table address.
- Update linker scatter file – The linker file defines where code and data sections get placed in memory. Update it to place the vector table section at the new address.
- Rebuild code with new vector table location – Compile your code so the new vector table address gets used on reset and exceptions.
- Redirect interrupts if required – If relocating the vector table to RAM, update interrupt vector locations to point to code still in flash.
Detailed explanations for each step are provided in the following sections.
1. Select a New Vector Table Location
First, choose an available address for the new vector table location. Some options:
- Start of RAM (e.g. 0x20000000)
- End of flash memory
- External RAM or flash chip address space
Ensure no existing code uses the new vector table address range. The vector table requires 256 contiguous bytes. Also align the address on a 256 byte boundary for best performance.
2. Configure the VTOR Register
The VTOR register specifies the vector table base address. To relocate the vector table, this register must be updated to point to the new location.
In Cortex-M0, the VTOR register is a 32-bit register located at address 0xE000ED08. Write the new vector table address to this register before any exceptions occur. This is often done early in the reset handler code.
For example, to set the VTOR to 0x20000000 for a vector table located at the start of RAM: /* Reset handler */ void Reset_Handler() { // Update VTOR with new vector table address SCB->VTOR = 0x20000000; // Rest of reset handler code }
After this, exceptions will use the vector table at the new RAM address.
3. Update the Linker Scatter File
The linker scatter file defines the memory map – where code and data sections get placed. To move the vector table, the scatter file must be updated.
For example, a default scatter file may define the vector table section .vectors like this: LR_IROM1 0x00000000 0x00000400 { ; load region size_region ER_IROM1 0x00000000 0x00000400 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) } .vectors 0x00000000 0x000001000 { ; vector table placed at start of IRAM } …
To move it, change the .vectors address. For example: LR_IROM1 0x00000000 0x00000400 { ER_IROM1 0x00000000 0x00000400 { *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) } … .vectors 0x20000000 0x00000100 { ; vector table placed at start of RAM }
Ensure the new address has at least 256 bytes allocated. Rebuild the code with the updated scatter file to place the vector table correctly.
4. Rebuild Code with New Settings
Next, rebuild your Cortex-M0 project with the new VTOR and scatter file settings. The generated code will now use the relocated vector table. Make sure to set the VTOR register early in your startup code before exceptions are handled.
Test that the reset and exception handlers are called correctly after relocating the vector table.
5. Redirect Interrupts If Needed
One special case is relocating the vector table to RAM. Since RAM is erased on reset, interrupt vectors can’t point directly to handler code in RAM. Instead, they need to point back to code in flash memory.
For ARMv6-M (Cortex-M0), this can be done using a special Interrupt Vector Table Offset Register (VTOR). This register adds an offset to all exception vector fetches, allowing them to indirectly reference code in flash.
So if you move the vector table itself to 0x20000000 in RAM, set the IVT offset to 0xFFFF0000 using: SCB->VTOR = 0x20000000; // Relocated vector table in RAM SCB->IVT_OFS = 0xFFFF0000; // Interrupt vectors point to flash
With this offset, an interrupt vector containing 0x00001234 would point to 0xFFFF1234 in flash when fetched by the processor.
Conclusion
Relocating the vector table in Cortex-M0 microcontrollers provides flexibility in the memory layout. It requires configuring the VTOR register, updating scatter files, and potentially redirecting interrupts. With these steps completed, you can take advantage of a custom vector table location.
Understanding the vector table and relocation process enables creating more advanced embedded firmware. The techniques covered in this guide apply across the entire Cortex-M family, with slight differences in register names and features. Refer to the reference manual for your specific Cortex-M MCU for complete details when relocating the vector table.