Forums

LPC2366: Question about UART interrupt which goes into DAbt_Handler

Started by abracadalba November 21, 2007
Hi to everyone,

I'm using LPC2366.
My question is about an UART interrupt wich goes into DAbt_Handler.
More in detail, a part of my projest is to receive data through UART2
and to echo the received data to UART1.
Both UARTs are configured @600kBaud.
After receiving some characters, I see my application crashing.
I Use Keil uVision with GCC.
Optimization level is 1.

Used prototypes are:

void UART2_Handler(void) __attribute__ ((naked));
void UART1_Handler(void) __attribute__ ((naked));

I use these Macros in order to manage entry/exit to/from interrupts:

#define ISR_ENTRY() asm volatile(" sub lr, lr,#4\n" \
" stmfd sp!,{r0-r12,lr}\n" \
" mrs r1, spsr\n" \
" stmfd sp!,{r1}")

#define ISR_EXIT() asm volatile(" ldmfd sp!,{r1}\n" \
" msr spsr_c,r1\n" \
" ldmfd sp!,{r0-r12,pc}^")
UART2 is initializated as follows:

void UART2_Init(unsigned long int baudrate)
{
DWORD Fdiv;
unsigned int indice;

/* ATurn on UART2 */
PCONP |= (1 << 24);

PCLKSEL1 &= 0xFFFDFFFF; /* UART2 clk = CCLK */
PCLKSEL1 |= 0x00010000; /* */

U2LCR = 0x83; /* 8 bits, no Parity, 1 Stop bit
Enable access to divisor registers*/

Fdiv = (F_PCLK_UART2/16)/baudrate ; /* baud rate settings */
U2DLM = Fdiv / 256;
U2DLL = Fdiv % 256;

U2LCR = 0x03; /* DLAB = 0: Disable access to divisor registers */
U2FCR = 0x07; /* Enable and reset TX and RX FIFO, */
/* interrupt enable when there are 4 characters */
/*in the RX FIFO */

/*-------------*/
/* Install IRQ */
VICIntEnClr = 1 << UART2_INT; /*Disable interrupt UART2 on VIC*/
VICVectCntl28 = 0x00000001; /*Priority */
VICVectAddr28 = (DWORD) &(UART2_Handler);

VICIntSelect &= 0xEFFFFFFF; /*Interrupt is IRQ*/

VICIntEnable |= (1 << UART2_INT); /* EnableIRQ for UART2*/

/* Enable UART2 interrupt sources */
U2IER = IER_RBR | IER_THRE | IER_RLS;
}

And this is the code of my UART2 ISR:
As you can see, this interrupt routine does nothing, it
simply delete the cause of the interrupt.
That I see is that, aftes some ISR callings, the application
crashes and then the DAbt_Handler is called.

void UART2_Handler (void)
{
volatile BYTE IIRValue, LSR2Value, LSR1Value;
volatile BYTE Dummy, indice, pippo;

ISR_ENTRY(); /* IRQ ISR prefix.*/

IIRValue = U2IIR; /* Read interrupt cause*/

IIRValue >>= 1; /* Skip pending bit in IIR */
IIRValue &= 0x07; /* interrupt identification */

switch(IIRValue)
{
case(IIR_RLS):
{
LSR2Value = U2LSR;
}
break;

case(IIR_RDA):
case(IIR_CTI):
{
Dummy = U2RBR;
}
break;

case(IIR_THRE):

LSR2Value = U2LSR; /* Check status in the LSR */

if ( LSR2Value & LSR_THRE )
UART2TxEmpty = 1;
else
UART2TxEmpty = 0;

break;

} /* End switch */

/* Clear this interrupt from the VIC */
VICVectAddr = 0x00000000;

ISR_EXIT();

return;
}

Someone could help me?
Thank you in advance!

An Engineer's Guide to the LPC2100 Series

On Wed, 21 Nov 2007, abracadalba wrote:

> I'm using LPC2366.
> My question is about an UART interrupt wich goes into DAbt_Handler.

