Offline compiler : nearly there, just need a little more help.

28 May 2011

Hi there !

Short intro : I'm currently porting the grbl opensource g-code interpreter to the LPC1768/9. So offline compiling, targeting both the mbed and the LXPxpresso board. In doing that, I super often end up re-coding things the mbed library alredy provides in a very very nice way. Not fun. So I'm trying to use the mbed libs directly into my project, but that does not work. That's where I need a little help.

I have not seen a single place on the internet where somebody reports successfully using the mbed libraries with the GNU toolchain. If you know such a place, please tell. However, it seems that it can work with the Keil compiler.

The most usefull piece of information that can be found on using the GNU toolchain ( codesourcery ) with the mbed libraries is here.

Ok so here is what I've done so far : 

  • 1. Install codesourcery's toolchain, it has a nice graphical installer, so that's easy.
  • 2. Setup a base project. I used this because it does C++ ( which most examples on the net do not ) and is quite complete.

Quote:

mkdir mbedlibs

cd mbedlibs

wget http://cortex-m3-tutorials.googlecode.com/files/lpc_17xx_CPP_26Apr2011.rar

unrar e lpc_17xx_CPP_26Apr2011.rar

rm *.rar

Just change cs-rm to rm at line 78 in makefile, and remove makesection/ at line 27 and the usb bootloader target at line 82, and it should compile fine. Your config may need other small adjustments like that.

Ok so now we can compile C++ programs for the mbed ( .bin files ) and the lxpresso board ( .elf files ), we just miss the mbed libraries.

  • 3. Get the mbed libraries :

Quote:

svn checkout http://mbed.org/projects/libraries/svn/mbed/trunk

mv trunk mbed

cp mbed/LPC1768/mbed.ar mbed/libmbed.a

cp mbed/LPC1768/capi.ar mbed/libcapi.a

Now edit the makefile, line 66 should become :

LDFLAGS = -Wl,-Map=main.map,--cref,--gc-sections -L . -L ./mbed/ -lmbed -lcapi -lc -lm -lgcc -lstdc++ -T$(LSCRIPT)

Change main.cpp to this mbed example : 

#define __NEWLIB__
#include "LPC17xx.h"

#define TARGET_LPC1768
#include "mbed/mbed.h"

DigitalOut myled(LED1);

int main() {
    while(1) {
        myled = 1;
        wait(0.25);
        myled = 0;
        wait(0.25);
    }
}

Ok if we try to do a make clean; make , we now get tons of errors like this : 

mbed/PinNames.h:18:14: error: use of enum 'PinName' without previous declaration
mbed/PinNames.h:18:29: error: invalid type in declaration before ';' token
mbed/PinNames.h:19:6: error: using typedef-name 'PinName' after 'enum'

That's because the compiler we use does not like forward declaration of enums. Which the .h in the mbed libs do a lot. We just have to comment them all by hand. Or you can download the zip file at the end of this post if I don't forget to include it. For example in mbed/PinNames.h we comment line 18 :

typedef enum PinName PinName;

And then the compiler is happy.

And now it compiles ! If it does not try to use the zip file attached, maybe I did something else that I don't remember about.

arm-none-eabi-gcc -O2 -gdwarf-2 -mcpu=cortex-m3 -mthumb -mthumb-interwork -mlong-calls -ffunction-sections -fdata-sections -fpromote-loop-indices -Wall -Wextra -Wimplicit -Wcast-align -Wpointer-arith -Wredundant-decls -Wshadow -Wcast-qual -Wcast-align -Wnested-externs --std=gnu99  -c core_cm3.c -o core_cm3.o
arm-none-eabi-gcc -O2 -gdwarf-2 -mcpu=cortex-m3 -mthumb -mthumb-interwork -mlong-calls -ffunction-sections -fdata-sections -fpromote-loop-indices -Wall -Wextra -Wimplicit -Wcast-align -Wpointer-arith -Wredundant-decls -Wshadow -Wcast-qual -Wcast-align -Wnested-externs --std=gnu99  -c delay.c -o delay.o
arm-none-eabi-gcc -O2 -gdwarf-2 -mcpu=cortex-m3 -mthumb -mthumb-interwork -mlong-calls -ffunction-sections -fdata-sections -fpromote-loop-indices -Wall -Wextra -Wimplicit -Wcast-align -Wpointer-arith -Wredundant-decls -Wshadow -Wcast-qual -Wcast-align -Wnested-externs --std=gnu99  -c startup_LPC17xx.c -o startup_LPC17xx.o
arm-none-eabi-gcc -O2 -gdwarf-2 -mcpu=cortex-m3 -mthumb -mthumb-interwork -mlong-calls -ffunction-sections -fdata-sections -fpromote-loop-indices -Wall -Wextra -Wimplicit -Wcast-align -Wpointer-arith -Wredundant-decls -Wshadow -Wcast-qual -Wcast-align -Wnested-externs --std=gnu99  -c syscalls.c -o syscalls.o
arm-none-eabi-gcc -O2 -gdwarf-2 -mcpu=cortex-m3 -mthumb -mthumb-interwork -mlong-calls -ffunction-sections -fdata-sections -fpromote-loop-indices -Wall -Wextra -Wimplicit -Wcast-align -Wpointer-arith -Wredundant-decls -Wshadow -Wcast-qual -Wcast-align -Wnested-externs --std=gnu99  -c system_LPC17xx.c -o system_LPC17xx.o
arm-none-eabi-gcc -O2 -gdwarf-2 -mcpu=cortex-m3 -mthumb -mthumb-interwork -mlong-calls -ffunction-sections -fdata-sections -fpromote-loop-indices -Wall -Wextra -Wimplicit -Wcast-align -Wpointer-arith -Wredundant-decls -Wshadow -Wcast-qual -Wcast-align -fno-rtti -fno-exceptions -c main.cpp -o main.o
In file included from mbed/Base.h:13:0,
                 from mbed/DigitalIn.h:12,
                 from mbed/mbed.h:22,
                 from main.cpp:5:
mbed/DirHandle.h:79:18: warning: unused parameter 'location'
In file included from mbed/Stream.h:9:0,
                 from mbed/Serial.h:12,
                 from mbed/mbed.h:34,
                 from main.cpp:5:
