Copy interrupt vector from flash to RAM at startup (ARM7)

Technical Note 27158






11/6/2015 1:51 PM


This Technical Note discusses how to locate the ARM7/9 interrupt vector in RAM, and initialize the interrupt vector automatically in the startup code.


Using the simulator

The example project ( is built for and debugged in the Simulator. The Simulator is good enough as the focus in this technical note is at the mechanism of initialization of a vector table at startup.

Assumption on the memory map of the simulated device

The assumption is that the device has...

Flash at 0x1000000 to 0x100FFFF


RAM at 0x2000000 to 0x2007FFF

...and at startup, flash is mirrored to...

0x0000000 to 0x000FFFF

...while after remap, RAM is mirrored to...

0x0000000 to 0x0007FFF

Remap (not covered in the example)

Remap is not covered here, as remap in done different ways in ARM7/9-devices from different chip vendors.

The theoretical assumption (in this Tech Note and its' example) is that Remap is done in __low_level_init(), that is, before initialization is done. 


The reason for a special solution

The IAR ILINK linker will normally not generate code for copy-initialization of a vector table. But the IAR ILINK linker can be informed that it should initialize the vector table.

Additions in a startup .s file

Additions that need to be done:

  • Add a second vector table, i.e. the vector table that will be located in RAM. (In the example, the RAM vector table is just a copy-paste of the original vector table's source code.)
  • Place this vector table in its own section. (In the example this section has the name .intvec_RAM)
  • Give the vector table its own label. (In the example this label is __vector_RAM)
  • At the line above the vector table's label, add this special label __iar_init$$done: (This label tells ILINK that it is OK to initialize this vector table at startup.)

Additions in the .icf file

The changes in the .icf file are:

define symbol _region_COPY_start__ = 0x00;
define symbol _region_COPY_end__ = 0x7F;
define region COPY_region = mem:[from _region_COPY_start__ to _region_COPY_end__];

initialize by copy { section .intvec_RAM };
define block RamCode { section .intvec_RAM };
define block RamCodeInit { section .intvec_RAM_init };
place in ROM_region { block RamCodeInit };
place in COPY_region { block RamCode };

Where the details are:

The lines...

define symbol _region_COPY_start__   = 0x00;
define symbol _region_COPY_end__     = 0x7F;
define region COPY_region = mem:[from _region_COPY_start__ to _region_COPY_end__];

...are added in order to define the region to where copying will be done.

The line...

initialize by copy { section .intvec_RAM };

...informs ILINK that this section is to be initialized.

In the line...

define block RamCodeInit { section .intvec_RAM_init };

... the section .intvec_RAM_init part informs ILINK (by the use of the string _init that the block will hold the initializer data (in flash) for section .intvec_RAM .

The final change in the .icf file is that the IAR ILINK linker should not place any 'normal' data/code in the lowermost 0x80 bytes of the RAM and flash memories, all in order not to overwrite the interrupt vector in RAM. So the start addresses are adjusted to

define symbol __ICFEDIT_region_ROM_start__ = 0x1000080;
define symbol __ICFEDIT_region_RAM_start__ = 0x2000080;

To use the example


Close all editor tabs in IAR Embedded Workbench for ARM and rebuild the project.

Start debugging

Start C-SPY. The application will halt at the label __iar_program_start: This is intentional as you can then see in the Memory Window that memory at address 0x00 (and up) are all zeroes.

Perform Go

The application will halt in main() as there is a breakpoint. You can now see in the Memory Window that address 0x00 (and up) now holds the copied vector table.

All product names are trademarks or registered trademarks of their respective owners.

We do no longer support Internet Explorer. To get the best experience of, we recommend upgrading to a modern browser such as Chrome or Edge.