Reply by Brendan Murphy February 7, 20072007-02-07
--- In l..., "Michael Anton" wrote:
> You of course still need a proper assembler stub to call your C
> function for this to work. I am not sure if they are included in
> CrossWorks. This stub saves the registers used by the called C
> function (R0-R3, IP, and LR).
>
> Here is what I use to call an interrupt routine:
>
> stmfd SP!,{R0-R3,IP,LR} // Save critical registers on the stack
> ldr R0,VICVectAddr // Address of the VICVectAddr register
> ldr R0,[R0] // Read the VICVectAddr register to get the interrupt
> handler address
> ands R0,R0 // Check if the adress is zero, and set flags
> movne LR,PC // Save the PC in the link register so we can return
> bxne R0 // Branch to the interrupt handler
> ldr R0,VICVectAddr // Address of the VICVectAddr register
> str R0,[R0] // Update the VIC priority hardware
> ldmfd SP!,{R0-R3,IP,LR} // Restore the stack
> subs PC,LR,#4 // Return from routine
>
> VICVectAddr: .word 0xFFFFF030
>
> This will fetch the interrupt handler address from the VIC.
> If anyone has a better method of doing this, I'm open to
> suggestions, especially since I'm and ARM assembler newbie.
>
> Mike
>

Mike,

An alternative stub is below (no doubt the formatting will be messed
up making it difficult to read, but you should get the idea). It's
slightly longer, but has the following advantages:

- nested interrupts, where a higher priority interrupt can interrupt
the ISR), are supported

- interrupts are disabled for an absolute minimum of time (6
instructions into the ISR), rather than the whole ISR

- the main ISR code can be coded as a standard 'C' function, with no
special keywords and pragmas (and can by in Thumb if required),
removing problems with portability and bugs in these features in some
compilers

- stack space is optimised slightly: the IRQ stack is minimal (4
words) and no extra safety margin is needed

Brendan

An Engineer's Guide to the LPC2100 Series

Reply by darkcobrax February 7, 20072007-02-07
--- In l..., "Michael Anton" wrote:
> I forgot to mention that you do need to change the interrupt vector
> to branch to this stub, or it won't change a thing.

D'OH! That could be important, yes.. :)

I did a quick test by butchering the built-in Crossworks IRQ stub,
which is what I had been replacing with other stubs. The interrupts
continued working. You are correct, I never really changed a thing.

Your files look very different than mine. Fortunately, I recognized
the 'ldr pc, [pc, #-0xFF0]' command. The Crossworks docs say:

"You need to have the instruction 'ldr pc, [pc, #-0xFF0]' located at
the IRQ exception vector for vectored interrupts to work. To do this
make sure you have the preprocessor definition
VECTORED_IRQ_INTERRUPTS defined when you compile the
Philips_LPC210X_Startup.s file."

This define was actually the *first* thing I'd added trying to get
LPCUSB to work. Without it, the interrupt function as declared by
Bertrik with '__attribute__ ((interrupt("IRQ")))' didn't work at
all. I hunted down the conditional compile for this define, and
guess what it has if you *don't* define this?

A jump to the Crossworks IRQ stub. D'OH again!

So I removed the define, positively verified that the default
Crossworks IRQ stub is being used, and removed '__attribute__
((interrupt("IRQ")))' from the interrupt declaration.

The interrupt routine is now working with optimizations on!

Strangely, this broke something in my own, non-interrupt code. I'll
save this issue for later, it's break time. Three days of debugging
only to learn I'd taken a wrong turn at the beginning. At least it
was a scenic and educational route!
Reply by Michael Anton February 7, 20072007-02-07
>
> Though I'm satisfied with the other workaround, I went ahead
> and tried
> this in combination with your prior suggestion. Same deal - works
> fine as long as optimization is off. There may be some other
> difference in play between your setup and mine.
>
> > This will fetch the interrupt handler address from the VIC.
> > If anyone has a better method of doing this, I'm open to
> > suggestions, especially since I'm and ARM assembler newbie.
>
> I've seen two stubs other than yours - one in Crossworks, and
> one Paul
> Knight sent me. I can't tell you which is best since I'm a complete
> asm newb, but all produced identical results for me. Let me know if
> you want me to post them.
>

I forgot to mention that you do need to change the interrupt vector
to branch to this stub, or it won't change a thing.

Here is a more complete snippet, starting with the interrupt
jump table:



Replace the line two lines up (it should be something similar in your code)
with:



Then include the stub below, after the FIQ branch (or perhaps the FIQ
routine if it is in assembler):



I suspect in all of the cases you tried, that the stub was not
actually used.

Mike
Reply by darkcobrax February 7, 20072007-02-07
--- In l..., "Michael Anton" wrote:
> You of course still need a proper assembler stub to call your C
> function for this to work. I am not sure if they are included in
> CrossWorks. This stub saves the registers used by the called C
> function (R0-R3, IP, and LR).

Though I'm satisfied with the other workaround, I went ahead and tried
this in combination with your prior suggestion. Same deal - works
fine as long as optimization is off. There may be some other
difference in play between your setup and mine.