mbed/FileLike.h: In constructor 'mbed::FileLike::FileLike(const char*)':
mbed/FileLike.h:27:32: warning: declaration of 'name' shadows a member of 'this'
In file included from mbed/LocalFileSystem.h:9:0,
                 from mbed/mbed.h:49,
                 from main.cpp:5:
mbed/FileSystemLike.h: In constructor 'mbed::FileSystemLike::FileSystemLike(const char*)':
mbed/FileSystemLike.h:42:38: warning: declaration of 'name' shadows a member of 'this'
mbed/FileSystemLike.h: At global scope:
mbed/FileSystemLike.h:62:17: warning: unused parameter 'filename'
mbed/FileSystemLike.h:72:17: warning: unused parameter 'oldname'
mbed/FileSystemLike.h:72:17: warning: unused parameter 'newname'
mbed/FileSystemLike.h: In member function 'virtual mbed::DirHandle* mbed::FileSystemLike::opendir(const char*)':
mbed/FileSystemLike.h:83:50: warning: declaration of 'name' shadows a member of 'this'
mbed/FileSystemLike.h: At global scope:
mbed/FileSystemLike.h:83:24: warning: unused parameter 'name'
mbed/FileSystemLike.h: In member function 'virtual int mbed::FileSystemLike::mkdir(const char*, mode_t)':
mbed/FileSystemLike.h:93:54: warning: declaration of 'name' shadows a member of 'this'
mbed/FileSystemLike.h: At global scope:
mbed/FileSystemLike.h:93:17: warning: unused parameter 'name'
mbed/FileSystemLike.h:93:17: warning: unused parameter 'mode'
arm-none-eabi-gcc -O2 -gdwarf-2 -mcpu=cortex-m3 -mthumb -mthumb-interwork -mlong-calls -ffunction-sections -fdata-sections -fpromote-loop-indices -Wall -Wextra -Wimplicit -Wcast-align -Wpointer-arith -Wredundant-decls -Wshadow -Wcast-qual -Wcast-align -fno-rtti -fno-exceptions -c mini_cpp.cpp -o mini_cpp.o
arm-none-eabi-g++ -mthumb -O2 -gdwarf-2 -mcpu=cortex-m3 -mthumb -mthumb-interwork -mlong-calls -ffunction-sections -fdata-sections -fpromote-loop-indices -Wall -Wextra -Wimplicit -Wcast-align -Wpointer-arith -Wredundant-decls -Wshadow -Wcast-qual -Wcast-align  core_cm3.o delay.o startup_LPC17xx.o syscalls.o system_LPC17xx.o  main.o mini_cpp.o --output main.elf -Wl,-Map=main.map,--cref,--gc-sections -L . -L ./mbed/ -lmbed -lcapi -lc -lm -lgcc -lstdc++ -TLPC17xx.ld
/home/arthur/data/Sandbox/Sourcery/bin/../lib/gcc/arm-none-eabi/4.5.2/../../../../arm-none-eabi/bin/ld: warning: ./mbed//libmbed.a(DigitalOut.LPC1768.o) uses 2-byte wchar_t yet the output is to use 4-byte wchar_t; use of wchar_t values across objects may fail
/home/arthur/data/Sandbox/Sourcery/bin/../lib/gcc/arm-none-eabi/4.5.2/../../../../arm-none-eabi/bin/ld: warning: ./mbed//libmbed.a(Base.LPC1768.o) uses 2-byte wchar_t yet the output is to use 4-byte wchar_t; use of wchar_t values across objects may fail
/home/arthur/data/Sandbox/Sourcery/bin/../lib/gcc/arm-none-eabi/4.5.2/../../../../arm-none-eabi/bin/ld: warning: ./mbed//libmbed.a(stdio.LPC1768.o) uses 2-byte wchar_t yet the output is to use 4-byte wchar_t; use of wchar_t values across objects may fail
/home/arthur/data/Sandbox/Sourcery/bin/../lib/gcc/arm-none-eabi/4.5.2/../../../../arm-none-eabi/bin/ld: warning: ./mbed//libcapi.a(serial_api.LPC1768.o) uses 2-byte wchar_t yet the output is to use 4-byte wchar_t; use of wchar_t values across objects may fail
/home/arthur/data/Sandbox/Sourcery/bin/../lib/gcc/arm-none-eabi/4.5.2/../../../../arm-none-eabi/bin/ld: warning: ./mbed//libcapi.a(exit.LPC1768.o) uses 2-byte wchar_t yet the output is to use 4-byte wchar_t; use of wchar_t values across objects may fail
/home/arthur/data/Sandbox/Sourcery/bin/../lib/gcc/arm-none-eabi/4.5.2/../../../../arm-none-eabi/bin/ld: warning: ./mbed//libcapi.a(pinmap.LPC1768.o) uses 2-byte wchar_t yet the output is to use 4-byte wchar_t; use of wchar_t values across objects may fail
/home/arthur/data/Sandbox/Sourcery/bin/../lib/gcc/arm-none-eabi/4.5.2/../../../../arm-none-eabi/bin/ld: warning: ./mbed//libcapi.a(wait_api.LPC1768.o) uses 2-byte wchar_t yet the output is to use 4-byte wchar_t; use of wchar_t values across objects may fail
/home/arthur/data/Sandbox/Sourcery/bin/../lib/gcc/arm-none-eabi/4.5.2/../../../../arm-none-eabi/bin/ld: warning: ./mbed//libcapi.a(gpio_api.LPC1768.o) uses 2-byte wchar_t yet the output is to use 4-byte wchar_t; use of wchar_t values across objects may fail
/home/arthur/data/Sandbox/Sourcery/bin/../lib/gcc/arm-none-eabi/4.5.2/../../../../arm-none-eabi/bin/ld: warning: ./mbed//libcapi.a(semihost_api.LPC1768.o) uses 2-byte wchar_t yet the output is to use 4-byte wchar_t; use of wchar_t values across objects may fail
/home/arthur/data/Sandbox/Sourcery/bin/../lib/gcc/arm-none-eabi/4.5.2/../../../../arm-none-eabi/bin/ld: warning: ./mbed//libcapi.a(us_ticker_api.LPC1768.o) uses 2-byte wchar_t yet the output is to use 4-byte wchar_t; use of wchar_t values across objects may fail
/home/arthur/data/Sandbox/Sourcery/bin/../lib/gcc/arm-none-eabi/4.5.2/../../../../arm-none-eabi/bin/ld: warning: ./mbed//libcapi.a(utils_api.LPC1768.o) uses 2-byte wchar_t yet the output is to use 4-byte wchar_t; use of wchar_t values across objects may fail
/home/arthur/data/Sandbox/Sourcery/bin/../lib/gcc/arm-none-eabi/4.5.2/../../../../arm-none-eabi/bin/ld: warning: ./mbed//libcapi.a(timer_api.LPC1768.o) uses 2-byte wchar_t yet the output is to use 4-byte wchar_t; use of wchar_t values across objects may fail
arm-none-eabi-size main.elf
   text	   data	    bss	    dec	    hex	filename
  84518	   1452	   2172	  88142	  1584e	main.elf
