This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Timer/counter/External Interrupts code in ARM assembly

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

Parents
  • 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.

    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.

Reply
  • 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.

    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.

Children
  • 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!!!

  • Secondly how will i give the address of the ISR to any of the VICVectAddr register.

    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