hi all,
I am on the learning stage of LPC2148 and I have done basic programs like interrupts ... ADC ... TIMER/COUNTER. But all the code I have written is in C Language.
Though I had written some basic progarams of LED in assembly but not the interrupt part.
Could any one here tell me what are the rules to write the assembly code for interrupts i.e. for FIQ, IRQ and NV IRQ.
If possible plz guide me with some source code.
I am using KEIL uvision 4.
Arvind Shrivastava
There is no difference. All you need to make sure is that you do the right thing - namely, acknowledge the interrupt, don't loop etc. - just like in C. Why bother with assembly? time critical stuff? code size? isn't the optimization of the compiler good enough? something?
"Why bother with assembly?"
Be serious.
It is still possible for a proficient writer of assembler to produce faster and smaller code than can be created by the best compilers.
Guys! ... Please dont argue for which is better 'C'(HLL) or assembly ... I had just asked if some one can guide me for writing interrupt routines in assembly.
No doubt Assembly is the best but requires more exposure and experience then high level language for writing OPTTIMIZED & efficient code.
Hope some some guidance will come out form you all beautifull minds.
The simplest course of action for you to pursuit is:
1. Write it in C, compile with minimum optimization and observe the generated compiler code (see "listing" tab). 2. Have the assembly guide at hand as reference.
S Steve said:
It is a very useful for an embedded engineer to be aware of what goes on under the hood so they can understand what the compiler is doing and how they might effectively carry out debugging tasks.
---
Totally agree with that concept, and not just for programming. If only my wife could be persuaded to understand what was going on "under the hood". She might then have realised that the "funny sound coming from my engine when I go up the hill" was actually an expensive to fix slipping, soon to be burnt out, clutch!
There was no arguing which is best, for the single reason that there can't be any "best" unless you define the criteria for "best".
Is it "best" to have the smallest, fastest, code that gets shipped one week too late? Or that contains a very embarrasing bug because one of the developers didn't know assembler well enough, resulting in a missed register save that wasn't obvious until that interrupt did happen at a very specific position of the main code processing - resulting in the slightly smaller program just happen to remove someones arm?
The debate was about the reason for you to ask for help with assembler. If you asked because you thought you needed assembler or if you did know you needed assembler or just wanted to broaden your knowledge.
But for whatever debate you may enter - always remember that "best" needs to be very well defined way before you start to suggest what is best.
Frogramming forums normally get stuck around: - what is best - HLL or assembler? - which HLL is best? - which processor is best? - which compiler is best? - ...
Almost always without any definition of the grading criteria, so almost always resulting in an epic failure.
Per Westermark said:
-----------------------
Thanx for your reply
Now from my part for the word "BEST" -> Assembly is best in the case of code optimization which obviously results in memory saving and speed.
Hope "BEST" part is descriptive from the above statement.
Now for why I am asking for the assembler code -> Surely I wanted to broaden my knowledge which results in the better understanding of the system.
Now can any body here guide me with small code( like timer interrupt for LED blinking or something like that).
Nowadays say that coding in assembly code is best for speed and size is not true, as the compiler may handle many optimization that you would not be able to do (pipeline, cache, ...). In my opinion, you write assembly code to be deterministic with the code produced (size& speed), or when you no have no high-level language for your device (here the C compiler).
Why don't you specify your needs with speed/code size and try to see if your compiler satisfy these needs ?
If you really want to know how to code this in assembly you can still code it in C and read the listing produced (with the different level optimization).
ohk!
I got the idea what you guys wanted to say about the assembly and HLL and the meaning of BEST also.
As I am on the learning stage so there is no specific need of my application as there is no one presently.
I juz wanted to try my hand on assembly for the interrupt part. As I had already told that I have written the small code for LED blinking in assembly.
I HLL like 'C' I have written the code for interrupt. But I am not getting any concrete idea and hint for writing code in assembly for the interrupts.
I juz know that some changes are to be made in Startup.s file. But what are the changes I am not getting it in a proper manner.
You must READ the above statement clearly.
I juz know that some changes are to be made in Startup.s file. But what are the changes I am not getting it in a proper manner.M
No this is not the case. if you write you interrupt handler like this:
__irq void DAbt_Handler(void) { handle_failure() ; for (;;) ; }
and then
__asm void handle_failure(void) { // assembly code here }
you're done.
You can also write the handler itself directly in assembly, like this:
__asm __irq void DAbt_Handler(void)
Let me reiterate:
There is nothing special about assembly code in interrupts handlers. It is just assembly. Nothing magical or mysterious about it. If you need help with the syntax or instruction set - you must have a look in the assembly guide of the tool chain.
One more thing: Use assembly in interrupt handlers does not require any change to the startup file!
I am not asking for inline assembly ... I am asking for the assembly code from scratch that juz include Startup.s file IN KEIL IDE and no .C file at all.
If I am not wrong while making FIQ program in C I had to make changes in Startup.s file ... although this is not the case for Vectored and non-vectored IRQ ... but ya for FIQ i had to make the changes.
Can anybody gimme the code for 1 second timer interrupt!!!
Hi Arvind Shrivastava,
Try to get a book called "The Defi nitive Guide to the ARM Cortex-M3" written by Joseph Yiu.
It has a lot of assembly example code like the following.
LDR R0, =0xE000ED0C ; Application Interrupt and Reset ; Control Register LDR R1, =0x05FA0500 ; Priority Group 5 (2/6) STR R1, [R0] ; Set Priority Group ... MOV R4,#8 ; Vector Table in ROM LDR R5,=(NEW_VECT_TABLE+8) LDMIA R4!,{R0-R1} ; Read vectors address for NMI and ; Hard Fault STMIA R5!,{R0-R1} ; Copy vectors to new vector table ... LDR R0,=0xE000ED08 ; Vector Table Offset Register LDR R1,=NEW_VECT_TABLE STR R1,[R0] ; Set vector table to new location ... LDR R0,=IRQ7_Handler ; Get starting address of IRQ#7 handler LDR R1,=0xE000ED08 ; Vector Table Offset Register LDR R1,[R1] ADD R1, R1, #(4*(7+16)); Calculate IRQ#7 handler vector ; address STR R0,[R1] ; Setup vector for IRQ#7 ... LDR R0,=0xE000E400 ; External IRQ priority base MOV R1, #0xC0 STRB R1,[R0,#7] ; Set IRQ#7 priority to 0xC0 ... LDR R0,=0xE000E100 ; SETEN register MOV R1,#(1<<7) ; IRQ#7 enable bit (value 0x1 shifted ; by 7 bits) STR R1,[R0] ; Enable the interrupt
But it is not for your LPC2148.
Sir,
Thanx a lot for your kind reply and valuable guidance.
No problem if the code is not for LPC2148 ... i juz wanna 2 know the concept.
thanx once again
It is embarrassing that, for the people who were involved in this thread, I am afraid that, you and me, might be the only two persons, who don't know how to code in assembly.
I think the situation is, for those who know how to code in assembly, they don't need things like tutorial or example code, they just know how to do that; for those who don't know how to code in assembly, the resource is very limited.
And I believe that you already know this, just to remind you once again,
Assembly is very platform dependent, though the general concept should be very similar.
No Problem if I dont know how to code in assembly, atleast I can try my hand.
For the rest of the guys in this forum ... might I am not been able to give them the clear picture of what I wanted to do.
So again I am briefing ...
I wanted to write a simple code in assembly for TIMER Interrupt ... lets say for 1 second and toggle some GPIO thats it.
Now for the concept ... where I am confused or having no idea is ...
how to write the ISR? how to assign the address of the ISR?
Above task is done successfully in c by me ... coz many tutorials are available on net.
But for the assembly ... I am bit confused ... this juz may be the result of lack of my information and concrete knowledge.
In your case (about writing an ISR), I will recommend you to get an Evaluation Board/Kit equipped with a LPC1768, and get the "The Definitive Guide to the ARM Cortex-M3". It would be a good beginning to you.
If it is not possible, then you can try to use the KEIL IDE's Simulator with "The Definitive Guide to the ARM Cortex-M3"
If it is still not possible to you, and you decide to work with the LPC2148, then you will need to read the ARM7TDMI xxx Technical Reference Manual first.
From ARM7TDMI xxx Technical Reference Manual:
2.9.2 Entering an exception When handling an exception the ARM7TDMI-S core: 1. Preserves the address of the next instruction in the appropriate LR. When the exception entry is from: • ARM state, the ARM7TDMI-S copies the address of the next instruction into the LR (current PC + 4, or PC + 8 depending on the exception) • Thumb state, the ARM7TDMI-S writes the value of the PC into the LR, offset by a value (current PC + 4, or PC + 8 depending on the exception). The exception handler does not have to determine the state when entering an exception. For example, in the case of a SWI, MOVS PC, r14_svc always returns to the next instruction regardless of whether the SWI was executed in ARM or Thumb state. 2. Copies the CPSR into the appropriate SPSR. 3. Forces the CPSR mode bits to a value which depends on the exception. 4. Forces the PC to fetch the next instruction from the relevant exception vector. The ARM7TDMI-S core also sets the interrupt disable flags on interrupt exceptions to prevent otherwise unmanageable nestings of exceptions.
2.9.3 Leaving an exception When an exception is completed, the exception handler must: 1. Move the LR, minus an offset to the PC. The offset varies according to the type of exception, as shown in Table 2-3 on page 2-19. 2. Copy the SPSR back to the CPSR. 3. Clear the interrupt disable flags that were set on entry.
And you need to be familar with the KEIL toolchain also.
how to write the ISR? how to assign the address of the ISR? Above task is done successfully in c by me ... coz many tutorials are available on net.
Cortex-M3 is very different from ARM7, especially about the Interrupt (IRQ mode).
For ARM7, the Interrupt Controller is not one part of the ARM core. So the Interrupt Controller varies from manufacturer to manufacturer.
In your case, the LPC2148 has a Vectored Interrupt Controller (a peripheral). In the startup file of LPC2148,
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
{ LDR PC,[PC, #-0x0FF0] } actually points to the address of the Vectored Interrupt Controller. And you need to register your ISR to the VIC.
When you write an ISR in C with the KEIL toolchain, actually the KEIL toolchain does a lot of work for you, it is KEIL's magic. When you write an ISR in assembly, you need to do all that work by yourself.
But that magic can be seen by writing an ISR in C, and then look at the produced assembler output. So Keil can produce a stub that you can then extend with own assembler code to perform the required task.
can any body gimme a simple code example.
The problem I am facing is ... whether the Interrupt handling by VIC variables are needed to be modied or CPSR values are to be set or reset for the interrupt.
Secondly how will i give the address of the ISR to any of the VICVectAddr register.
If some body has the code ... for KEIL then plz post it here!!!
Do you know how to do this in C language?
I have a list, the last item on my list, added recently, is "Write a tiny assembly example for LPC2368". But I don't think I will have enough time to complete my list.
A tiny assembly example for LPC2368 will not work on LPC2148. And the VIC of LPC2368 and the VIC of LPC2148 is different.
Yes I know how to do it in C Language.
I think I am not been able to make myself clear for my requirement though I had tried a lot to express my confusion and need for the guidance.
So let it be ... but if you guys have the assembly source code for the timer interrupt or any other interrupt and is possible for you to send to me ... then please send me.
The below code has been tested on my LPC2368 board.
#include "LPC23xx.h" #define VIC_BASE_ADDR 0xFFFFF000 #define VECT_ADDR_INDEX 0x100 #define VECT_PRIO_INDEX 0x200 #define HIGHEST_PRIORITY 0x01 #define TIMER0_INT 4 #define Timer0_Vect_Addr (*(volatile unsigned long *)(VIC_BASE_ADDR + VECT_ADDR_INDEX + TIMER0_INT*4)) #define Timer0_Vect_Prio (*(volatile unsigned long *)(VIC_BASE_ADDR + VECT_PRIO_INDEX + TIMER0_INT*4)) #define TIME_INTERVAL 7999999 void Timer0Handler(void) __irq { T0IR = 1; /* Clear Interrupt Flag */ FIO3CLR = (1<<26); /* LED On */ VICVectAddr = 0; /* Acknowledge Interrupt */ } void init_stuff(void) { Timer0_Vect_Addr = (unsigned long)Timer0Handler; /* Set Interrupt Vector */ Timer0_Vect_Prio = HIGHEST_PRIORITY; VICIntEnable = 1 << TIMER0_INT; /* Enable Interrupt */ T0MR0 = TIME_INTERVAL; T0MCR = 3; T0TCR = 1; FIO3DIR |= (1<<26); // 1 for Output } int main(void) { init_stuff(); while(1) { if ( T0TC > (TIME_INTERVAL/2) ) FIO3SET = (1<<26); /* LED Off */ } }
Will try to translate it into assembly with the magic power of KEIL toolchain.
Comment out the below line in your Startup.s
IMPORT __use_two_region_memory
Save the below code as "ASM_Test.s"
ARM AREA ||.text||, CODE, READONLY, ALIGN=2 Timer0Handler PROC ;;;14 ;;;15 void Timer0Handler(void) __irq PUSH {r0,r1} ;;;16 { ;;;17 T0IR = 1; /* Clear Interrupt Flag */ MOV r0,#1 LDR r1,|L1.172| STR r0,[r1,#0] ;;;18 FIO3CLR = (1<<26); /* LED On */ MOV r0,#0x4000000 RSB r1,r1,r0,LSL #3 STR r0,[r1,#0x7c] ;;;19 VICVectAddr = 0; /* Acknowledge Interrupt */ MOV r0,#0 STR r0,[r0,#-0x100] ;;;20 } POP {r0,r1} SUBS pc,lr,#4 ;;;21 ENDP init_stuff PROC ;;;22 ;;;23 void init_stuff(void) ADR r0,Timer0Handler ;;;24 { ;;;25 Timer0_Vect_Addr = (unsigned long)Timer0Handler; /* Set Interrupt Vector */ MOV r1,#0 STR r0,[r1,#-0xef0] ;;;26 Timer0_Vect_Prio = HIGHEST_PRIORITY; MOV r0,#1 STR r0,[r1,#-0xdf0] ;;;27 VICIntEnable = 1 << TIMER0_INT; /* Enable Interrupt */ MOV r0,#0x10 STR r0,[r1,#-0xff0] ;;;28 ;;;29 T0MR0 = TIME_INTERVAL; LDR r0,|L1.176| LDR r1,|L1.172| STR r0,[r1,#0x18] ;;;30 T0MCR = 3; MOV r0,#3 STR r0,[r1,#0x14] ;;;31 T0TCR = 1; MOV r0,#1 STR r0,[r1,#4] ;;;32 ;;;33 FIO3DIR |= (1<<26); // 1 for Output RSB r0,r1,r0,LSL #29 LDR r0,[r0,#0x60] ORR r0,r0,#0x4000000 RSB r1,r1,r1,LSL #15 STR r0,[r1,#0x60] ;;;34 } BX lr ;;;35 ENDP EXPORT __main __main PROC ;;;36 ;;;37 int main(void) PUSH {lr} ;;;38 { ;;;39 init_stuff(); BL init_stuff ;;;40 ;;;41 while(1) B |L1.168| |L1.136| ;;;42 { ;;;43 if ( T0TC > (TIME_INTERVAL/2) ) LDR r0,|L1.172| LDR r0,[r0,#8] LDR r1,|L1.180| CMP r0,r1 BLS |L1.168| ;;;44 FIO3SET = (1<<26); /* LED Off */ MOV r0,#0x4000000 LDR r1,|L1.184| STR r0,[r1,#0x78] |L1.168| B |L1.136| ;;;45 } ;;;46 } ;;;47 ENDP |L1.172| DCD 0xe0004000 |L1.176| DCD 0x007a11ff |L1.180| DCD 0x003d08ff |L1.184| DCD 0x3fffc000 __ARM_use_no_argv EQU 0 END
Create a project with the Startup.s and ASM_Test.s. Build it, Run.
I don't have too much time for this demo project.
I haven't studied the assembly code, that KEIL toolchain generated for me, I just quickly modified them to fit my need. There were some warnings when I built this assembly demo project. And the LED blinking was not regular as what I expected, when I tested this project with my LPC2368 board. So, this assembly demo project is very low quality, but it seems work.
Now, I have quickly done my homework.
Hi John Linq,
thanx a alot dear for your kind help, guidance and efforts. I really appreciate your work!!!
thanks once again
regards Arvind
View all questions in Keil forum