...

> /* Clear this interrupt from the VIC */
> VICVectAddr = 0x00000000;
> ISR_EXIT();
> return;

Just a guess, but shouldn't you clear the VIC *after* your ISR prolog?
I suspect (it's happened to me) that you're clearing the VIC, you get
another interrupt (you cleared the old one by reading I2IIR), so you
keep descending thru the IRQ stacks over and over 'till you run past the
end of RAM (or run past your IRQ stack into somewhere else) and generate
your DABT.

-Kenny

--
Kenneth R. Crudup Sr. SW Engineer, Scott County Consulting, Los Angeles
O: 3630 S. Sepulveda Blvd. #138, L.A., CA 90034-6809 (888) 454-8181
Hi Kenny,
and thank you very much for your reply.
I have made as you suggested, but with these modifications my LPC
doesn't
exit from an ISR routine.

Thinking more about the problem, I think it could be a problem of
declaration of ISRs.
As I told in my first post, I declare ISRs as *naked* using
the __attribute__ ((naked)) declaration in prototypes.
Moreover, I use the ISR_ENTRY and ISR_EXIT assembly macros
in order to manage the SP.

At this point, I don't know if this managing is correct. [:((]
I'm using GCC, optimization level is 1, and my IDE is Keil uVision.

Anyoune could help me? [:)]
Hi to everyone,
I am still investigating why I am experiencing problems with UART
interrupt of my LPC2366 @48MHz.

- My ISR routines are declared *naked*;
- I'm using Keil uVision with GNU compiler GCC V3.3.1 (Maybe it is too
old?);
- I'm using the ISRENTRY and ISREXIT macros;

The problem I experience is that after a few seconds of execution, my
application crashes and goes to DAbt_Handler.
I experience this problem only with UART interrupt, and other
interrups works ok... maybe because UART is at high speed (600kBaud)?

ISR_ENTRY:
sub lr, lr,#4
stmfd sp!,{r0-r12,lr}
mrs r1, spsr
stmfd sp!,{r1}

ISR_EXIT:
ldmfd sp!,{r1}
msr spsr_c,r1
ldmfd sp!,{r0-r12,pc}^

My UART routine is very simple (in order to investigate the problem):
void UART2_Handler (void)
{
volatile BYTE IIRValue, LSR2Value, LSR1Value;
volatile BYTE Dummy;

IIRValue = U2IIR;

I_ENABLE;

IIRValue >>= 1;
IIRValue &= 0x07;

switch(IIRValue)
{
case(IIR_RLS):
LSR2Value = U2LSR;
break;

case(IIR_RDA):
case(IIR_CTI):
Dummy = U2RBR;
break;

case(IIR_THRE):

LSR2Value = U2LSR;
if ( LSR2Value & LSR_THRE )
UART2TxEmpty = 1;
else
UART2TxEmpty = 0;

break;

}

I_DISABLE;

VICVectAddr = 0x00000000;
}

I've read in AN10381 there are other MACROS: I_ENABLE and I_DISABLE.
I'm confused... what couple of macro should I use?

Any help or suggestion will be very appreciated!

Thank you very much in advance.
All,

