Yahoo Groups archive

Lpc2000

Index last updated: 2026-04-28 23:31 UTC

Message

Re: relocating code in RAM with lpc2106.

2005-02-28 by kennethwada

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 Wada

Attachments

Move to quarantaine

This moves the raw source file on disk only. The archive index is not changed automatically, so you still need to run a manual refresh afterward.