This Technical Note applies to IAR Embedded Workbench for ARM version 5.20 and later. The wanted behavior is to run all code in RAM to gain execution speed.
The toolchain has features to make it possible to copy all (or most) of the code to RAM at program startup. In order to take advantage of these features there are 4 actions to take.
These are the steps, in detail, that needs to be taken in order change your application to be able to run from RAM.
The 2 parallel examples are meant to show the differences between these ARM cores, and between these chip manufacturers.
Example projects:
Cortex-M3 (AT91SAM3U)
Modifications are made in the board_cstartup_iar.c file located in \arm\examples\Atmel\at91lib\boards\at91sam3u-ek
Added C function:
void DummyHandlerROM(void)
Edited all entries except __iar_program_start and .__ptr = __sfe( "CSTACK" ) }, in ...
const IntVector __vector_table[] =
{
{ .__ptr = __sfe( "CSTACK" ) },
__iar_program_start,
DummyHandlerROM,
DummyHandlerROM,
DummyHandlerROM,
DummyHandlerROM,
...to point to DummyHandlerROM();
Added 2nd vector table placed in RAM...
__root const IntVector __vector_RAM_table[];
...which hold all vectors
{ .__ptr = __sfe( "CSTACK" ) },
__iar_program_start,
NMI_Handler,
HardFault_Handler,
ARM 7 (LPC2148)
Modifications are made in the cstartup.s file located in \arm\examples\NXP\IAR-LPC-214X\LCD\board
Added assembler function:
Dummy_Handler_ROM
Changed IRQ and FIQ ...
DC32 __iar_program_start ;; Reset
DC32 0 ;; Undefined instructions
DC32 0 ;; Software interrupt (SWI/SVC)
DC32 0 ;; Prefetch abort
DC32 0 ;; Data abort
DC32 0 ;; RESERVED
DC32 Dummy_Handler_ROM ;; IRQ
DC32 Dummy_Handler_ROM ;; FIQ
...to point to Dummy_Handler_ROM
Added 2nd vector table placed in RAM...
SECTION .intvec_RAM:CODE:ROOT(2)
...which hold vectors for IRQ and FIQ
ldr pc,[pc,#+24] ;; IRQ
ldr pc,[pc,#+24] ;; FIQ
DC32 irq_handler ;; IRQ
DC32 fiq_handler ;; FIQ
Cortex-M3 (AT91SAM3U)
Modifications are made in the flash.icf file located in \arm\examples\Atmel\at91lib\boards\at91sam3u-ek\at91sam3u4
The start of the RAM region has to be adjusted so that the vectors in RAM fit below the RAM region.
define symbol __ICFEDIT_region_RAM0_start__ = 0x200000BC;
A symbol holding the address of the interrupt vectors in RAM is added.
define symbol RAM_vectors_start = 0x20000000;
The linker adds code for copying CODE to RAM when the below line is changed from...
initialize by copy { readwrite };
...to...
initialize by copy { readonly, readwrite };
...which is documented in the Development Guide, section "Running all code from RAM".
The interrupt vectors are copied to RAM, using the linker directive:
place at address mem:RAM_vectors_start { section .vectors_RAM };
ARM 7 (LPC2148)
Modifications are made in the Flash.icf file located in \arm\examples\NXP\IAR-LPC-214X\LCD\config
The size of the ordinary C stack has to be adjusted up, (with space taken from the IRQ and FIQ stacks).
define symbol __ICFEDIT_size_cstack__ = 0x2000;
define symbol __ICFEDIT_size_irqstack__ = 0x100;
define symbol __ICFEDIT_size_fiqstack__ = 0x100;
A symbol holding the address of the interrupt vectors in RAM is added.
define symbol RAM_intvec_start = 0x40000000;
The linker adds code for copying CODE to RAM when the below line is changed from...
initialize by copy { readwrite };
...to...
initialize by copy { readonly, readwrite };
...which is documented in the Development Guide, section "Running all code from RAM".
The interrupt vectors are copied to RAM, using the linker directive:
place at address mem:RAM_intvec_start { section .intvec_RAM };
Cortex-M3 (AT91SAM3U)
One final modification is made to board_cstartup_iar.c located in \arm\examples\Atmel\at91lib\boards\at91sam3u-ek
The Cortex-M3 register VTOR holds the address of the vector table.
The source of...
unsigned int * src = __section_begin(".vectors");
... is changed to ...
unsigned int * src = __section_begin(".vectors_RAM");
...where the variable 'src' is used a few lines below to set VTOR, so that the vector table in RAM is used.
ARM 7 (LPC2148)
One modification is made to demo.c located in \arm\examples\NXP\LPC214x\IAR-LPC-214X\LCD\app
The MEMMAP register is set to RAM which forces the LPC2148 to remap the 0x40 lowest bytes of RAM down to address 0x00, thus starting to use the vector table in RAM.
The source of...
#ifdef FLASH
if (SYS_Init(FOSC, FCCLK, VPBDIV1, USER_FLASH,
0x0001FF0F,0x87FE01F1,0,0xFFFFFFFF))
return 1;
#else
if (SYS_Init(FOSC, FCCLK, VPBDIV1, USER_RAM,
0x0001FF0F,0x87FE01F1,0,0xFFFFFFFF))
return 1;
#endif
... is changed to ...
if (SYS_Init(FOSC, FCCLK, VPBDIV1, USER_RAM,
0x0001FF0F,0x87FE01F1,0,0xFFFFFFFF))
return 1;
... in order to set MEMMAP to RAM, and to disable the unwanted (in this context) flash-protection source.
Check these sections of the .map file
- PLACEMENT SUMMARY check in which memory objects are placed
- MODULE SUMMARY check placements of objects ("ro code" vs "rw code")
- ENTRY LIST check addresses of functions
The MODULE SUMMARY, as well as the summary at the end of the map file, shows the result.
Cortex-M3 (AT91SAM3U) Original Example 368 bytes of readonly data memory
2 245 bytes of readonly data memory |
Cortex-M3 (AT91SAM3U) Modified Example ARM 7 (LPC2148) Modified Example |
Notes
The linker protects sections that are referenced from the startup code from being affected by an 'initialize by copy' directive.
This includes
So the linker ensures that only code that runs after copy initialization has been finished will be copied to RAM. For this reason it is safe to add readonly in the
initialize by copy { readonly, readwrite }; command.
The linker log (option --log sections) is extended in IAR Embedded Workbench for ARM 6.10 with information of symbols marked as 'needed for init'.
In Note A it is explained that the linker protects code used/referenced from startup. Furthermore the linker algorithm to figure out which code that's needed by the initialization process at startup marks all code in a module (i.e. a compiled file is a mdoule) and not only code referenced from cstartup, e.g. all code in a module where referenced interrupt handlers are defined.
So the suggested construction will minimize the amount of code that is placed in ROM/flash.
Up to version 5.30 there was requirement of LPC specific labels in the vector table. These labels where the copying cannot be done by the initialization process at startup, because of the special (for ARM7/9 LPC-devices) __vector_0x14 (and __vector_0x1C for Cortex-M-devices), holding the checksum of the interrupt vectors. This checksum is calculated by ielftool after ilinkarm, but ielftool cannot calculate the checksum when changes are made to cstartup.s to enable automatic copying of the interrupt vectors, i.e. breaking references of what's needed by the initialization process at startup.
To cope with these two issues, the interrupt vectors are split into one part placed in ROM (used only by code in ROM) and another part placed in RAM (used by code in the application).
All product names are trademarks or registered trademarks of their respective owners.