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 lpc2000@yahoogroups.com, "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 lpc2000@yahoogroups.com, "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 WadaMessage
Re: relocating code in RAM with lpc2106.
2005-02-28 by kennethwada
Attachments
- No local attachments were found for this message.