arm-none-eabi-objcopy -R .stack -O ihex main.elf main.hex
arm-none-eabi-objcopy -O binary -j .text -j .data main.elf main.bin

Win !

So far, it's very nice. We have our bin file, everything compiles ok.

Fail

Except : if we transfer the bin file to the mbed, the code does not run, the led does not blink ! Sad :(

A new hope

This really looks like we are super very close to have it working. It just needs a little something, but I can't find what. Anyone has any idea ?

But ! I also have a LXPxpresso LPC1769 board. And when I upload the .elf file to the board : Magic ! It works The LED blinks and all !

So we have offline compiling of mbed code with the mbed libraries, that does not work on the mbed itself, but works on the LXPxpresso board.

Anyone has ideas about what would cause this ?

Really sounds like it's just one line to change somewhere, please mbed gurus, help !

The zip file with the working project : /media/uploads/arthurwolf/mbed.zip

Edit :

The « uses 2-byte wchar_t yet the output is to use 4-byte wchar_t; use of wchar_t values across objects may fail » warnings can be removed by adding

-Wl,--no-wchar-size-warning

to LD_FLAGS in Makefile

28 May 2011

Nice I'd love an ofline compiler

30 May 2011

Hello !

Made some progress ! Not on having the mBed libs themselves working on the mBed board, that still does not work.

But on binary size. On this page, which is the inspiration for this, it is said that " The entirety of the libraries are being linked in blindly. ". Investigating this further, you actually get the big ( >80k ) program size even without linking the libmbed, but simply if you use any part of libstdc++, like the new operator. That is because the exception handling code is included in the final program. There is a compiler option to avoid that : -fno-exceptions , the makefile uses it, but unfortunately, at least with Code Sourcery's toolchain, that does not work, and the exception code ( including/requiring the big printf ) gets included into your program whatever you do.

Fortunately, this has already been reported to them, and even if they did not fix it ( no "paying" client asked for it ), somebody else did.

So these are libstdc++ and libsupc++, but without the exception handling code. Just replace the .a files in your codesourcery install, and voila !

arm-none-eabi-size main.elf
   text	   data	    bss	    dec	    hex	filename
  30218	   1444	    104	  31766	   7c16	main.elf

( instead of 84518 previously ).

Ok that's one good thing done, now can somebody please make this work on the mBed ? ( at the moment, works only with lxpxpresso, and even on lxpxpresso, gives problems when doing more than blinking ( eg. write ) ).

Thanks a lot ! :)

13 Jun 2011

Wow you made pretty awesome progress. You have inspired me to look a bit more into this as well so I tried picking up the baton this weekend and continuing the work you started here.

While I don't have things like printf() or file I/O working, I did get the basic HelloWorld LED blinking application to build and run on the mbed.

Deviations that I know I made from your solution:

  1. The biggest change that I made was to try and get things building where the bulk of the code comes from mbed.ar and capi.ar rather than the base cortex-m3 project to which you hyperlinked above. This means that I only ended up keeping a bit of code from startup_LPC17xx.c to initialize the device RAM and jump to the application's main() function. This portion I placed in rvshim.c and named it __main() to make it compatible with what the Reset_Handler() in capi.ar expects it to be. I also kept syscalls.c which we will probably need to revisit to get some more of the mbed library up and running.
  2. One of the big things that using the mbed libraries gets you over using the ones in your base project, is its SystemInit() function. This sets up the clocks and enables the peripherals. I suspect that this is part of the reason that your version of the code runs on the LPCExpresso board and not the mbed. I did try just changing that over in your project but still no blinking LED so it wasn't the only cause of problems.
  3. I didn't perform the rename of the capi.ar and mbed.ar since I just added them to the link stage like any other object file rather than treating them like libs.
  4. The only thing I remember modifying in the .ld file was to KEEP(*(RESET)) instead of KEEP(*(.isr_vector .isr_vector.*)) since the vector and Reset_Handler are found in this section of capi.ar
  5. I did a bunch of tweaks in the makefile to make it closer to what I got working through simple batch files originally. I did add a step which creates disassembler output for the .ELF file so that I can use it to debug what is causing problems. I bumped the optimization level up to 3, just for the fun of it :) I built the C/C++ files under GCC with 2-byte wchar_t to more closely match RealView and disabled the warning from the linker about this descrepancy from its standard. This could cause problems with the CRT.
  6. My HelloWorld.cpp is taken directly from the online compiler. This means that it doesn't have some of the includes/defines that yours had at the top of the file. I added the #define TARGET_LPC1768 to be specified from the makefile so that you don't need to add it to each source file.
  7. I too had to make modification to the mbed headers to get them to compile with no errors/warnings. Instead of commenting out the forward declaration of typedef enums, I just moved them to after the declaration of the enums where they should have been placed by the original programmer. I also modified the code to get rid of all warnings. This included renaming some method parameters to not collide with member names and fake usage of unused parameters.

I have attached an archive of my version of the HelloWorld project: /media/uploads/AdamGreen/mbed.zip

14 Jun 2011

Adam Green wrote:

Wow you made pretty awesome progress. You have inspired me to look a bit more into this as well so I tried picking up the baton this weekend and continuing the work you started here.

Great ! It's exactly what this was intended for :) You obviously know a lot more about this stuff than I do, I got there mostly by chance.

I can't test your code right now, but your makefile seems simpler and more compact that the one I ended up with, so that's very good.

