EmbeddedRelated.com
Forums

relocating code in RAM with lpc2106.

Started by Milind Deshpande February 27, 2005

Hi,

I am a newbie doing firmware development on LPC2106 and using couple of interrupts for UART0 and TIMER1. The interrupts work fine when the code resides in flash.

However when I try to put the code in RAM for debug, the interrupts no longer work and so I cannot do any debug on UART0.
When putting the code in FLASH I am linking the code as below:

Code: 0x00000000 i.e. whole 128K for code.

Ram: 0x40000000 i.e. whole 64k for data.

Register E01FC040 = 0x0;
When putting the code in RAM I am linking the code as below:

Code: 0x40000000 i.e. 48K for Code

Ram: 0x4000C000 i.e. 15K for Data.

Register E01FC040 = 0x2;
The LPC manual does not say anything else for relocating the code in RAM, so I am not sure what is going wrong with my settings. Could someone please explain or let me know if I need to do any further settings to get the interrupts working in RAM.

Thanks in advance.
Regards

Milind __________________________________________________





RS485 bootloader ?

An Engineer's Guide to the LPC2100 Series



Milind Deshpande <> wrote:

Hi,

I am a newbie doing firmware development on LPC2106 and using couple of interrupts for UART0 and TIMER1. The interrupts work fine when the code resides in flash.

However when I try to put the code in RAM for debug, the interrupts no longer work and so I cannot do any debug on UART0.
When putting the code in FLASH I am linking the code as below:

Code: 0x00000000 i.e. whole 128K for code.

Ram: 0x40000000 i.e. whole 64k for data.

Register E01FC040 = 0x0;
When putting the code in RAM I am linking the code as below:

Code: 0x40000000 i.e. 48K for Code

Ram: 0x4000C000 i.e. 15K for Data.

Register E01FC040 = 0x2;
The LPC manual does not say anything else for relocating the code in RAM, so I am not sure what is going wrong with my settings. Could someone please explain or let me know if I need to do any further settings to get the interrupts working in RAM.

Thanks in advance.
Regards

Milind

---------

You should remap the interrupt vector table from 0x00000000 to 0x40000000,then your program will run in the ram as well as in the flash.
__________________________________________________
---------------------------------
Yahoo! Groups Links

To ---------------------------------


Hong Jiang <> schrieb am Mon, 28 Feb 2005 09:20:19
+0800 (CST):

Hong, check your email program to have correct quoting.

> You should remap the interrupt vector table from 0x00000000 to
> 0x40000000,then your program will run in the ram as well as in the flash.

He does set it correctly.

--
42Bastian Schick



Milind Deshpande <> schrieb am Sun, 27 Feb 2005
14:55:41 -0800 (PST):

> Code: 0x40000000 i.e. 48K for Code
>
> Ram: 0x4000C000 i.e. 15K for Data.
>
> Register E01FC040 = 0x2;

When do you write the MEMMAP register ? Before or after downloading ? --
42Bastian Schick




Hi All,

I am also facing the same problem.

I am trying to run the interrupts from SRAM and i have set that
MEMMAP register also.

But the interrupts are not working.

I am getting the interrupt but it's not going to SRAM vector table..

Please help me.

Thanks in advance.

Regards,
-Srinivas.

--- In , 42Bastian Schick <bastian42@m...>
wrote:
> Milind Deshpande <milind_pd@y...> schrieb am Sun, 27 Feb 2005
> 14:55:41 -0800 (PST):
>
> > Code: 0x40000000 i.e. 48K for Code
> >
> > Ram: 0x4000C000 i.e. 15K for Data.
> >
> > Register E01FC040 = 0x2;
>
> When do you write the MEMMAP register ? Before or after
downloading ?
>
>
> --
> 42Bastian Schick




I am writing to the MEMMAP register after download. The actual
command is the first line of my main() routine which was done as per
Ashling guide.

Milind

--- In , 42Bastian Schick <bastian42@m...>
wrote:
> Milind Deshpande <milind_pd@y...> schrieb am Sun, 27 Feb 2005
> 14:55:41 -0800 (PST):
>
> > Code: 0x40000000 i.e. 48K for Code
> >
> > Ram: 0x4000C000 i.e. 15K for Data.
> >
> > Register E01FC040 = 0x2;
>
> When do you write the MEMMAP register ? Before or after
downloading ?
>
>
> --
> 42Bastian Schick




Hello Milind;

Let us say...

You are attempting to do a very advanced thing with the LPC2xxx chip.
This is emminently doable though.

In general, you need to do the following:

Define your startup vector:
'the following is a code snippet from one of my projects'

AREA INTVECT, 'CODE_IVEC', READONLY, ALIGN=2 // READONLY, ALIGN=4
bytes
RSEG INTVECT
PUBLIC __startup
__startup PROC CODE32

// Pre-defined interrupt handlers that may be directly
// overwritten by C interrupt functions
EXTERN CODE32 (Undef_Handler?A)
EXTERN CODE32 (SWI_Handler?A)
EXTERN CODE32 (PAbt_Handler?A)
EXTERN CODE32 (DAbt_Handler?A)
EXTERN CODE32 (IRQ_Handler?A)
EXTERN CODE32 (FIQ_Handler?A)

// Exception Vectors
// Mapped to Address 0.
// Absolute addressing mode must be used.