> This will fetch the interrupt handler address from the VIC.
> If anyone has a better method of doing this, I'm open to
> suggestions, especially since I'm and ARM assembler newbie.

I've seen two stubs other than yours - one in Crossworks, and one Paul
Knight sent me. I can't tell you which is best since I'm a complete
asm newb, but all produced identical results for me. Let me know if
you want me to post them.
Reply by Michael Anton February 6, 20072007-02-06
> I just tried it, and it didn't solve the problem. But I'll remember
> those functions - as you said, it's a lot easier. Thanks!

You of course still need a proper assembler stub to call your C
function for this to work. I am not sure if they are included in
CrossWorks. This stub saves the registers used by the called C
function (R0-R3, IP, and LR).

Here is what I use to call an interrupt routine:



This will fetch the interrupt handler address from the VIC.
If anyone has a better method of doing this, I'm open to
suggestions, especially since I'm and ARM assembler newbie.

Mike
Reply by darkcobrax February 6, 20072007-02-06
--- In l..., "Michael Anton" wrote:
> Another workaround, is to just disable optimization for your
> interrupt code, but enable optimization for everything else.
> But, I'm not sure how you would do this in Crossworks. It is not
> hard to if using a GCC makefile.

This worked! And it's a workaround I can live with. I moved the ISR
to a file by itself, and Crossworks has a 'properties' window that
lets you set optimization on a file-by-file basis.

All my problems using LPCUSB seem to be solved. I'll go stress-test
it now to make sure. :)

Thanks again to everyone who helped me through this!
Reply by darkcobrax February 6, 20072007-02-06
--- In l..., "Paul Curtis" wrote:
> The best thing you could do is just write your ISR in plain C and not worry
> about the interaction of optimization and IRQs as that's all just plain
> hidden by the goo that comes with CrossWorks. I use this to set up my own
> ISR:

I just tried it, and it didn't solve the problem. But I'll remember
those functions - as you said, it's a lot easier. Thanks!
Reply by Darcy Williams February 6, 20072007-02-06
--- In l..., "Michael Anton" wrote:
> Another workaround, is to just disable optimization for your
> interrupt code, but enable optimization for everything else.
> But, I'm not sure how you would do this in Crossworks. It is not
> hard to if using a GCC makefile.
>
> I was bit by this bug recently as well (initially the code worked fine
> with optimizations enabled, until I changed it slightly), and ended
> up coding assembler stubs.

This should answer the question...
http://ccgi.rowley.co.uk/support/faq.php?do=article&articleidW

Question:
I have a source file that contains a number of functions and I want to
set the optimization level of one of those functions to a different
value. Is it possible to set the optimization level of a single
function within a single source file?

Answer:
No, the optimization level can only be set for the entire source file
using the Compiler > Optimization Level project property. You will
need to put the function into another source file and set the
optimization level of this source file to the required value.
Reply by Michael Anton February 6, 20072007-02-06
>
> I was aware of that GCC bug, made sure that optimization was off, and
> even tried the workaround using an assembly stub; but no joy.
>
> It was your wording "As in release mode" that clued me in -
> Crossworks keeps different settings for each mode! Though
> optimization was off for Ram Debug, it *wasn't* off for the other
> modes.
>
> Now I can run successfully in all modes, as long as I have
> optimization *off*.
>

Another workaround, is to just disable optimization for your
interrupt code, but enable optimization for everything else.
But, I'm not sure how you would do this in Crossworks. It is not
hard to if using a GCC makefile.

I was bit by this bug recently as well (initially the code worked fine
with optimizations enabled, until I changed it slightly), and ended
up coding assembler stubs.

Good luck,

Mike Anton
Reply by Paul Curtis February 6, 20072007-02-06
Hi,

Having implemented my own USB stack for the LPC2148 with CrossWorks, I
suppose I'd better chime in here.

> Aalt, indeed it *does* help. Thank you!
>
> I was aware of that GCC bug, made sure that optimization was off, and
> even tried the workaround using an assembly stub; but no joy.
>
> It was your wording "As in release mode" that clued me in -
> Crossworks keeps different settings for each mode! Though
> optimization was off for Ram Debug, it *wasn't* off for the other
> modes.
>
> Now I can run successfully in all modes, as long as I have
> optimization *off*.
>
> The last problem is getting this to work with optimization.
> Crossworks appears to already use an assembly stub, in file
> VIC_irq_handler.s. However, the documentation states you must still
> use __attribute__ ((interrupt("IRQ"))).
>
> I received a replacement stub from Paul Knight, which he said helped
> in getting his USBLIB to run (apparently under plain GCC). It seems
> to make no difference - if I remove the IRQ attribute or turn
> optimization on, the program fails.
>
> Has anyone successfully implemented this workaround with Crossworks?

The best thing you could do is just write your ISR in plain C and not worry
about the interaction of optimization and IRQs as that's all just plain
hidden by the goo that comes with CrossWorks. I use this to set up my own
ISR:



To handle USB requests I have:



-- Paul.