Do you have Serial or Timers working ? ( they have calls to printf and I/0, so here they failed because of that ) I'm guessing they are the next thing to get working now.

Adam Green wrote:

  1. The biggest change that I made was to try and get things building where the bulk of the code comes from mbed.ar and capi.ar rather than the base cortex-m3 project to which you hyperlinked above.

I ended up understanding this needs to be done too, but with no idea as how to do it..

Adam Green wrote:

  1. One of the big things that using the mbed libraries gets you over using the ones in your base project, is its SystemInit() function. This sets up the clocks and enables the peripherals. I suspect that this is part of the reason that your version of the code runs on the LPCExpresso board and not the mbed. I did try just changing that over in your project but still no blinking LED so it wasn't the only cause of problems.

Yes, the LPCXpresso uses LPC1769 while mBed uses LPC1768, so any difference can make it fail ...

Adam Green wrote:

  1. I didn't perform the rename of the capi.ar and mbed.ar since I just added them to the link stage like any other object file rather than treating them like libs.

Got that from the previous work. Did not understand it.

Adam Green wrote:

  1. I did a bunch of tweaks in the makefile to make it closer to what I got working through simple batch files originally. I did add a step which creates disassembler output for the .ELF file so that I can use it to debug what is causing problems.

Wow if you can do that you can probably get it all working, I can't wait !

Adam Green wrote:

  1. My HelloWorld.cpp is taken directly from the online compiler. This means that it doesn't have some of the includes/defines that yours had at the top of the file. I added the #define TARGET_LPC1768 to be specified from the makefile so that you don't need to add it to each source file.

Good, that means you are closer to what the online compiler does.

Please keep this up !

While the forum thread it not very crowded, I'm sure this will be of use to a lot of people.

Thanks a lot for the awesome progress !

Edit : Ok, could not wait :)

This code :

#include "mbed.h"

Ticker flipper;
DigitalOut led1(LED1);
DigitalOut led2(LED2);

void flip() {
    led2 = !led2;
}

int main() {
    led2 = 1;
    flipper.attach(&flip, 5.0); // the address of the function to be attached (flip) and the interval (2 seconds)

    // spin in a main loop. flipper will interrupt it to call flip
    while(1) {
        led1 = !led1;
        wait(0.1);
    }
}

Makes led1 blink for 5 seconds, then when the Ticker is supposed to happen, the board freezes. It means it does not work, but the fact it freezes after 5 seconds means it works then bugs ... that's already progress !

Could you contact me at wolf.arthur@gmail.com ?

15 Jun 2011

I have made a bit of progress with getting basic C standard I/O to send/receive text via the USB serial connection.

The following piece of code now works as I expect it.

int main() 
{
    int Value = -1;

    printf("\r\n\r\nGCC4MBED Test Suite\r\n");
    printf("Standard I/O Unit Tests\r\n");
    
    printf("Test 1: printf() test\r\n");
    
    printf("Test 2: scanf() test\r\n");
    printf("    Type number and press Enter: ");
    scanf("%d", &Value);
    printf("\n    Your value was: %d\r\n", Value);
    
    fprintf(stdout, "Test 3: fprintf(stdout, ...) test\r\n");
    
    fprintf(stderr, "Test 4: fprintf(stderr, ...) test\r\n");

    printf("Test 5: fscanf(stdin, ...) test\r\n");
    printf("    Type number and press Enter: ");
    fscanf(stdin, "%d", &Value);
    printf("\n    Your value was: %d\r\n", Value);
    
    printf("Test complete\r\n");
    
    for(;;)
    {
    }
}

Summary of changes:

commit e302e1ae2ec5da4f56b5eba2f1ff1b45101221ac
Author: Adam Green
Date:   Tue Jun 14 18:22:12 2011 -0700

    Got basic stdin/stdout/stderr support implemented
    
    Implemented enough file related syscalls to thunk through to mbed.ar _sys_*() functions that things like printf() and
    scanf() now work.  This also included adding code to the __main() startup code to issue open calls for stdin, stdout,
    and stderr.  This gives the mbed code an opportunity to initialize the serial port connection.

commit 337a0246f10a540d7e3ea7289eb07f8f45ce9ed1
Author: Adam Green
Date:   Tue Jun 14 17:10:07 2011 -0700

    Moved mbed shim code into its own gcc4mbed directory
    
    Modified HelloWorld project to pull the shim code from this new directory so each project doesn't have to use its own
    copy.

I will take a quick look at the timer issue you pointed to above to see if there is anything obvious to change for making it work. Nothing jumps to mind. After that I want to finish up the file related syscalls and then maybe LocalFileSystem will start to work as well.

/media/uploads/AdamGreen/gcc4mbed.zip

15 Jun 2011

Nice work ! I have followed your instructions and it is working. I have also test the Keil Appnote to use the Keil Compiler to compile offline and it also works with small projects and the Keil test version.

There is a big difference in code size. The Keil code is 9524 byte compared to the 67381 byte from the GNU. I use the gcc4mbed project. It looks the GNU linker is not striping the unused libc functions...

Peter

15 Jun 2011

You can get instructions to get the code size lower upper in this thread ( here ). But even with that it looks like the code size is still high.

The ticker example gives me a 90794 size here ... which is very much compared to the online compiler.

15 Jun 2011

Yes, I too have noticed that the resulting binaries are quite large. I have been concentrating on taking Arthur's great work and getting it to work with more of the mbed library. I have been completely ignoring the size issue. I haven't even picked up the CRT (pointed to by Arthur above) with exception support removed. Once I am happier with the functionality, I will take a look at the size to see if I can get that reined in. I am currently optimizing the compilation under GCC for speed and not size so this could save some size as well but in the past I have found the ARM binary output from GCC to be pretty bad when you optimize for size.

By the way, I did update the gcc4mbed.zip on this site last night to fix the Ticker issue that Arthur pointed out yesterday (thanks for testing it out and raising this issue!). Related commit notes:

commit 59136549ca27008178b1f00b2235c5054bc0cc35
Author: Adam Green
Date:   Tue Jun 14 23:24:56 2011 -0700
    Modified link map to fix interrupt vector location
    
    Previously the interrupt vector was being placed at an arbitrary address by the linker when the mbed code was
    expecting it at a fixed location of 0x10000000.  This was leading to a crash when Ticker interrupts (or any other
    interrupt) fired.  I suspect that there will be a few other issues like this to track down.
    
    I also modified the startup code to open stdin/stdout/stderr before running through the global constructors incase such
    a constructor wants to call printf(), etc.
    
    Added a utility library to help in debugging and testing this port.  Currently I just have a DebugDumpMemory()
    function which can dump a buffer to stdout.  I used this to track down the interrupt vector issue that was causing a
    hang on Ticker interrupts.

Today I am going to try and finish plumbing the syscalls through to the mbed library.

15 Jun 2011

Great !

I can't wait to see what you will get working next !

16 Jun 2011

Hi!,

Great work with the offline compiling, and thanks a lot for documenting the steps!

I'm currently trying to link mbedlib to the older version of mbed (LPC2368) with gcc. But having some broblems.

I have managed to set up an working codesourcery's toolchain, found working linkscript and created an simple program that lights mbed leds without the use of mbedlib. Also your example /media/uploads/arthurwolf/mbed.zip compiles and links. But i couldn't test it because I don't have the lpc_17xx version of mbed.

When I try to link with LPC2368 vesion of the mbedlib. I'm getting following error:

Quote:

/usr/local/bin/../lib/gcc/arm-none-eabi/4.5.2/../../../../arm-none-eabi/bin/ld: error: ./mbedlibmbed.a(Base.LPC2368.o): Object has vendor-specific contents that must be processed by the 'ARM' toolchain

Looks to me like the mbedlib binaries have some parts that the gcc could not understand.

Does anybody know what it means?

-Frans

17 Jun 2011

Frans Korhonen wrote:

Looks to me like the mbedlib binaries have some parts that the gcc could not understand.

Does anybody know what it means?

I can try and take a look at the 2368 version later but for right now I am concentrating on the 1768 version. The biggest issue is that I only have a 1768 version of the mbed so I will just be able to look at getting the build issues for the 2368 version fixed. I won't be able to actually try running the code and work on thunking the CRT through for that device. Maybe someone else can pick up that part if we can get it to at least build.

18 Jun 2011

I have finished the first version of the newlib syscall thunks to mbed.ar With these changes, I have been able to use the LocalFileSystem class as well.

A few more details about this latest version:

commit bcee398010a19a96f094c50b2f18e138f309ef5a
Author: Adam Green
Date:   Fri Jun 17 18:24:21 2011 -0700

    Finished first version of syscall thunks to mbed.ar
    
    Updates to syscall thunks include:
        _open:   I was masking off the flag bits incorrectly.  I must learn how to write C code :)
        _close:  Now passes the call through to _sys_call
        _isatty: I have hardcoded stdin/stdout/stderr to return 1 and otherwise pass through the request to _sys_istty().
                 I did this hardcoding since mbed.ar will return 0 for these handles which isn't what I would expect and
                 results in weird behaviour.
        _write:  Remove some of the older debug code that I had in here to flash the LED on write requests.
        _fstat:  Added a basic version as found in the newlib documentation.
        _system: Just returns the appropriate error to indicate that the device has no command interpreter.
        _lseek:  I don't know how to describe my change here.  It is some of the hackiest code I have ever written.  mbed.ar
                 only provides _sys_seek() for seeking within a file and this function can only seek from the beginning of
                 the file and doesn't support SEEK_CUR or SEEK_END.  The actual FileHandle objects in the mbed library
                 provide a lseek() method which can perform all three seek directions.  My version of _lseek actually
                 decodes the machine code of _sys_seek to find the literal which contains the pointer of the file handle
                 table used internally by the mbed library.  The code then looks up the appropriate FileHandle object in
                 this table and calls its lseek() method.
    
    System calls called out as overrideable in newlib documentation which weren't implemented follow in this list
    with my current reasoning:
    environ         Not required.  getenv() and setenv() can be used without providing an override as there is a default
    _execve         Standard C APIs implemented by newlib don't end up calling this function.  Implemented _system
                    instead.
    _fork           Standard C APIs implemented by newlib don't end up calling this function.  Implemented _system
                    instead.
    _link           This is a POSIX routine and while newlib will call it for the standard C rename() function, this
                    particular routine is overridden in mbed.ar where it just returns -1.
    _stat           This is a system API and not part of the C standard.  It doesn't appear to be required for mbed.
    _times          Appears to be a system API and not part of the C standard.  Not called from standard APIs.
    _unlink         This is a POSIX routine.  newlib will call it for standard C remove(), this particular API is
                    already overidden by mbed.ar
    
    Added a DebugDumpStack() to agutil.ar which can be used to dump the current contents of the stack.  I used it to
    manually decode a call stack so that I could figure out what path I went through in newlib to make it to unexpected
    places in the syscall thunks.  Also added code to DebugDumpMemory() which verifies that the supplied buffer is aligned
    correctly for the ElementSize and added some extra casting to silence warnings in GCC about potential alignment issues.
    Alignment and element size errors in DebugDumpMemory() now exit the application by calling mbed's error() function.
    
    Added a PROVIDE in the mbed.ld script to give the __ARM_grp_.debug_frame$i._ZN4mbed14FileSystemLike6renameEPKcS2_
    a value since the link stage would otherwise fail.  I need to figure out how to properly deal with these. It looks like RealView
    might expect this symbol to come from the main program and not mbed.ar  These inline virtual methods provided by base
    classes end up having code created for them by the class that use them (ie. LocalFileSystem instantiates code for
    FileSystemLike::rename but doesn't instantiate the debug_frame)
    
    Added LocalFileSystem unit test which is based on the sample code found in the mbed documentation for this class.

At this point, it appears that the mbed code mostly works when built through GCC but there will no doubt be further issues with how the linking is taking place. I am going to go off for awhile now and do some more research/thinking in this area. Until then, feel free to pick it up and try it out and let me know what does or doesn't work for you.

The latest code can be found here: /media/uploads/AdamGreen/gcc4mbed.zip

18 Aug 2011

Adam, when I try to compile the makefile project with Eclipse and Code Sourcery gcc Sourcery G++ Lite, the compiler does nothing:

Build of configuration Default for project lpc_17xx_CPP **

cs-make all cs-make: Nothing to be done for `all'.

Am I missing something?

P.s. Do you guys have any idea how to get standard C libraries to work with mbed? E.g. where to get working system call stubs, etc.

18 Aug 2011

Hi !

Does it work without Eclipse, in a shell ? Eg : 

make clean make

18 Aug 2011

I don't use Eclipse so I can't help you there. I just use a simple code editor and then run make for all of my projects.

My system call stubs can be found in the syscalls.* files under the gcc4mbed directory in the .zip archive from my previous post. These thunk through to syscalls in the mbed library so it will need to be linked in as well. Someone might have something that make things work on the LPC1768 without mbed.ar and instead uses the CMSIS APIs for things like redirecting stdin/stdout/stderr through the UART.

18 Aug 2011

It compiled from console. Strange. Probably an unwanted feature of Eclipse. Printf seems to work. But how... Argh. Frustrating.

18 Aug 2011

I think I'll go with this. Got my project to build on this. Thanks a ton, guys! The size of the binary is indeed huge, but I can live with that.

01 Sep 2011

Hi guys, that's really great work you did.

many thanks for it.

I got it working on a *nix box with eclipse. If somebody is interested have a look at

http://mbed.org/users/jgnoss/notebook/mbed-offline-on-nix-with-gnueclipse/

Ju

16 Sep 2011

Now that Arthur is making more use of the libraries and a few other people have picked up the project, I figured I should probably provide an update with my recent changes.

Juho Lepisto wrote:

The size of the binary is indeed huge, but I can live with that.

One of the main changes in the updated [/media/uploads/AdamGreen/gcc4mbed.zip] archive is a modification to include size optimized newlib and C++ libraries. They are still not as small as what the cloud compiler generates (the gcc4mbed samples tend to be 2x larger when built with GCC) but they are much smaller than what you would have obtained with the previous versions of the libraries. I used a lot of the tricks that I found in Hugo Vincent's https://github.com/hugovincent/arm-eabi-toolchain project to aid in this size reduction.

An example size reduction for the HelloWorld sample:

       text	   data	    bss	    dec	    hex	filename
     118653	   1500	   2500	 122653	  1df1d	HelloWorld.elf BEFORE
      21816	   1376	    104	  23296	   5b00	HelloWorld.elf AFTER

The following commit comments give a brief overview of what has changed since the last update:

commit fac404926448c50689ee351ff59f94fc8034aa4a
Author: Adam Green
Date:   Wed Jun 29 22:43:41 2011 -0700

    Initial check-in of changes to make mbed binaries smaller
    
    I made modifications to HelloWorld and StdIO samples to make them smaller.
    These changes include:
        - Switching to -O2 instead of -O3.
        - Removed -mlong-calls from compiler line.
        - Forced linker to use smaller versions of the standard C and C++
          libraries.
    
    Delayed the opening of stdin,stdout, and stderr until an I/O is actually
    performed on one of these handles.  This saves a lot of code space for
    samples such as HelloWorld which don't even do any standard I/O.
    A call to _sys_open() in the mbed.ar library causes sscanf() and fprintf() to
    be pulled in so it is best to make sure that you really need to open a file
    before doing so.
    
    Added another missing mbed.ar symbol to mbed.ld that showed up during this
    work.  I set the two I know about so far to 0xBAADF00D so that I could
    search the resulting binaries for these values to make sure that they weren't
    going to be used erroneously.
    
    Added initial versions of smaller standard C and C++ libraries.  I created the
    C newlib libraries on my machine and the C++ libraries are from 2009 and have
    exceptions turned off.  I plan to create a complete set of these libraries now
    that I can build the whole Code Sourcery tool chain on my own machine so
    they are small and all match the tool chain.  These will come in a future
    commit.


commit 55461e1f22673bc6fef37792a01306d12d58968f
Author: Adam Green
Date:   Sat Sep 10 21:02:18 2011 -0700

    Enable RTTI in the makefiles
    
    The makefile on which this project is based, had RTTI disabled but it turns
    out that the mbed libraries use this information which lead to a crash when
    it attempted to perform a <dynamic_cast> on a class which was compiled by
    the GCC compiler.
    
    Also adding a SDFileSystem sample based on some code that Arthur Wolf sent me
    earlier in the week.  This required pulling in the FATFileSystem library from
    mbed as well.  One issue with the FATFileSystem headers is that they defined
    mode_t to be of type int when they built the libraries but GCC associates
    the unsigned int type with mode_t so the method names mismatch due to name
    mangling.  I just removed the use of the mode_t type from the headers and used
    int instead so that GCC would use the same name mangling as was used by mbed.
    
    Renamed LPC1768.sct to LPC1768.scatter so that I could send a ZIP archive of
    the project to gmail users.  Without this change, the ZIP would be rejected
    since it thought that this file might be a script.


commit 3aa8d5cd41f67f17ad98cc206771e3ec7c1b9391
Author: Adam Green
Date:   Sun Sep 11 14:13:58 2011 -0700

    Default .c files to be compiled as C++ like online compiler and place common makefile 
    steps in gcc4mbed/build/gcc4mbed.mk
    
    I got tired of making changes to every sample makefile when I found a problem
    or wanted to add more functionality to the makefile.  Therefore, I pulled out
    the common parts of the makefile and now I only need to configure a few
    variables before including this common makefile.
    
    Example makefile:
    PROJECT=SampleProject
    SRC=src
    GCC4MBED_DIR=gcc4mbed
    INCDIRS=src/SDFileSystem
    LIBS_PREFIX=
    LIBS_SUFFIX=
    
    include gcc4mbed/build/gcc4mbed.mk
    
    Note on what the variables mean (can also be found in gcc4mbed.mk):
    USAGE:
    Variables that must be defined in including makefile.
      PROJECT: Name to be given to the output binary for this project.
      SRC: The root directory for the sources of your project.
      GCC4MED_DIR: The root directory for where the gcc4mbed sources are located
                   in your project.  This should point to the parent directory
                   of the build directory which contains this gcc4mbed.mk file.
      LIBS_PREFIX: List of library/object files to prepend to mbed.ar capi.ar libs.
      LIBS_SUFFIX: List of library/object files to append to mbed.ar capi.ar libs.


commit 6746b919907d1fdff64a80986b284adf13b529d5
Author: Adam Green
Date:   Wed Sep 14 00:03:52 2011 -0700

    Adding size optimized C/C++ libraries to gcc4mbed project.
    
    I have built newlib and C++ libraries that have had various flags enabled within the CodeSourcery build script
    to help reduce the size of the resulting binaries.  I used a lot of the tricks that I found in Hugo Vincent's
    https://github.com/hugovincent/arm-eabi-toolchain github project to aid in this size reduction.  The common
    makefile for the gcc4mbed project has been modified to place these size optimized versions of the libraries
    earlier in the search order than the defaults that come with the Code Sourcery toolchain.
    
    This is a list of sizes for the samples from before this change:
       text	   data	    bss	    dec	    hex	filename
     118653	   1500	   2500	 122653	  1df1d	HelloWorld.elf
     123219	   1496	   2476	 127191	  1f0d7	StdIO.elf
     121090	   1700	   2572	 125362	  1e9b2	Ticker.elf
     127305	   1500	   2496	 131301	  200e5	LocalFileSystem.elf
     142804	   1716	   3416	 147936	  241e0	SDFileSystem.elf
     118653	   1500	   2500	 122653	  1df1d	CTest.elf
    
    This is the list of sizes for the samples after this change:
       text	   data	    bss	    dec	    hex	filename
      21816	   1376	    104	  23296	   5b00	HelloWorld.elf
      52247	   1456	    404	  54107	   d35b	StdIO.elf
      64794	   1664	    520	  66978	  105a2	Ticker.elf
      55877	   1460	    424	  57761	   e1a1	LocalFileSystem.elf
      84776	   1680	   1364	  87820	  1570c	SDFileSystem.elf
      21816	   1376	    104	  23296	   5b00	CTest.elf
    
    These results are still about 2x the size of what the cloud compiler generates but that is probably as good as I can
    get it.


commit 688abeb5d39bce8d43fa6768b21a06bd749103ac
Author: Adam Green
Date:   Thu Sep 15 16:49:20 2011 -0700

    Checking in my basic prep.sh script which builds the CodeSourcery tool chain on my Mac.
    
    This script downloads the 2011.03-42 version of the CodeSourcery/Mentor Graphics tool chain, extracts the
    necessary sources, and then modifies the build script so that it works on my Mac and builds smaller C++ and
    newlib libraries for using with the gcc4mbed project.
21 Sep 2011

This will probably be the last update of the gcc4mbed.zip now that the gcc4med project is available on github. This forum post discusses the github release.

The latest version, /media/uploads/AdamGreen/gcc4mbed.zip, includes these updates:

commit bf8b5f7836a3e2392a8e579ae053cfeaabdedc9d
Author: Adam Green 
Date:   Sun Sep 18 14:23:37 2011 -0700

    Updated external/makefile to work on Windows.
    
    Can now install and patch the mbed libraries from a Windows machine as well.
    This did require adding some binaries for svn and patch to the repository so
    that Windows users wouldn't have to download these files just to get the mbed
    libraries.  The external/win32/readme.txt file indicates from where on the
    Internet each of the binaries was downloaded.

commit 40bd154ea7294a151d17f59b7ac177079d0a2cd4
Author: Adam Green 
Date:   Sun Sep 18 01:59:20 2011 -0700

    Added external/makefile which can download and patch mbed libs.
    
    With this makefile in place, it is no longer necessary for the mbed headers and libraries to be part of the
    gcc4mbed repository.  Instead the developer can just go into the external directory and run make to have revision 28
    of the libraries pulled down and patched so that they will work with GCC.

commit 41302f36be99b84c0eba0796c4eb286650afe3db
Author: Adam Green 
Date:   Sat Sep 17 23:50:07 2011 -0700

    Support placing data in AHBSRAM0 and AHBSRAM1 sections.
    
    Now able to run some lwIP samples where the buffers are placed in AHBSRAM1 bank.
    
    It should be noted that the data in these sections is left unitialized but I think this matches the cloud compiler
    behaviour.
    
    I also modifed the process used to set the INCLUDE path since lwIP required that some paths be in the INCLUDE
    path which didn't themselves have any headers in them but their subfolders did.  The #include specified one of
    these subfolder names.  The code now includes any directory which contains any files or subdirectories which
    matches even more closely with what the cloud compiler does based on what I saw with the lwIP sample.

commit 33a3797d140c365d7860584f9ee488e50edb9000
Author: Adam Green 
Date:   Fri Sep 16 23:24:30 2011 -0700

    Implemented a INCLUDE search path similar to that used by the mbed cloud compiler.
    
    The makefile now searches the subdirectories of the project (down to 4 levels deep) for .h files.  It thens adds the
    directories for these .h files to the include path after sorting them.  This means that the root project directory
    will come before its subfolders and headers within its subfolders are searched in alphabetical order of their
    containing subfolder.  This appears to match what I see with the cloud compiler.  It also searches these project
    header folders before it searches in the mbed library folders.

commit 2e2d36519ec0aed94e4d8ff30e41a76c3322f2b1
Author: Adam Green 
Date:   Fri Sep 16 22:24:05 2011 -0700

    Add deploy rule which can copy resulting binary of build to device.
    
    Since different environments will require different commands for deploying binaries to the LPC17xx device, the user
    has to set the LPC_DEPLOY to an appropriate value indicating the command which should be run for the deploy rule.
    Examples:
        export LPC_DEPLOY='lpc21isp PROJECT.hex /dev/ttyUSB0 115200 14746'
        export LPC_DEPLOY='cp PROJECT.bin /Volumes/MBED/'
    
    The first example will deploy a resulting HEX file to the raw LPC17xx device via serial port and the second example
    will just copy the file to the MBED mass storage device.  It should be noted that the word PROJECT will be replaced
    with the name of the project currently being built before the deploy command is executed.
    
    To build a project and then deploy it, the user would only need run the following make command:
        make all deploy

commit 3408e21bcd4b6f6ec259e3b29d3f0d5883427199
Author: Adam Green 
Date:   Fri Sep 16 17:59:34 2011 -0700

    Moved __main() and SystemInit() down into the unused space before the CRP word.
    
    These functions are required by every executable that gets built with gcc4mbed and therefore makes use of the 700+
    bytes of unused space that I introduced into the beginning of the binary with the CRP reservation change.
    
    There are still almost 200 bytes still unused in this space.  If you had a function which you knew would fit into
    this space, you could mark it with the following attribute to have the linker use up this free space:
    __attribute__ ((section(".mbed_init")))
    
    If you try to put a function which is too large in this space, you will get a linker error indicating that it tried
    to move the counter backwards.

commit b9964761f2473205f16175ad63451086392f2a91
Author: Adam Green 
Date:   Fri Sep 16 17:32:32 2011 -0700

    Modified makefiles so that they work with either cs-make/cs-rm or make/rm
    
    Previously the makefiles were using cs-rm for cleaning up from previous builds.  This worked well on Windows but on the
    Mac or other *nix operating systems, you would need to edit the makefiles or create links for cs-rm.  Now the
    makefiles detect whether cs-make or make was used to kick off the build and then attempts to use the version of rm
    which matches the version of make used.

commit bf4b09e55e5f194b82ea874d2d7b651ca06cdd6a
Author: Adam Green 
Date:   Fri Sep 16 17:00:53 2011 -0700

    Stripped symbols from mbed libraries.
    
    Running "arm-none-eabi-objcopy -g" on the RealView compiled libraries removed the .debug_frame symbols which ended up
    causing random unresolved hidden symbol errors at link time.  I was also able to remove the PROVIDE() clauses from
    mbed.ld since I no longer need to fake these symbols to silence linker errors.

commit de17e195d4ebaae16ca637180c15db15d1e2f6ad
Author: Adam Green 
Date:   Fri Sep 16 13:05:34 2011 -0700

    Fixed issue in .fastcode section of mbed.ld
    
    It turns out that this section in the mbed.ld script has always had a bug where it was setting the value of the
    _sidata symbol when it was supposed to be setting the _sifastcode symbol.  When I moved this section in the
    linker script so that fastcode wouldn't interfere with the RAM based copy of the interrupt vectors at 0x10000000
    it ended up being the last line to define this symbol and overwrote the correct value set by the .data section.

commit 907be99eb7e820b8c84333ad80c2fcde1796417d
Author: Adam Green 
Date:   Thu Sep 15 22:51:53 2011 -0700

    Reserving room in the output binary for the Code Read Protection (word).
    
    This does add over 512 bytes of padding to the resulting binary but it is probably best to be safe and not put
    any code in this area.  You could always add code to the RESET section to use up the space before 0x2FC in the
    FLASH.
    
    The following application note shows how to set this value given the .crp section which was added to the mbed.ld
    script: http://www.nxp.com/documents/application_note/AN10968.pdf
    
    This is an excerpt from that application note:
    __attribute__ ((section(".crp"))) const uint32_t CRP_WORD = 0xFFFFFFFF;
13 Oct 2011

The latest version seems to work great, except for some reason the serial port functions in 9600 baud regardless of configuration of UART0 baud rate registers. My software is configured to work in 115200 baud, but when I compile with the new gcc4mbed it works in 9600. Really strange feature. It worked ok on older version I used.

13 Oct 2011

Juho Lepisto wrote:

My software is configured to work in 115200 baud, but when I compile with the new gcc4mbed it works in 9600.

Sorry about that! This appears to be the same issue that Charles brought up in the other gcc4mbed thread and that I tracked in this issue on github. It should now be fixed in the latest version up on github.

29 Jan 2012

Adam,

I've been looking at Sam's USB Audio Code. This code uses a volatile boolean (or two) to toggle waiting between the interrupt layer and the program layer.

This same code behaves differently when compiled with the online compiler vs with gcc4mbed - it works fine in the online compiler but looks like the volatile declarations are ignored in gcc4mbed - so the interrupt/user signaling doesn't work.

This is with a LPC1768 target, on a mac (osx64) from a 11/15/2011 tarball (CODE_SOURCERY_MD5=b1bd1dcb1f922d815ba7fa8d0e6fcd37 MACBIN_MD5=5591077f049837249455131d463ff885)

Any leads on how to fix this in gcc4mbed - I would love to keep working offline!

Thanks, Jonathon

29 Jan 2012

I will take a look at Sam's sample over the next couple of days to see if I can figure out what might be going on when building it with gcc4mbed.

Is there a particular reason you think that it is related to volatile qualifiers? These have always worked for me with GCC in the past. Knowing what debugging you have done so far that makes you think that it is related to this qualifier might help point me in the right direction for my own debugging session.

Thanks,

Adam

29 Jan 2012

Hi Adam,

Thanks for the quick reply! Two things I found when using gcc4mbed:

First is that the 'SOF_handler' didn't seem to work correctly in USBAudio.cpp - it was always true even though a read (or write) was setting it to false. I added a "if (!SOF_handler) { log something } around the SOF_handler = true in the USBAudion::SOF routine. The user land (in USBAudio::read) sets this to false and then blocks; the interrupt sets this to true when it gets a new frame.

Second is that the USBAudio::EP3_OUT_callback doesn't get called (I think because the interrupts are either not setup, or the IntSt doesn't have EP(EP3OUT)). I think this comes down to LPC_USB->USBEpIntSt in USBBusInterface_LPC17_LPC23.cpp. I added some debugging around line #634 but never got into the "if (LPC_USB->USBEpIntSt & EP(EP3OUT)) {" section.

Most of my debugging was around logging the state of 'SOF_handler' and 'available' in USBAudio::read, USBAudio::SOF, USBAudio::EP3_OUT_callback. With gcc4mbed I would get as far as one packet in the SOF handler, but nothing from the EP3_OUT_callback. With the online compiler I get one (or two) packets via the SOF handler, and then the EP3_OUT_callbacks kick in to give me packets of data.

Hope this helps, happy to add more to get to the bottom of this. It is entirely possible that the real problem is a loose nut on the keyboard.

Thanks, Jonathon

31 Jan 2012

Adam,

Thank you of helping me with this over the last couple of days. It looks like the problem is my fault and gcc4mbed is behaving perfectly. I will see if I can fix the problem, and get back to you.

Thanks, Jonathon

31 Jan 2012

Jonathon,

If after you fix up the current issues, you still hit problems where the code works with the online compiler and not when compiled with GCC, send me a drop of the code and I will take another look.

Thanks,

Adam