vectors: LDR PC,Reset_Addr
LDR PC,Undef_Addr
LDR PC,SWI_Addr
LDR PC,PAbt_Addr
LDR PC,DAbt_Addr
NOP /* Reserved Vector */
; LDR PC,IRQ_Addr
LDR PC,[PC, #-0x0FF0] /* Vector from
VicVectAddr */
LDR PC,FIQ_Addr

Reset_Addr: DD Reset_Handler
Undef_Addr: DD Undef_Handler?A
SWI_Addr: DD SWI_Handler?A
PAbt_Addr: DD PAbt_Handler?A
DAbt_Addr: DD DAbt_Handler?A
DD 0 /* Reserved Address */
IRQ_Addr: DD IRQ_Handler?A
FIQ_Addr: DD FIQ_Handler?A
ENDP

As you can see, this vector consumes exactly 64 bytes of code!

Next, you need to relocate, (at runtime), your 64 byte interrupt
vector table that you created above.

Do this as follows:

Reset_Handler:
.... ; <--- some startup code here, (usually PINSEL programming)

/*****
Relocate interrupt vectors to internal RAM
***/
MEMMAP EQU 0xE01FC040 ; interrupt memory map
register

LDR R1,=__startup
MOV R0,#0x40000000
MOV R2,#0x10

copyLoop:
LDMIA R1!,{R3}
STMIA R0!,{R3}
SUBS R2,R2,#0x0001
BNE copyLoop

LDR R0,=MEMMAP
MOV R1,#0x02
STR R1, [R0]

In your 'C' code, you need to define your vectors such that they
reside in RAM. The Keil compiler has a real nifty way to do this via
the following LINKER directive:

CLASSES (ERAM (0x40000040-0x40001FFF))

This places all code that has been defined to store in flash, and
execute in RAM to be loaded at runtime into the RAM area.

That is, for every subroutine you define with the following Keil
modifier:

void my_interrupt_service (void) __irq __ram;

This __irq and __ram modifier does two things:
__irq compiles the subroutine as a service vector using ARM
instructions.

__ram places the entire subroutine into the ERAM segment that will
automatically get loaded into flash by the nifty Keil tool.

in lieu of the Keil tool, you must be able find a way relocate,
(copy)
your service vectors into ram at run time.

whew!

hope this helps;
Ken Wada



Re: relocating code in RAM with lpc2106.

Hi Ken,
Is it imperative that I have to set the MEMMAP register to 0x2
value, before I brach off to main()? From your code it seems that
way. Here is the snippet from my code. Let me know if you see
anything funky here.

Milind

/* Export list */
.global handle_uart0
.global handle_tmr0

/*#define ARM_RDP_MONITOR 0x01*/
/*#define ARM_RDI_MONITOR 0x01*/

/* Define some hardware locations */
.equ VICVecAddr, 0xfffff030 /* Address of
VICVectAddr register */

/********************************************************************
* Exception vector table - common to all ARM-based
systems *
********************************************************************
* Common to all ARM-based systems. Table entries just jump to
handlers using full 32-bit addressing.
****************************************/
_int_vectors:

ldr pc, do_reset_addr
ldr pc, do_undefined_instruction_addr
ldr pc, do_software_interrupt_addr
ldr pc, do_prefetch_abort_addr
ldr pc, do_data_abort_addr
/* .long 0xB9205F88 /* ARM-reserved
vector */
nop
ldr pc, [pc, #-0xff0] /* set PC (currently 0x18)
to VicVectAddr (0xFFFFF030) by - 0xFF0 */
ldr pc, do_fiq_addr

do_reset_addr: .long do_reset
do_undefined_instruction_addr: .long do_undefined_instruction
do_software_interrupt_addr: .long do_software_interrupt
do_prefetch_abort_addr: .long do_prefetch_abort
do_data_abort_addr: .long do_data_abort
do_fiq_addr: .long do_fiq

/********************************************************************
* Yet to be implemented exceptions
*********************************************************************
* Just fall through to reset exception handler for now
********************************************************************/ do_undefined_instruction:
do_software_interrupt:
do_prefetch_abort:
do_data_abort:
do_fiq:

/********************************************************************
* System reset handler
********************************************************************/
do_reset:

/* Set stack pointers for all modes used (supervisor, IRQ
and FIQ) */
ldr sp, =__stack_svc /* set supervisor mode
stack pointer */

msr cpsr_c, #0xd2 /* enter IRQ mode, with
interrupts disabled */

ldr sp, =__stack_irq /* set IRQ mode stack
pointer */

mov lr, #0x0 /* clear out other
IRQ shadow register */

msr cpsr_c, #0xd1 /* enter FIQ mode, with
interrupts disabled */

ldr sp, =__stack_fiq /* set FIQ mode stack
pointer */ /* Clear uninitialized data section (bss) */
ldr r4, =__start_bss /* First address*/
ldr r5, =__end_bss /* Last address*/
mov r6, #0x0

loop_zero:
str r6, [r4]
add r4, r4, #0x4
cmp r4, r5
blt loop_zero

/* Copy initialized data sections from ROM into RAM */
ldr r4, =_fdata /* destination address
*/
ldr r5, =_edata /* Last address*/
ldr r6, =_etext /* source address*/
cmp r4, r5
beq skip_initialize

loop_initialise:
ldr r3, [r6]
str r3, [r4]
add r4, r4, #0x4
add r6, r6, #0x4
cmp r4, r5
blt loop_initialise

skip_initialize: #if !defined(ARM_RDP_MONITOR) && !defined(ARM_RDI_MONITOR)
mov r0, #0 /* no arguments */
mov r1, #0 /* no argv either */
#else
/* Need to set up standard file handles */
bl initialise_monitor_handles
#endif

/* Enable interrupts, enter supervisor mode and branch to
start of 'C' code */

msr cpsr_c, #0x13 /* I=0 F=0 T=0 MODE=supervisor */
bl main

/********************************************************************
**********
* Interrupt
exceptions *
*********************************************************************
*********/

handle_uart0:
stmfd r13!, {r12, r14} /* save r12 & r14 */
mrs r12, spsr /* save the spsr */
stmfd r13!, {r12}
msr cpsr_c, #0x93 /* switch to sys mode */
stmfd r13!, {r0-r3, r14} /* save sys mode registers
*/
msr cpsr_c, #0x13 /* enable interrupts */
bl uartInterrupt /* go handle the interrupt
*/
msr cpsr_c, #0x93 /* disable interrupts */
ldmfd r13!, {r0-r3, r14} /* restore sys mode
registers */
msr cpsr_c, #0x92 /* switch back to irq mode
*/
ldmfd r13!, {r12} /* restore spsr */
msr spsr_cxsf, r12
ldmfd r13!, {r12, r14} /* restore r12 & r14 */
stmfd r13!, {r0-r1} /* save r0 & r1 */
ldr r0, =VICVecAddr /* update VIC */
mov r1, #0xff
str r1, [r0]
ldmfd r13!, {r0-r1} /* restore r0 & r1 */
subs pc, lr, #0x4 /* return from teh
interrupt */

handle_tmr0:
stmfd r13!, {r12, r14} /* save r12 & r14 */
mrs r12, spsr /* save the spsr */
stmfd r13!, {r12}
msr cpsr_c, #0x93 /* switch to sys mode */
stmfd r13!, {r0-r3, r14} /* save sys mode registers
*/
msr cpsr_c, #0x13 /* enable interrupts */
bl tmrInterrupt /* go handle the interrupt
*/
msr cpsr_c, #0x93 /* disable interrupts */
ldmfd r13!, {r0-r3, r14} /* restore sys mode
registers */
msr cpsr_c, #0x92 /* switch back to irq mode
*/
ldmfd r13!, {r12} /* restore spsr */
msr spsr_cxsf, r12
ldmfd r13!, {r12, r14} /* restore r12 & r14 */
stmfd r13!, {r0-r1} /* save r0 & r1 */
ldr r0, =VICVecAddr /* update VIC */
mov r1, #0xff
str r1, [r0]
ldmfd r13!, {r0-r1} /* restore r0 & r1 */
subs pc, lr, #0x4 /* return from teh
interrupt */ /*
* End of startup code
*/

.size _int_vectors,.-_int_vectors;

--- In , "kennethwada" <kwada@a...> wrote:
>
> Hello Milind;
>
> Let us say...
>
> You are attempting to do a very advanced thing with the LPC2xxx
chip.
> This is emminently doable though.
>
> In general, you need to do the following:
>
> Define your startup vector:
> 'the following is a code snippet from one of my projects'
>
> AREA INTVECT, 'CODE_IVEC', READONLY, ALIGN=2 // READONLY,
ALIGN=4
> bytes
> RSEG INTVECT
> PUBLIC __startup
> __startup PROC CODE32
>
> // Pre-defined interrupt handlers that may be directly
> // overwritten by C interrupt functions
> EXTERN CODE32 (Undef_Handler?A)
> EXTERN CODE32 (SWI_Handler?A)
> EXTERN CODE32 (PAbt_Handler?A)
> EXTERN CODE32 (DAbt_Handler?A)
> EXTERN CODE32 (IRQ_Handler?A)
> EXTERN CODE32 (FIQ_Handler?A)
>
> // Exception Vectors
> // Mapped to Address 0.
> // Absolute addressing mode must be used.
>
> vectors: LDR PC,Reset_Addr
> LDR PC,Undef_Addr
> LDR PC,SWI_Addr
> LDR PC,PAbt_Addr
> LDR PC,DAbt_Addr
> NOP /* Reserved Vector
*/
> ; LDR PC,IRQ_Addr
> LDR PC,[PC, #-0x0FF0] /* Vector from
> VicVectAddr */
> LDR PC,FIQ_Addr
>
> Reset_Addr: DD Reset_Handler
> Undef_Addr: DD Undef_Handler?A
> SWI_Addr: DD SWI_Handler?A
> PAbt_Addr: DD PAbt_Handler?A
> DAbt_Addr: DD DAbt_Handler?A
> DD 0 /* Reserved Address
*/
> IRQ_Addr: DD IRQ_Handler?A
> FIQ_Addr: DD FIQ_Handler?A
> ENDP
>
> As you can see, this vector consumes exactly 64 bytes of code!
>
> Next, you need to relocate, (at runtime), your 64 byte interrupt
> vector table that you created above.
>
> Do this as follows:
>
> Reset_Handler:
> .... ; <--- some startup code here, (usually PINSEL
programming)
>
> /*****
> Relocate interrupt vectors to internal RAM
> ***/
> MEMMAP EQU 0xE01FC040 ; interrupt memory map
> register
>
> LDR R1,=__startup
> MOV R0,#0x40000000
> MOV R2,#0x10
>
> copyLoop:
> LDMIA R1!,{R3}
> STMIA R0!,{R3}
> SUBS R2,R2,#0x0001
> BNE copyLoop
>
> LDR R0,=MEMMAP
> MOV R1,#0x02
> STR R1, [R0]
>
> In your 'C' code, you need to define your vectors such that they
> reside in RAM. The Keil compiler has a real nifty way to do this
via
> the following LINKER directive:
>
> CLASSES (ERAM (0x40000040-0x40001FFF))
>
> This places all code that has been defined to store in flash, and
> execute in RAM to be loaded at runtime into the RAM area.
>
> That is, for every subroutine you define with the following Keil
> modifier:
>
> void my_interrupt_service (void) __irq __ram;
>
> This __irq and __ram modifier does two things:
> __irq compiles the subroutine as a service vector using ARM
> instructions.
>
> __ram places the entire subroutine into the ERAM segment that will
> automatically get loaded into flash by the nifty Keil tool.
>
> in lieu of the Keil tool, you must be able find a way relocate,
> (copy)
> your service vectors into ram at run time.
>
> whew!
>
> hope this helps;
> Ken Wada




no; It is not imperative to set MEMMAP=0x2 as I did with the example.
You need to do this MEMMAP=2 at any time AFTER relocating your
vectors, and BEFORE starting up the interrupts, (startup via VIC
register setup).

By the way, I noticed throughout your code, this switching to/from
USER mode, and disabling/enabling interrupts in your vectors.

If you are currently processing an exception, the silicon
automatically switches the process to:
--> ARM format
--> SYSTEM mode

If you do not allow nesting of interrupts, (generally not recommended
to nest), then you do not need to do this (enabling/disabling
interrupts inside a vector). In general, you should not nest
interrupts in the ARM, for concern in regards to corrupting the SPSR
(shadow of CPSR) register. If you do the nesting, then you need to
define a shadow of a shadow! This gets really complicated.

In general, I have found no need to enable/disable interrupts. I have
done all atomic and monitor style operations using a pseudo-semaphore
technique that exploits the ARM SWI hardware. This is very nice, and
very much like the INT86 instruction that those Intel architectures
have. TI also supports hardware like this on their very fine DSP
cores!

You really ought to avoid enabling/disabling interrupts because of the
ARM cache vs. interrupt issues. This is a very dangerous area to
tread. I know most users hear are probably doing this a lot, and
probably see no problem with doing this. In fact, I believe this is
precisely the reason why Philips, in their users manual, writes 3-4
paragraphs on this, (spurious interrupts concerns).

I have worked many years with fully pipelined/cached architectures,
and one of the most difficult, (to prove, and to quantify) problems
with these architectures is cache pipeline vs asynchronous events,
(ie. enabling/disabling exceptions).

You really ought to let the ARM silicon do what it is really good at,
(resynchronizing itself), and leave the coding up to you.

The problem with this is, we embedded engineers, for many years are
used to non-pipelined cached architectures, and are not familiar with
some of the advanced interrupt techniques of the more modern
architectures. Once you learn this stuff, it is not hard to get very
nice reliable and robust systems cranked out.

Ken Wada

--- In , "milind_pd" <milind_pd@y...> wrote:
>
> Hi Ken,
> Is it imperative that I have to set the MEMMAP register to 0x2
> value, before I brach off to main()? From your code it seems that
> way. Here is the snippet from my code. Let me know if you see
> anything funky here.
>
> Milind
>
> /* Export list */
> .global handle_uart0
> .global handle_tmr0
>
> /*#define ARM_RDP_MONITOR 0x01*/
> /*#define ARM_RDI_MONITOR 0x01*/
>
> /* Define some hardware locations */
> .equ VICVecAddr, 0xfffff030 /* Address of
> VICVectAddr register */
/********************************************************************
> * Exception vector table - common to all ARM-based
> systems *
> ********************************************************************
> * Common to all ARM-based systems. Table entries just jump to
> handlers using full 32-bit addressing.
> ****************************************/
> _int_vectors:
>
> ldr pc, do_reset_addr
> ldr pc, do_undefined_instruction_addr
> ldr pc, do_software_interrupt_addr
> ldr pc, do_prefetch_abort_addr
> ldr pc, do_data_abort_addr
> /* .long 0xB9205F88 /* ARM-reserved
> vector */
> nop
> ldr pc, [pc, #-0xff0] /* set PC (currently 0x18)
> to VicVectAddr (0xFFFFF030) by - 0xFF0 */
> ldr pc, do_fiq_addr
>
> do_reset_addr: .long do_reset
> do_undefined_instruction_addr: .long do_undefined_instruction
> do_software_interrupt_addr: .long do_software_interrupt
> do_prefetch_abort_addr: .long do_prefetch_abort
> do_data_abort_addr: .long do_data_abort
> do_fiq_addr: .long do_fiq
/********************************************************************
> * Yet to be implemented exceptions
>
*********************************************************************
> * Just fall through to reset exception handler for now
>
********************************************************************/
>
>
> do_undefined_instruction:
> do_software_interrupt:
> do_prefetch_abort:
> do_data_abort:
> do_fiq:
/********************************************************************
> * System reset handler
>
********************************************************************/
> do_reset:
>
> /* Set stack pointers for all modes used (supervisor, IRQ
> and FIQ) */
> ldr sp, =__stack_svc /* set supervisor mode
> stack pointer */
>
> msr cpsr_c, #0xd2 /* enter IRQ mode, with
> interrupts disabled */
>
> ldr sp, =__stack_irq /* set IRQ mode stack
> pointer */
>
> mov lr, #0x0 /* clear out other
> IRQ shadow register */
>
> msr cpsr_c, #0xd1 /* enter FIQ mode, with
> interrupts disabled */
>
> ldr sp, =__stack_fiq /* set FIQ mode stack
> pointer */ > /* Clear uninitialized data section (bss) */
> ldr r4, =__start_bss /* First address*/
> ldr r5, =__end_bss /* Last address*/
> mov r6, #0x0
>
> loop_zero:
> str r6, [r4]
> add r4, r4, #0x4
> cmp r4, r5
> blt loop_zero
>
> /* Copy initialized data sections from ROM into RAM */
> ldr r4, =_fdata /* destination address
> */
> ldr r5, =_edata /* Last address*/
> ldr r6, =_etext /* source address*/
> cmp r4, r5
> beq skip_initialize
>
> loop_initialise:
> ldr r3, [r6]
> str r3, [r4]
> add r4, r4, #0x4
> add r6, r6, #0x4
> cmp r4, r5
> blt loop_initialise
>
> skip_initialize: > #if !defined(ARM_RDP_MONITOR) && !defined(ARM_RDI_MONITOR)
> mov r0, #0 /* no arguments */
> mov r1, #0 /* no argv either */
> #else
> /* Need to set up standard file handles */
> bl initialise_monitor_handles
> #endif
>
> /* Enable interrupts, enter supervisor mode and branch to
> start of 'C' code */
>
> msr cpsr_c, #0x13 /* I=0 F=0 T=0 MODE=supervisor
*/
> bl main /********************************************************************
> **********
> * Interrupt
> exceptions *
>
*********************************************************************
> *********/
>
> handle_uart0:
> stmfd r13!, {r12, r14} /* save r12 & r14 */
> mrs r12, spsr /* save the spsr */
> stmfd r13!, {r12}
> msr cpsr_c, #0x93 /* switch to sys mode */
> stmfd r13!, {r0-r3, r14} /* save sys mode registers
> */
> msr cpsr_c, #0x13 /* enable interrupts */
> bl uartInterrupt /* go handle the interrupt
> */
> msr cpsr_c, #0x93 /* disable interrupts */
> ldmfd r13!, {r0-r3, r14} /* restore sys mode
> registers */
> msr cpsr_c, #0x92 /* switch back to irq mode
> */
> ldmfd r13!, {r12} /* restore spsr */
> msr spsr_cxsf, r12
> ldmfd r13!, {r12, r14} /* restore r12 & r14 */
> stmfd r13!, {r0-r1} /* save r0 & r1 */
> ldr r0, =VICVecAddr /* update VIC */
> mov r1, #0xff
> str r1, [r0]
> ldmfd r13!, {r0-r1} /* restore r0 & r1 */
> subs pc, lr, #0x4 /* return from teh
> interrupt */
>
> handle_tmr0:
> stmfd r13!, {r12, r14} /* save r12 & r14 */
> mrs r12, spsr /* save the spsr */
> stmfd r13!, {r12}
> msr cpsr_c, #0x93 /* switch to sys mode */
> stmfd r13!, {r0-r3, r14} /* save sys mode registers
> */
> msr cpsr_c, #0x13 /* enable interrupts */
> bl tmrInterrupt /* go handle the interrupt
> */
> msr cpsr_c, #0x93 /* disable interrupts */
> ldmfd r13!, {r0-r3, r14} /* restore sys mode
> registers */
> msr cpsr_c, #0x92 /* switch back to irq mode
> */
> ldmfd r13!, {r12} /* restore spsr */
> msr spsr_cxsf, r12
> ldmfd r13!, {r12, r14} /* restore r12 & r14 */
> stmfd r13!, {r0-r1} /* save r0 & r1 */
> ldr r0, =VICVecAddr /* update VIC */
> mov r1, #0xff
> str r1, [r0]
> ldmfd r13!, {r0-r1} /* restore r0 & r1 */
> subs pc, lr, #0x4 /* return from teh
> interrupt */ > /*
> * End of startup code
> */
>
> .size _int_vectors,.-_int_vectors;
>
> --- In , "kennethwada" <kwada@a...> wrote:
> >
> > Hello Milind;
> >
> > Let us say...
> >
> > You are attempting to do a very advanced thing with the LPC2xxx
> chip.
> > This is emminently doable though.
> >
> > In general, you need to do the following:
> >
> > Define your startup vector:
> > 'the following is a code snippet from one of my projects'
> >
> > AREA INTVECT, 'CODE_IVEC', READONLY, ALIGN=2 // READONLY,
> ALIGN=4
> > bytes
> > RSEG INTVECT
> > PUBLIC __startup
> > __startup PROC CODE32
> >
> > // Pre-defined interrupt handlers that may be directly
> > // overwritten by C interrupt functions
> > EXTERN CODE32 (Undef_Handler?A)
> > EXTERN CODE32 (SWI_Handler?A)
> > EXTERN CODE32 (PAbt_Handler?A)
> > EXTERN CODE32 (DAbt_Handler?A)
> > EXTERN CODE32 (IRQ_Handler?A)
> > EXTERN CODE32 (FIQ_Handler?A)
> >
> > // Exception Vectors
> > // Mapped to Address 0.
> > // Absolute addressing mode must be used.
> >
> > vectors: LDR PC,Reset_Addr
> > LDR PC,Undef_Addr
> > LDR PC,SWI_Addr
> > LDR PC,PAbt_Addr
> > LDR PC,DAbt_Addr
> > NOP /* Reserved Vector
> */
> > ; LDR PC,IRQ_Addr
> > LDR PC,[PC, #-0x0FF0] /* Vector from
> > VicVectAddr */
> > LDR PC,FIQ_Addr
> >
> > Reset_Addr: DD Reset_Handler
> > Undef_Addr: DD Undef_Handler?A
> > SWI_Addr: DD SWI_Handler?A
> > PAbt_Addr: DD PAbt_Handler?A
> > DAbt_Addr: DD DAbt_Handler?A
> > DD 0 /* Reserved Address
> */
> > IRQ_Addr: DD IRQ_Handler?A
> > FIQ_Addr: DD FIQ_Handler?A
> > ENDP
> >
> > As you can see, this vector consumes exactly 64 bytes of code!
> >
> > Next, you need to relocate, (at runtime), your 64 byte interrupt
> > vector table that you created above.
> >
> > Do this as follows:
> >
> > Reset_Handler:
> > .... ; <--- some startup code here, (usually PINSEL
> programming)
> >
> > /*****
> > Relocate interrupt vectors to internal RAM
> > ***/
> > MEMMAP EQU 0xE01FC040 ; interrupt memory map
> > register
> >
> > LDR R1,=__startup
> > MOV R0,#0x40000000
> > MOV R2,#0x10
> >
> > copyLoop:
> > LDMIA R1!,{R3}
> > STMIA R0!,{R3}
> > SUBS R2,R2,#0x0001
> > BNE copyLoop
> >
> > LDR R0,=MEMMAP
> > MOV R1,#0x02
> > STR R1, [R0]
> >
> > In your 'C' code, you need to define your vectors such that they
> > reside in RAM. The Keil compiler has a real nifty way to do this
> via
> > the following LINKER directive:
> >
> > CLASSES (ERAM (0x40000040-0x40001FFF))
> >
> > This places all code that has been defined to store in flash, and
> > execute in RAM to be loaded at runtime into the RAM area.
> >
> > That is, for every subroutine you define with the following Keil
> > modifier:
> >
> > void my_interrupt_service (void) __irq __ram;
> >
> > This __irq and __ram modifier does two things:
> > __irq compiles the subroutine as a service vector using ARM
> > instructions.
> >
> > __ram places the entire subroutine into the ERAM segment that will
> > automatically get loaded into flash by the nifty Keil tool.
> >
> > in lieu of the Keil tool, you must be able find a way relocate,
> > (copy)
> > your service vectors into ram at run time.
> >
> > whew!
> >
> > hope this helps;
> > Ken Wada




Hello Everyone,
Thanks for your help. Actual problem was not my code but non-erasure
of RAM at Power ON. With Ashling tools and Ashling Eval board,I need
to do a hard reset from Pathfinder and then load the application.
Just Power ON reset is not sufficient.
Thanks for all the inputs.

Milind
--- In , "kennethwada" <kwada@a...> wrote:
>
> no; It is not imperative to set MEMMAP=0x2 as I did with the
example.
> You need to do this MEMMAP=2 at any time AFTER relocating your
> vectors, and BEFORE starting up the interrupts, (startup via VIC
> register setup).
>
> By the way, I noticed throughout your code, this switching to/from
> USER mode, and disabling/enabling interrupts in your vectors.
>
> If you are currently processing an exception, the silicon
> automatically switches the process to:
> --> ARM format
> --> SYSTEM mode
>
> If you do not allow nesting of interrupts, (generally not
recommended
> to nest), then you do not need to do this (enabling/disabling
> interrupts inside a vector). In general, you should not nest
> interrupts in the ARM, for concern in regards to corrupting the
SPSR
> (shadow of CPSR) register. If you do the nesting, then you need to
> define a shadow of a shadow! This gets really complicated.
>
> In general, I have found no need to enable/disable interrupts. I
have
> done all atomic and monitor style operations using a pseudo-
semaphore
> technique that exploits the ARM SWI hardware. This is very nice,
and
> very much like the INT86 instruction that those Intel
architectures
> have. TI also supports hardware like this on their very fine DSP
> cores!
>
> You really ought to avoid enabling/disabling interrupts because of
the
> ARM cache vs. interrupt issues. This is a very dangerous area to
> tread. I know most users hear are probably doing this a lot, and
> probably see no problem with doing this. In fact, I believe this
is
> precisely the reason why Philips, in their users manual, writes 3-
4
> paragraphs on this, (spurious interrupts concerns).
>
> I have worked many years with fully pipelined/cached
architectures,
> and one of the most difficult, (to prove, and to quantify)
problems
> with these architectures is cache pipeline vs asynchronous events,
> (ie. enabling/disabling exceptions).
>
> You really ought to let the ARM silicon do what it is really good
at,
> (resynchronizing itself), and leave the coding up to you.
>
> The problem with this is, we embedded engineers, for many years
are
> used to non-pipelined cached architectures, and are not familiar
with
> some of the advanced interrupt techniques of the more modern
> architectures. Once you learn this stuff, it is not hard to get
very
> nice reliable and robust systems cranked out.
>
> Ken Wada
>
> --- In , "milind_pd" <milind_pd@y...> wrote:
> >
> > Hi Ken,
> > Is it imperative that I have to set the MEMMAP register to 0x2
> > value, before I brach off to main()? From your code it seems
that
> > way. Here is the snippet from my code. Let me know if you see
> > anything funky here.
> >
> > Milind
> >
> > /* Export list */
> > .global handle_uart0
> > .global handle_tmr0
> >
> > /*#define ARM_RDP_MONITOR 0x01*/
> > /*#define ARM_RDI_MONITOR 0x01*/
> >
> > /* Define some hardware locations */
> > .equ VICVecAddr, 0xfffff030 /* Address of
> > VICVectAddr register */
> >
> >
> /******************************************************************
**
> > * Exception vector table - common to all ARM-based
> > systems *
> >
********************************************************************
> > * Common to all ARM-based systems. Table entries just jump to
> > handlers using full 32-bit addressing.
> > ****************************************/
> > _int_vectors:
> >
> > ldr pc, do_reset_addr
> > ldr pc, do_undefined_instruction_addr
> > ldr pc, do_software_interrupt_addr
> > ldr pc, do_prefetch_abort_addr
> > ldr pc, do_data_abort_addr
> > /* .long 0xB9205F88 /* ARM-reserved
> > vector */
> > nop
> > ldr pc, [pc, #-0xff0] /* set PC (currently
0x18)
> > to VicVectAddr (0xFFFFF030) by - 0xFF0 */
> > ldr pc, do_fiq_addr
> >
> > do_reset_addr: .long do_reset
> > do_undefined_instruction_addr: .long do_undefined_instruction
> > do_software_interrupt_addr: .long do_software_interrupt
> > do_prefetch_abort_addr: .long do_prefetch_abort
> > do_data_abort_addr: .long do_data_abort
> > do_fiq_addr: .long do_fiq
> >
> >
> /******************************************************************
**
> > * Yet to be implemented exceptions
> >
>
*********************************************************************
> > * Just fall through to reset exception handler for now
> >
>
********************************************************************/
>
>

> >
> > do_undefined_instruction:
> > do_software_interrupt:
> > do_prefetch_abort:
> > do_data_abort:
> > do_fiq:
> >
> >
> /******************************************************************
**
> > * System reset handler
> >
>
********************************************************************/
> > do_reset:
> >
> > /* Set stack pointers for all modes used (supervisor,
IRQ
> > and FIQ) */
> > ldr sp, =__stack_svc /* set supervisor
mode
> > stack pointer */
> >
> > msr cpsr_c, #0xd2 /* enter IRQ
mode, with
> > interrupts disabled */
> >
> > ldr sp, =__stack_irq /* set IRQ mode
stack
> > pointer */
> >
> > mov lr, #0x0 /* clear out other
> > IRQ shadow register */
> >
> > msr cpsr_c, #0xd1 /* enter FIQ
mode, with
> > interrupts disabled */
> >
> > ldr sp, =__stack_fiq /* set FIQ mode
stack
> > pointer */
> >
> >
> > /* Clear uninitialized data section (bss) */
> > ldr r4, =__start_bss /* First
address*/
> > ldr r5, =__end_bss /* Last
address*/
> > mov r6, #0x0
> >
> > loop_zero:
> > str r6, [r4]
> > add r4, r4, #0x4
> > cmp r4, r5
> > blt loop_zero
> >
> > /* Copy initialized data sections from ROM into RAM */
> > ldr r4, =_fdata /* destination
address
> > */
> > ldr r5, =_edata /* Last
address*/
> > ldr r6, =_etext /* source
address*/
> > cmp r4, r5
> > beq skip_initialize
> >
> > loop_initialise:
> > ldr r3, [r6]
> > str r3, [r4]
> > add r4, r4, #0x4
> > add r6, r6, #0x4
> > cmp r4, r5
> > blt loop_initialise
> >
> > skip_initialize:
> >
> >
> > #if !defined(ARM_RDP_MONITOR) && !defined(ARM_RDI_MONITOR)
> > mov r0, #0 /* no arguments */
> > mov r1, #0 /* no argv either */
> > #else
> > /* Need to set up standard file handles */
> > bl initialise_monitor_handles
> > #endif
> >
> > /* Enable interrupts, enter supervisor mode and branch
to
> > start of 'C' code */
> >
> > msr cpsr_c, #0x13 /* I=0 F=0 T=0
MODE=supervisor
> */
> > bl main
> >
> >
> /******************************************************************
**
> > **********
> > * Interrupt
> > exceptions *
> >
>
*********************************************************************
> > *********/
> >
> > handle_uart0:
> > stmfd r13!, {r12, r14} /* save r12 & r14 */
> > mrs r12, spsr /* save the spsr */
> > stmfd r13!, {r12}
> > msr cpsr_c, #0x93 /* switch to sys mode */
> > stmfd r13!, {r0-r3, r14} /* save sys mode
registers
> > */
> > msr cpsr_c, #0x13 /* enable interrupts */
> > bl uartInterrupt /* go handle the
interrupt
> > */
> > msr cpsr_c, #0x93 /* disable interrupts */
> > ldmfd r13!, {r0-r3, r14} /* restore sys mode
> > registers */
> > msr cpsr_c, #0x92 /* switch back to irq
mode
> > */
> > ldmfd r13!, {r12} /* restore spsr */
> > msr spsr_cxsf, r12
> > ldmfd r13!, {r12, r14} /* restore r12 & r14 */
> > stmfd r13!, {r0-r1} /* save r0 & r1 */
> > ldr r0, =VICVecAddr /* update VIC */
> > mov r1, #0xff
> > str r1, [r0]
> > ldmfd r13!, {r0-r1} /* restore r0 & r1 */
> > subs pc, lr, #0x4 /* return from teh
> > interrupt */
> >
> > handle_tmr0:
> > stmfd r13!, {r12, r14} /* save r12 & r14 */
> > mrs r12, spsr /* save the spsr */
> > stmfd r13!, {r12}
> > msr cpsr_c, #0x93 /* switch to sys mode */
> > stmfd r13!, {r0-r3, r14} /* save sys mode
registers
> > */
> > msr cpsr_c, #0x13 /* enable interrupts */
> > bl tmrInterrupt /* go handle the
interrupt
> > */
> > msr cpsr_c, #0x93 /* disable interrupts */
> > ldmfd r13!, {r0-r3, r14} /* restore sys mode
> > registers */
> > msr cpsr_c, #0x92 /* switch back to irq
mode
> > */
> > ldmfd r13!, {r12} /* restore spsr */
> > msr spsr_cxsf, r12
> > ldmfd r13!, {r12, r14} /* restore r12 & r14 */
> > stmfd r13!, {r0-r1} /* save r0 & r1 */
> > ldr r0, =VICVecAddr /* update VIC */
> > mov r1, #0xff
> > str r1, [r0]
> > ldmfd r13!, {r0-r1} /* restore r0 & r1 */
> > subs pc, lr, #0x4 /* return from teh
> > interrupt */
> >
> >
> > /*
> > * End of startup code
> > */
> >
> > .size _int_vectors,.-_int_vectors;
> >
> > --- In , "kennethwada" <kwada@a...> wrote:
> > >
> > > Hello Milind;
> > >
> > > Let us say...
> > >
> > > You are attempting to do a very advanced thing with the
LPC2xxx
> > chip.
> > > This is emminently doable though.
> > >
> > > In general, you need to do the following:
> > >
> > > Define your startup vector:
> > > 'the following is a code snippet from one of my projects'
> > >
> > > AREA INTVECT, 'CODE_IVEC', READONLY, ALIGN=2 // READONLY,
> > ALIGN=4
> > > bytes
> > > RSEG INTVECT
> > > PUBLIC __startup
> > > __startup PROC CODE32
> > >
> > > // Pre-defined interrupt handlers that may be directly
> > > // overwritten by C interrupt functions
> > > EXTERN CODE32 (Undef_Handler?A)
> > > EXTERN CODE32 (SWI_Handler?A)
> > > EXTERN CODE32 (PAbt_Handler?A)
> > > EXTERN CODE32 (DAbt_Handler?A)
> > > EXTERN CODE32 (IRQ_Handler?A)
> > > EXTERN CODE32 (FIQ_Handler?A)
> > >
> > > // Exception Vectors
> > > // Mapped to Address 0.
> > > // Absolute addressing mode must be used.
> > >
> > > vectors: LDR PC,Reset_Addr
> > > LDR PC,Undef_Addr
> > > LDR PC,SWI_Addr
> > > LDR PC,PAbt_Addr
> > > LDR PC,DAbt_Addr
> > > NOP /* Reserved
Vector
> > */
> > > ; LDR PC,IRQ_Addr
> > > LDR PC,[PC, #-0x0FF0] /* Vector from
> > > VicVectAddr */
> > > LDR PC,FIQ_Addr
> > >
> > > Reset_Addr: DD Reset_Handler
> > > Undef_Addr: DD Undef_Handler?A
> > > SWI_Addr: DD SWI_Handler?A
> > > PAbt_Addr: DD PAbt_Handler?A
> > > DAbt_Addr: DD DAbt_Handler?A
> > > DD 0 /* Reserved
Address
> > */
> > > IRQ_Addr: DD IRQ_Handler?A
> > > FIQ_Addr: DD FIQ_Handler?A
> > > ENDP
> > >
> > > As you can see, this vector consumes exactly 64 bytes of code!
> > >
> > > Next, you need to relocate, (at runtime), your 64 byte
interrupt
> > > vector table that you created above.
> > >
> > > Do this as follows:
> > >
> > > Reset_Handler:
> > > .... ; <--- some startup code here, (usually PINSEL
> > programming)
> > >
> > > /*****
> > > Relocate interrupt vectors to internal RAM
> > > ***/
> > > MEMMAP EQU 0xE01FC040 ; interrupt memory
map
> > > register
> > >
> > > LDR R1,=__startup
> > > MOV R0,#0x40000000
> > > MOV R2,#0x10
> > >
> > > copyLoop:
> > > LDMIA R1!,{R3}
> > > STMIA R0!,{R3}
> > > SUBS R2,R2,#0x0001
> > > BNE copyLoop
> > >
> > > LDR R0,=MEMMAP
> > > MOV R1,#0x02
> > > STR R1, [R0]
> > >
> > > In your 'C' code, you need to define your vectors such that
they
> > > reside in RAM. The Keil compiler has a real nifty way to do
this
> > via
> > > the following LINKER directive:
> > >
> > > CLASSES (ERAM (0x40000040-0x40001FFF))
> > >
> > > This places all code that has been defined to store in flash,
and
> > > execute in RAM to be loaded at runtime into the RAM area.
> > >
> > > That is, for every subroutine you define with the following
Keil
> > > modifier:
> > >
> > > void my_interrupt_service (void) __irq __ram;
> > >
> > > This __irq and __ram modifier does two things:
> > > __irq compiles the subroutine as a service vector using ARM
> > > instructions.
> > >
> > > __ram places the entire subroutine into the ERAM segment that
will
> > > automatically get loaded into flash by the nifty Keil tool.
> > >
> > > in lieu of the Keil tool, you must be able find a way relocate,
> > > (copy)
> > > your service vectors into ram at run time.
> > >
> > > whew!
> > >
> > > hope this helps;
> > > Ken Wada