1. Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
    Dismiss Notice

Can't get LPC2148 timer match interrupts to work

Discussion in 'Microcontrollers' started by futz, Jan 17, 2009.

  1. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US
    all interrupts on a PIC are disabled until you enable them. I wish i had that board so i could help ya out but me just thinking and reading isnt helping much :D

    Why not just comment this out:
    Code (text):

    .set  I_BIT, 0x80       /* when I bit is set, IRQ is disabled (program status registers) */
     
    and see what that does. Instead of turning them on later do it so its always on.
     
  2. futz

    futz Active Member

    Joined:
    Sep 15, 2007
    Messages:
    2,043
    Likes:
    24
    Location:
    Vancouver, B.C.
    I realize that. But all you have to do is diddle bits in a couple registers and they work. In this thing they're disabled. I diddle all the right registers and they should work, but they don't because somebody thought it made sense to make sure they couldn't work without doing something that should have already been done in the startup code. Weird!


    I'm thinking more like in this piece of crt.s code
    Code (text):
                    msr   CPSR_c, #MODE_IRQ|I_BIT|F_BIT     /* IRQ Mode */
                    mov   sp, r0
                    sub   r0, r0, #IRQ_STACK_SIZE
    change it like this
    Code (text):
                    msr   CPSR_c, #MODE_IRQ     /* IRQ Mode */
                    mov   sp, r0
                    sub   r0, r0, #IRQ_STACK_SIZE
    and do the same for the FIQ section.

    EDIT: Well, that doesn't work. I'm obviously completely misunderstanding something. And none of the tutorials or other people's source code I've looked at mentions it.



    For the life of me I can't understand why someone thought that was a good idea. I'm sure there's some good reason, but I sure don't know what it might be.
     
    Last edited: Jan 19, 2009
  3. futz

    futz Active Member

    Joined:
    Sep 15, 2007
    Messages:
    2,043
    Likes:
    24
    Location:
    Vancouver, B.C.
    This code pops the interrupt once each time the processor is reset, but never again. So I'm getting closer...
    Code (text):
    #include "LPC214x.h"
    #define PLOCK 0x400
    #define IRQ_MASK 0x00000080
    void init(void);
    void IRQ_Routine (void)   __attribute__ ((interrupt("IRQ")));
    void FIQ_Routine (void)   __attribute__ ((interrupt("FIQ")));
    void SWI_Routine (void)   __attribute__ ((interrupt("SWI")));
    void UNDEF_Routine (void) __attribute__ ((interrupt("UNDEF")));
    unsigned enableIRQ(void);
    unsigned disableIRQ(void);
    unsigned restoreIRQ(unsigned oldCPSR);

    unsigned int cp;

    int main(void)
    {
        int i;
        IODIR0 = 0x30600000;
        IOCLR0 = 0x30600000;                    //LEDs off
        init();
        T0TCR = 0x02;                           //reset counter
        T0IR = 0xff;
        T0MCR = 0x0003;                         //interrupt and reset on MR0
        T0MR0 = 0x0000ffff;                     //compare-hit count
        VICVectCntl0 = 0x00000024;              //use it for Timer 0 Interrupt:
        VICVectAddr0 = (unsigned)&IRQ_Routine;   //set interrupt vector in 0
        VICIntEnable = 0x00000010;              //enable TIMER0 interrupt
        T0TCR = 0x01;                           //enable Timer0
        cp = enableIRQ();
       
        while(1){
            i=0;
            i=1;
        }
    }

    void IRQ_Routine(void)
    {
        int i;
        IOSET0 = 0x30600000;        //4 LEDs blink
        for(i=0;i<0x0000ffff;i++);
        IOCLR0 = 0x30600000;
        T0IR = 0x01;                //clear interrupt
        VICVectAddr0 = 0;           //end of interrupt - dummy write
    }

    void init(void)
    {
        PLLCFG=0x24;                //set multiplier/divider values
        PLLFEED=0xaa;
        PLLFEED=0x55;
        PLLCON=0x01;                //enable PLL
        PLLFEED=0xaa;
        PLLFEED=0x55;
        while(!(PLLSTAT & PLOCK));  //wait for the PLL to lock to set frequency
        PLLCON=0x3;                 //connect the PLL as the clock source
        PLLFEED=0xaa;
        PLLFEED=0x55;
        MAMCR=0x02;                 //enable MAM
        MAMTIM=0x04;                //set number of clocks for flash memory fetch
        VPBDIV=0x01;                //set peripheral clock(pclk) to system clock(cclk)
    }

    void FIQ_Routine(void){
        while (1) ;
    }
    void SWI_Routine(void){
        while (1) ;
    }
    void UNDEF_Routine(void) {
        while (1) ;
    }
    static inline unsigned asm_get_cpsr(void)
    {
      unsigned long retval;
      asm volatile (" mrs  %0, cpsr" : "=r" (retval) : /* no inputs */  );
      return retval;
    }

    static inline void asm_set_cpsr(unsigned val)
    {
      asm volatile (" msr  cpsr, %0" : /* no outputs */ : "r" (val)  );
    }

    unsigned enableIRQ(void)
    {
      unsigned _cpsr;

      _cpsr = asm_get_cpsr();
      asm_set_cpsr(_cpsr & ~IRQ_MASK);
      return _cpsr;
    }

    unsigned disableIRQ(void)
    {
      unsigned _cpsr;

      _cpsr = asm_get_cpsr();
      asm_set_cpsr(_cpsr | IRQ_MASK);
      return _cpsr;
    }

    unsigned restoreIRQ(unsigned oldCPSR)
    {
      unsigned _cpsr;

      _cpsr = asm_get_cpsr();
      asm_set_cpsr((_cpsr & ~IRQ_MASK) | (oldCPSR & IRQ_MASK));
      return _cpsr;
    }
     
     
  4. dave

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    -
    Likes:
    0


     
  5. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US

    i think its:
    Code (text):

    void IRQ_Routine(void)
    {
        int i;
        IOSET0 = 0x30600000;        //4 LEDs blink
        for(i=0;i<0x0000ffff;i++);
        IOCLR0 = 0x30600000;
        T0IR = 0x01;                //clear interrupt
    [b]    VICVectAddr0 = 0;           //end of interrupt - dummy write[/b]
    //The above bold changes the address again
    }

     
    try this:
    Code (text):

    void IRQ_Routine(void)
    {
        int i;
        IOSET0 = 0x30600000;        //4 LEDs blink
        for(i=0;i<0x0000ffff;i++);
        IOCLR0 = 0x30600000;
        T0IR = 0x01;                //clear interrupt
        VICVectAddr = 0x0000;           //end of interrupt - dummy write
    }


     
    Read:
    5.4.12 Vector Address register (VICVectAddr - 0xFFFF F030)
     
  6. futz

    futz Active Member

    Joined:
    Sep 15, 2007
    Messages:
    2,043
    Likes:
    24
    Location:
    Vancouver, B.C.
    Oops! :eek: But that didn't fix it. Still doesn't work. Now, for no apparent reason, the debugger has decided it doesn't want to run the program anymore. :D Stupid thing.
     
    Last edited: Jan 19, 2009
  7. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US
    how about reseting the counter after the ISR like:

    EDIT:
    Code (text):

    void IRQ_Routine(void)
    {
        int i;
        IOSET0 = 0x30600000;        //4 LEDs blink
        for(i=0;i<0x0000ffff;i++);
        IOCLR0 = 0x30600000;
        T0IR = 0x01;                //clear interrupt
        VICVectAddr = 0x0000;           //end of interrupt - dummy write
        T0TCR = 0x02;  
        T0TCR = 0x01;            //Added this
    }
     
     
    Last edited: Jan 19, 2009
  8. futz

    futz Active Member

    Joined:
    Sep 15, 2007
    Messages:
    2,043
    Likes:
    24
    Location:
    Vancouver, B.C.
    Shouldn't be necessary. It'll wrap around. I don't care how long it takes at this point.

    And I have strange things happening. The debugger IS running it. What's happening now (I changed nothing (that I know of) to cause this) is when it gets into enable(IRQ) the program restarts every time and hits my debugger breakpoint at the start of main(). This makes it look like the program just isn't running. But when I single step I can see what's actually happening. Acts like the watchdog is running or something. It isn't. Or at least I didn't enable it. Should be disabled by default on this chip.

    Oh man! This is messin with my mind! :p
     
    Last edited: Jan 19, 2009
  9. futz

    futz Active Member

    Joined:
    Sep 15, 2007
    Messages:
    2,043
    Likes:
    24
    Location:
    Vancouver, B.C.
    Got it working finally. The LEDs are blippin away right now.

    Jason, remember when you suggested I change the "VICVectAddr0" in the ISR to "VICVectAddr". Well, I did that, and without consulting the User Manual, thought, "Hey! There's another one of those here at the line "VICVectAddr0 = (unsigned)IRQ_Routine;". So I changed that one too. BIG MISTAKE! There are 17 VICVectAddr registers. The one with no number suffix is the one you use to do a dummy write at the end of your ISR. The others are used to set the 16 IRQ vector addresses.

    So by removing the 0 suffix I ended up with no vector address for my ISR. When the interrupt hit it jumped to some random address, buzzed through empty memory, wrapped around and restarted the program.

    What fun!!! :p

    So, the working code is:
    Code (text):
    #include "LPC214x.h"
    #define PLOCK 0x400
    #define IRQ_MASK 0x00000080
    void init(void);
    void IRQ_Routine (void)   __attribute__ ((interrupt("IRQ")));
    void FIQ_Routine (void)   __attribute__ ((interrupt("FIQ")));
    void SWI_Routine (void)   __attribute__ ((interrupt("SWI")));
    void UNDEF_Routine (void) __attribute__ ((interrupt("UNDEF")));
    unsigned enableIRQ(void);
    unsigned disableIRQ(void);
    unsigned restoreIRQ(unsigned oldCPSR);

    int main(void)
    {
        int i;
        unsigned cp;
        IODIR0 = 0x30600000;
        IOCLR0 = 0x30600000;                    //LEDs off
        init();
        T0TCR = 0x02;                           //reset counter
        T0IR = 0xff;
        T0MCR = 0x0003;                         //interrupt and reset on MR0
        T0MR0 = 0x00ffffff;                     //compare-hit count
        VICVectCntl0 = 0x00000024;              //use it for Timer 0 Interrupt:
        VICVectAddr0 = (unsigned)IRQ_Routine;    //set interrupt vector in 0
        VICIntEnable = 0x00000010;              //enable TIMER0 interrupt
        T0TCR = 0x01;                           //enable Timer0
        cp = enableIRQ();
       
        while(1){
            i=0;
            i=1;
        }
    }

    void IRQ_Routine(void)
    {
        int i;
        IOSET0 = 0x30600000;        //4 LEDs blink
        for(i=0;i<0x0000ffff;i++);
        IOCLR0 = 0x30600000;
        T0IR = 0x01;                //clear interrupt
        VICVectAddr = 0;            //end of interrupt - dummy write
    }

    void init(void)
    {
        PLLCFG=0x24;                //set multiplier/divider values
        PLLFEED=0xaa;
        PLLFEED=0x55;
        PLLCON=0x01;                //enable PLL
        PLLFEED=0xaa;
        PLLFEED=0x55;
        while(!(PLLSTAT & PLOCK));  //wait for the PLL to lock to set frequency
        PLLCON=0x3;                 //connect the PLL as the clock source
        PLLFEED=0xaa;
        PLLFEED=0x55;
        MAMCR=0x02;                 //enable MAM
        MAMTIM=0x04;                //set number of clocks for flash memory fetch
        VPBDIV=0x01;                //set peripheral clock(pclk) to system clock(cclk)
    }

    void FIQ_Routine(void){
        while (1) ;
    }
    void SWI_Routine(void){
        while (1) ;
    }
    void UNDEF_Routine(void) {
        while (1) ;
    }
    static inline unsigned asm_get_cpsr(void)
    {
      unsigned long retval;
      asm volatile (" mrs  %0, cpsr" : "=r" (retval) : /* no inputs */  );
      return retval;
    }

    static inline void asm_set_cpsr(unsigned val)
    {
      asm volatile (" msr  cpsr, %0" : /* no outputs */ : "r" (val)  );
    }

    unsigned enableIRQ(void)
    {
      unsigned _cpsr;

      _cpsr = asm_get_cpsr();
      asm_set_cpsr(_cpsr & ~IRQ_MASK);
      return _cpsr;
    }

    unsigned disableIRQ(void)
    {
      unsigned _cpsr;

      _cpsr = asm_get_cpsr();
      asm_set_cpsr(_cpsr | IRQ_MASK);
      return _cpsr;
    }

    unsigned restoreIRQ(unsigned oldCPSR)
    {
      unsigned _cpsr;

      _cpsr = asm_get_cpsr();
      asm_set_cpsr((_cpsr & ~IRQ_MASK) | (oldCPSR & IRQ_MASK));
      return _cpsr;
    }
     
    Now I think I'll take that enableIRQ() code and put it back out in a separate file. Now that I know it works I sure don't need to see it all the time.
     
    Last edited: Jan 20, 2009
  10. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US
    Awsome!!!

    futz i dont want to hassle you but can i get a copy of the code and startup please? So when i get mine i can study it also.

    Code (text):

    VICVectAddr0 = (unsigned)IRQ_Routine;
     
    This is used to tell the uC that ISR routine that you want it to jump to that location on the ISR set using "VICVectCntl0". Since its a address i suggested using the & sign as:
    Code (text):

    VICVectAddr0 = (unsigned)&IRQ_Routine;
     
    But as we can see its not needed.
     
  11. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US
    Since you can use many IRQ routines think about naming it like T0IRQ_Routine
     
    Last edited: Jan 19, 2009
  12. futz

    futz Active Member

    Joined:
    Sep 15, 2007
    Messages:
    2,043
    Likes:
    24
    Location:
    Vancouver, B.C.
    Will you be using Eclipse/yagarto? If you're going to be running Crossworks you don't need any of this stuff.

    Yes, I know. VICVectAddr0 is the vector address for IRQ slot 0, which is the highest priority vectored IRQ. Only FIQ gets serviced at higher priority.

    Yup. Your idea made sense, but I looked at other code and nobody puts the &, so I guess it's not necessary.
     
  13. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US
    heh im not telling you what "VICVectAddr0" is just stating that i also know lol.
    Yeah im thinking about using "Eclipse/yagarto/OpenOCD" but might look into Crossworks or even RealView MDK which i think uses uVision or something.

    But my main plan is the Trio("Eclipse/yagarto/OpenOCD") or Crossworks. Im thinking Crossworks tho. Mainly because it looks like it will be easier to setup and more popular.

    The thing i dont understand is. Can i cross compile? Like use code made using yaharto with crossworks? Are they compatible? Or will there be many differences?

    Which are you sticking with?
     
  14. futz

    futz Active Member

    Joined:
    Sep 15, 2007
    Messages:
    2,043
    Likes:
    24
    Location:
    Vancouver, B.C.
    You don't need to cross compile. It's the same free open-source GCC compiler.

    As much as I dislike using that flaky debugger in Eclipse/yagarto/OpenOCD, I'm sticking with it. It works. You just have to learn its many quirks and bugs and how to work around them. It's flaky as hell, but you can get things done with it. The Crossworks debugger, in comparison, is beautifully polished and so sweet to use.

    I figure if I'm going to be using GCC either way, I learn a LOT more by using the open-source tools than I do with a polished package like Crossworks. Yes it's painful and takes a lot of time to figure it all out, but at the end I know a lot more than I would if I had used only Crossworks. They hide all this complexity from you unless you need to look at it. So you're going to have the pain sometime. Now, if you use Eclipse/yagarto, or later if you use Crossworks.
     
    Last edited: Jan 19, 2009
  15. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US
    ok i think i understand it a bit more. Yeah i would also agree that using open source tools gives one an advantage when learning because you have more options to setup. Hence learning more about the whole package.

    Dude when ever you want or can maybe you can write a little "how-to" to get me started on this ARM stuff. Maybe place it on your site as a article this way others can gain from this info.
     
  16. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US
  17. futz

    futz Active Member

    Joined:
    Sep 15, 2007
    Messages:
    2,043
    Likes:
    24
    Location:
    Vancouver, B.C.
  18. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US
    I was referring to the software at the bottom but i just remembered you said yours came with a cd i assume thats on it already then. :D
     
  19. futz

    futz Active Member

    Joined:
    Sep 15, 2007
    Messages:
    2,043
    Likes:
    24
    Location:
    Vancouver, B.C.
    Yes it is.
     
  20. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US
    im going to go see if i can gather info on setting up all 3 tools. I have all 3 installed and just need to understand how to integrate them together.

    I was reading some on your site but got lost really :)
     
  21. Ubergeek63

    Ubergeek63 Well-Known Member

    Joined:
    Apr 16, 2008
    Messages:
    1,886
    Likes:
    37
    Last edited: Jan 20, 2009

Share This Page