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 __________________________________________________ |
|
relocating code in RAM with lpc2106.
Started by ●February 27, 2005
Reply by ●February 27, 20052005-02-27
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 --------------------------------- |
Reply by ●February 28, 20052005-02-28
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 |
Reply by ●February 28, 20052005-02-28
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 |
Reply by ●February 28, 20052005-02-28
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 |
Reply by ●February 28, 20052005-02-28
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 |
Reply by ●February 28, 20052005-02-28
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 |
|
Reply by ●February 28, 20052005-02-28
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 |
Reply by ●February 28, 20052005-02-28
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 |
Reply by ●February 28, 20052005-02-28
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 |