Continue to Site

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.

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

Can't get LPC2148 timer match interrupts to work

Status
Not open for further replies.
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:
.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.
 
all interrupts on a PIC are disabled until you enable them.
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!


Why not just comment this out:
Code:
.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.
I'm thinking more like in this piece of crt.s code
Code:
    			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:
    			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:
This code pops the interrupt once each time the processor is reset, but never again. So I'm getting closer...
Code:
#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;
}
 
i think its:
Code:
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:
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)
 
how about reseting the counter after the ISR like:

EDIT:
Code:
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:
how about resetting the counter after the ISR like:
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:
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:
#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:
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:
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:
VICVectAddr0 = (unsigned)&IRQ_Routine;

But as we can see its not needed.
 
I don't 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.
Will you be using Eclipse/yagarto? If you're going to be running Crossworks you don't need any of this stuff.

Code:
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".
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.

Since its a address i suggested using the & sign as:
Code:
VICVectAddr0 = (unsigned)&IRQ_Routine;

But as we can see its not needed.
Yup. Your idea made sense, but I looked at other code and nobody puts the &, so I guess it's not necessary.
 
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?
 
The thing i dont understand is. Can i cross compile? Like use code made using yagarto with crossworks? Are they compatible? Or will there be many differences?

Which are you sticking with?
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:
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.
 
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 :)
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top