> abracadalba wrote:
> > - My ISR routines are declared *naked*;
> > - I'm using the ISRENTRY and ISREXIT macros;
>
> Whatever the reason, I had some problems with an interrupt a while ago.
> I also had the ISR declared "naked" and with the same macros.
>
> I tracked my problems down to having local variables within the
> interrupt; for some reason, with those macros the main stack
> got overrun at some point, and actually what was lost wasn't the
> return address from the IRQ... no, the problem was when the software
> had
> returned from the IRQ into the "main loop" which happened to be running
> in a function at that time. The return address from that function
> was trashed, so when it was done, the ARM promptly crashed.
>
> Removing the local variables fixed it for me, also running the software
> as attribute interrupt "IRQ" worked and even with local variables.
> (Didn't test with optimization or Thumb mode, though).
>
> After getting it working (I finally left it "naked" with macros, and
> the couple variables used as global ones) I was already too far behind
> schedule so I didn't have time, or really interest either,
> to investigate further. The usual story.
>
> (GCC, under Crossworks 1.7)
>
> So, I still really have no idea about the _real_ reason for it not
> working.

There is a known issue with GCC's code generation on ISRs; so, in order to
sidestep the issue and provide a nice solution, ctl_set_interrupt just plugs
a regular function into a slot to be executed by the vectoring scheme.
Simple. I just wonder why customers don't use this, you don't need to use
the taking, you just need to set the ISR.

-- Paul.
> >
> > So, I still really have no idea about the _real_ reason for it not
> > working.

Presumably, something is being written to the stack at bigger offset
than it shoud be - the local variables probably.

> There is a known issue with GCC's code generation on ISRs; so, in
order to
> sidestep the issue and provide a nice solution, ctl_set_interrupt
just plugs
> a regular function into a slot to be executed by the vectoring scheme.
> Simple. I just wonder why customers don't use this, you don't need
to use
> the taking, you just need to set the ISR.

I can second that. When I started on these ARM projects, I expected to
have problems with interrupts. Instead, I have had problems
everywhere else. I set up the interrupts with ctl_set_isr and
ctl_unmask_isr, and they just worked. I have UART, CAN, timer/capture
interrupts and they all worked fine, (well, after debugging,
obviously). My interrupt-handlers are compiled in thumb-mode but,
again, not a problem with CrossWorks/ctl.

Rgds,
Martin
abracadalba wrote:
> - My ISR routines are declared *naked*;
> - I'm using the ISRENTRY and ISREXIT macros;

Whatever the reason, I had some problems with an interrupt a while ago.
I also had the ISR declared "naked" and with the same macros.

I tracked my problems down to having local variables within the
interrupt; for some reason, with those macros the main stack
got overrun at some point, and actually what was lost wasn't the
return address from the IRQ... no, the problem was when the software had
returned from the IRQ into the "main loop" which happened to be running
in a function at that time. The return address from that function
was trashed, so when it was done, the ARM promptly crashed.

Removing the local variables fixed it for me, also running the software
as attribute interrupt "IRQ" worked and even with local variables.
(Didn't test with optimization or Thumb mode, though).

After getting it working (I finally left it "naked" with macros, and
the couple variables used as global ones) I was already too far behind
schedule so I didn't have time, or really interest either,
to investigate further. The usual story.

(GCC, under Crossworks 1.7)

So, I still really have no idea about the _real_ reason for it not
working.
Hi,

> Hello to everyone,
> and thank you very very much for your reply ;-)
>
> I am a little confused about the routines (or functionality)
> you mentioned.
> In detail, someone can briefly describe
> "ctl_set_interrupts", "ctl_set_isr", etc?
> Can I use them with GNU or has it its own relative
> functionality?
> Thank you very much in advance.

It's provided with CrossWorks and fully documented. It's not a generic GNU
thing.

--
Paul Curtis, Rowley Associates Ltd http://www.rowley.co.uk
CrossWorks for ARM, MSP430, AVR, MAXQ, and now Cortex-M3 processors
Hello to everyone,
and thank you very very much for your reply ;-)

I am a little confused about the routines (or functionality)
you mentioned.
In detail, someone can briefly describe
"ctl_set_interrupts", "ctl_set_isr", etc?
Can I use them with GNU or has it its own relative
functionality?
Thank you very much in advance.

Albert
> It's provided with CrossWorks and fully documented. It's not a
generic GNU
> thing.
>

Thank you Paul :-).
Unfortunately, we have already started our project
using Keil+GCC, thus I don't think we can now change
our IDE in order to buy CrossWorks...
Thank you very very much, anyway!

Does someone know if exist another way achieve
the results of the functionalities we are talking
about?

**************
** If does not exist, I am wrong if i tell that using
** only GCC I can't manage correctly ISRs?
**************

Thank you very much,

Alberto