EmbeddedRelated.com
Forums

LPCUSB VCOM IRQ + LPC2148 + Crossworks

Started by darkcobrax February 6, 2007
I'm trying to get the LPCUSB VCOM example working using interrupts,
but am having a strange problem.

I have the Olimex LPC-H2148, Crossworks v1.6 Build 2, and a Wiggler
clone for JTAG. Here's what I did to set up and modify the project:

1) Create a new project:
Type: Philps LPC2000/Generic LPC21xx Board/Executable
Target Processor: LPC2148
All other options default
2) in System File Philips_LPC210X_Startup.s, add #define
VECTORED_IRQ_INTERRUPTS
3) Add all applicable .c files from LPBUSB (latest version 142 from
SVN)
4) In main_serial.c, add a stub for __putchar
5) In main_serial.c, main function:
a) comment out call to Initialize (Crossworks sets clocks for you)
b) replace call to enableIRQ() with libarm_enable_irq()
c) at top of function, add: int i1;
d) just before end of endless echo loop, add: for
(i1=0;i1<2000;i1++);
6) Make sure the project's Properties/Compiler Options/Optimization
Level = None
7) Set active configuration to ARM RAM Debug, then Build and Run

If I follow this *exactly*, it works! But if I change almost
anything, the LPC locks up instead. Here are just a few of the
things I've tried that will break it:

Trying to run a Release version
Increasing the Optimization Level
Omitting the delay loop I've added

Even weirder, if I add the following function:

void delay(int d) {
int i1;
for(i1=0; i1<=d; i1++);
}

Then call delay(2000) to provide the delay instead, *the LPC locks
up*, even though this is functionally equivalent!

This suggests to me that something is wrong on a very low level.
Stack corruption? Memory alignment issues? Faulty assembly-level
IRQ handlers? I don't know.

Any insight on this issue would be greatly appreciated.

An Engineer's Guide to the LPC2100 Series

Update - I think I've fixed *one* problem.

The current recommended IRQ stack size for LPCUSB is 128 bytes.
Crossworks defaults to 256, so I originally assumed no problem
there. But I tried increasing it further to 512 bytes, and now it
seems to work flawlessly in Ram Debug, without the need for that odd
delay loop. I don't understand why I need a larger stack than
everyone else, but hey - whatever works, right?

However, I still can't get it to run in Flash, or Ram Release mode.

Here is some additional information I have been able to gather, if
any of this is useful:

Execution stops after ~0.2 seconds, but this time is not constant and
varies between runs. In Ram Release, it appears to stop at something
called PABORT_HANDLER. In Flash Release/Debug, it stops at
DABORT_HANDLER. Execution appears to stop upon return from USBHwISR,
not within. On the last pass through, it processes an "endpoint
interrupt", but none of the 32 endpoint bits are set.

Again, any insight is appreciated. I'll provide any additional
information required upon request.
Hello darkcobrax

Probably related to GCC bug #16634 (google for more info)

I think it can occur if the following situations are true:

- using the IRQ keyword
- use optimization (As in release mode)
- call a function from the interrupt

If I remember correctly, the return address will be wrong, because of a
mixed codegeneration of optimized and non-optimized code. A solution is
to use a assembly stub to handle the interrupt instead of using the

__attribute__ ((interrupt("IRQ")))

Hope this helps,

Aalt
The LPC2148 user manual mentions a minimum clock of 18 MHz (I can't
recall now whether this is for CCLK or PCLK). Are you complying with
that?

Is your MAM timing correct? (does other code run without problems?)
The clock and MAM setting is done in the Initialize function that you
commented out.

Can you set the IRQ really big (say 2k) and then send me the map
file of the unoptimised executable and the map file of the optimised
executable? (this way I hope to see if there is a problem with
struct packing / alignment).

Kind regards,
Bertrik
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?
--- In l..., Bertrik Sikken wrote:
> The LPC2148 user manual mentions a minimum clock of 18 MHz (I can't
> recall now whether this is for CCLK or PCLK). Are you complying with
> that?
>
> Is your MAM timing correct? (does other code run without problems?)
> The clock and MAM setting is done in the Initialize function that you
> commented out.

Crossworks appears to embed startup code that automatically sets all
this to appropriate values for this processor. I'm fairly certain
CCLK is 60mhz, PCLK is 30mhz, and MAM is on with optimal timing.
I'll double-check when I have a chance.

> Can you set the IRQ really big (say 2k) and then send me the map
> file of the unoptimised executable and the map file of the optimised
> executable? (this way I hope to see if there is a problem with
> struct packing / alignment).

My apologies, I have only a few days experience with Crossworks, GCC,
ARM, and this MCU (actually, *any* MCU), and I don't understand what
you just said. :) Hopefully you no longer need it, as the program is
now working except for an optimization problem - probably due to a
known GCC bug.

By the way, thank you for developing and supporting LPCUSB! Its
existence was a deciding factor in my choosing the LPC2148. Also,
the NAK interrupt fix in build 142 seems to be working as intended;
prior to that I was getting ~80k interrupts/second.
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.
>
> 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
--- 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.
--- 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!