Reply by abracadalba November 26, 20072007-11-26
> I'm coming into this thread without having read its beginning, so I
might be
> off topic.
>
> You are declaring the IRQ naked and then providing your own prologue and
> epilogue code through the use of the macros - but do these macros
setup a
> stack frame? Probably not as they don't know how big a stack you
require.
> You state that you have a local variable, but where is this variable
ending
> up in RAM?
>
> The easiest way of ensuring correct behaviour, but not the most
efficient
> way, is to split the ISR into two, a wrapper and a handler, as follows:
>
> void vAnISRWrapper( void ) __attribute__((naked));
> void vAnISRHandler( void );
>
> void vAnISRWrapper( void )
> {
> ____SAVE_CONTEXT(); /* Prologue macro. */
>
> ____/* Call the handler function. No stack is required
> ____by the wrapper as all it does is perform a branch. */
> ____vAnISRHandler();
>
> ____RESTORE_CONTEXT(); /* Epilogue macro. */
> }
>
> void vAnISRHandler( void )
> {
> ____/* Function that actually does the ISR work. If
> ____declaring a local variable here then the *compiler*
> ____will ensure there is stack allocated during the
> ____compiler generated function prologue. */
>
> long lAVariableDeclaredLocally;
>
> ____/* The variable can be accessed safely. */
> ____lAVariableDeclaredLocally = 0;
>
> ____/* Clear the interrupt before exiting the function! */
> }
> Regards,
> Richard.

Hello to everyone,
and thank you all for your answers.
In effect, you are right: the problem was in the managing of
local variables IN THE CASE THERE WILL BE NESTED INTERRUPTS.
I've seen this disabling all the interrupts except the UART ISR,
making it work very slowly, and tracing the entry/exit to/from the ISR.
As you suggest, a safe mode to correctly manage this behaviour is
to call an extern function (thanks Richard!) which safely manages
local variables.

Because the external function is a *normal* function, it is
Interruptible by other ISRs, even from ISRs which priority is less
then the priority of the ISR we are coming from. In order to
completely manage prioritized nested interrupts, now is required a bit
of code for managing the priority, in order to disable interrupts with
priority less or equal than the ISR we are coming from.
What do you think? Am I wrong?

Thank you very much for your answer, again.

An Engineer's Guide to the LPC2100 Series

Reply by Kenneth Crudup November 26, 20072007-11-26
On Mon, 26 Nov 2007, abracadalba wrote:

> Because the external function is a *normal* function, it is
> Interruptible by other ISRs, even from ISRs which priority is less
> then the priority of the ISR we are coming from. In order to
> completely manage prioritized nested interrupts, now is required a bit
> of code for managing the priority, in order to disable interrupts with
> priority less or equal than the ISR we are coming from.

Nah, that's what the VIC handles for you. In each of my ISRs, in every
(well, "most") of my interrupt handlers, after getting the cause of, then
clearing the source of the interrupt, I re-enable higher-priority (by VIC
lookup-table entry) interrupts (by dropping 0x0 in the VICVectReg).

I have code similar to yours that runs IRQs as regular functions in SVC
mode.

-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
Reply by "FreeRTOS.org Info" November 23, 20072007-11-23
> > 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?
> **************
>

I'm coming into this thread without having read its beginning, so I might be
off topic.

You are declaring the IRQ naked and then providing your own prologue and
epilogue code through the use of the macros - but do these macros setup a
stack frame? Probably not as they don't know how big a stack you require.
You state that you have a local variable, but where is this variable ending
up in RAM?

The easiest way of ensuring correct behaviour, but not the most efficient
way, is to split the ISR into two, a wrapper and a handler, as follows:

void vAnISRWrapper( void ) __attribute__((naked));
void vAnISRHandler( void );

void vAnISRWrapper( void )
{
____SAVE_CONTEXT(); /* Prologue macro. */

____/* Call the handler function. No stack is required
____by the wrapper as all it does is perform a branch. */
____vAnISRHandler();

____RESTORE_CONTEXT(); /* Epilogue macro. */
}

void vAnISRHandler( void )
{
____/* Function that actually does the ISR work. If
____declaring a local variable here then the *compiler*
____will ensure there is stack allocated during the
____compiler generated function prologue. */

long lAVariableDeclaredLocally;

____/* The variable can be accessed safely. */
____lAVariableDeclaredLocally = 0;

____/* Clear the interrupt before exiting the function! */
}
Regards,
Richard.

+ http://www.FreeRTOS.org
14 official architecture ports, 1000 downloads per week.

+ http://www.SafeRTOS.com
Certified by T as meeting the requirements for safety related systems.



Reply by abracadalba November 23, 20072007-11-23
> 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
Reply by abracadalba November 23, 20072007-11-23
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
Reply by Paul Curtis November 23, 20072007-11-23
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
Reply by Sam Laur November 23, 20072007-11-23
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.
Reply by mjames_doveridge November 23, 20072007-11-23
> >
> > 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
Reply by Paul Curtis November 23, 20072007-11-23
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.
Reply by abracadalba November 23, 20072007-11-23
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.