Offline GCC compiler works with mbed libraries!

12 Sep 2013

I have something that works in GDB now but I will try to convert it to a C function that you can call at runtime to dump the newlib-nano heap allocations.

12 Sep 2013

I tested this C++ code which makes allocations and frees them. As it progresses, it walks the heap:

main.cpp

#include <malloc.h>
#include <mri.h>
#include <stdio.h>
#include <stdint.h>


extern "C" uint32_t  __end__;
extern "C" uint32_t  __malloc_free_list;
extern "C" uint32_t  _sbrk(int size);


void heapWalk(void)
{
    uint32_t chunkNumber = 1;
    // The __end__ linker symbol points to the beginning of the heap.
    uint32_t chunkCurr = (uint32_t)&__end__;
    // __malloc_free_list is the head pointer to newlib-nano's link list of free chunks.
    uint32_t freeCurr = __malloc_free_list;
    // Calling _sbrk() with 0 reserves no more memory but it returns the current top of heap.
    uint32_t heapEnd = _sbrk(0);
    
    printf("Heap Size: %lu\n", heapEnd - chunkCurr);
    
    // Walk through the chunks until we hit the end of the heap.
    while (chunkCurr < heapEnd)
    {
        // Assume the chunk is in use.  Will update later.
        int      isChunkFree = 0;
        // The first 32-bit word in a chunk is the size of the allocation.  newlib-nano over allocates by 8 bytes.
        // 4 bytes for this 32-bit chunk size and another 4 bytes to allow for 8 byte-alignment of returned pointer.
        uint32_t chunkSize = *(uint32_t*)chunkCurr;
        // The start of the next chunk is right after the end of this one.
        uint32_t chunkNext = chunkCurr + chunkSize;
        
        // The free list is sorted by address.
        // Check to see if we have found the next free chunk in the heap.
        if (chunkCurr == freeCurr)
        {
            // Chunk is free so flag it as such.
            isChunkFree = 1;
            // The second 32-bit word in a free chunk is a pointer to the next free chunk (again sorted by address).
            freeCurr = *(uint32_t*)(freeCurr + 4);
        }
        
        // Skip past the 32-bit size field in the chunk header.
        chunkCurr += 4;
        // 8-byte align the data pointer.
        chunkCurr = (chunkCurr + 7) & ~7;
        // newlib-nano over allocates by 8 bytes, 4 bytes for the 32-bit chunk size and another 4 bytes to allow for 8
        // byte-alignment of the returned pointer.
        chunkSize -= 8;
        printf("Chunk: %lu  Address: 0x%08lX  Size: %lu  %s\n", chunkNumber, chunkCurr, chunkSize, isChunkFree ? "CHUNK FREE" : "");
        chunkCurr = chunkNext;
        chunkNumber++;
    }
}


int main()
{
    printf("Starting at main(%08X)...\n", (unsigned int)&main);
    
    void* p1 = malloc(100);
    void* p2 = malloc(100);
    void* p3 = malloc(100);
    void* p4 = malloc(100);
    heapWalk();
    free(p2);
    heapWalk();
    free(p4);
    heapWalk();
    free(p1);
    heapWalk();
    free(p3);
    heapWalk();

    return 0;
}

This results in the following output:

Starting at main(000001FD)...
Heap Size: 1900
Chunk: 1  Address: 0x10000670  Size: 428  
Chunk: 2  Address: 0x10000820  Size: 1024  
Chunk: 3  Address: 0x10000C28  Size: 100  
Chunk: 4  Address: 0x10000C98  Size: 100  
Chunk: 5  Address: 0x10000D00  Size: 100  
Chunk: 6  Address: 0x10000D70  Size: 100  
Heap Size: 1900
Chunk: 1  Address: 0x10000670  Size: 428  
Chunk: 2  Address: 0x10000820  Size: 1024  
Chunk: 3  Address: 0x10000C28  Size: 100  
Chunk: 4  Address: 0x10000C98  Size: 100  CHUNK FREE
Chunk: 5  Address: 0x10000D00  Size: 100  
Chunk: 6  Address: 0x10000D70  Size: 100  
Heap Size: 1900
Chunk: 1  Address: 0x10000670  Size: 428  
Chunk: 2  Address: 0x10000820  Size: 1024  
Chunk: 3  Address: 0x10000C28  Size: 100  
Chunk: 4  Address: 0x10000C98  Size: 100  CHUNK FREE
Chunk: 5  Address: 0x10000D00  Size: 100  
Chunk: 6  Address: 0x10000D70  Size: 100  CHUNK FREE
Heap Size: 1900
Chunk: 1  Address: 0x10000670  Size: 428  
Chunk: 2  Address: 0x10000820  Size: 1024  
Chunk: 3  Address: 0x10000C28  Size: 208  CHUNK FREE
Chunk: 4  Address: 0x10000D00  Size: 100  
Chunk: 5  Address: 0x10000D70  Size: 100  CHUNK FREE
Heap Size: 1900
Chunk: 1  Address: 0x10000670  Size: 428  
Chunk: 2  Address: 0x10000820  Size: 1024  
Chunk: 3  Address: 0x10000C28  Size: 424  CHUNK FREE

The first two allocations of 428 and 1024 bytes are from the use of printf() to display text to stdout. That is why they are never freed. This output shows free and active chunks in the heap at each stage and also shows how the heap coalesces adjacent free chunks to produce larger free chunks. By the end, we end up with a single free chunk >400 bytes instead of 4 separate free chunks of 100 bytes.

I hope that helps,

Adam

13 Sep 2013

Adam Green wrote:

Hello Gustavo,

There are two things going on here.

  1. gcc4mbed now uses newlib-nano for the C standard library to produce smaller binaries. This version of newlib doesn't support the malloc_stats() call.
  2. You get the "multiple definition" error from the linker because of something that I did wrong in the gcc4mbed makefiles which allows a mix of newlib standard and newlib-nano to be linked in.

Unfortunately, even after I fix my makefile issue, you will still get an 'undefined reference' linker error since it won't be able to find any definitions of the required _malloc_stats_r() function once only newlib-nano is used. In the future I hope to port some of my heap tagging extensions into gcc4mbed. These allow dumping of the heap from within the GDB debugger. You can see used and free locations in the heap and even get the name of the caller who made each allocation. I have had this working in the past for newlib but I need to do some porting as newlib-nano uses a different (simpler) heap structure.

Adam,

Undefined reference to _mallopt_r is caused by a bug in nano malloc. It should be fixed in next 4.7 release. Although the malloc_stats still doesn't do anything.

Multiple definition problem is typically caused by linking both -lc and -lc_s. In theory all symbols in -lc should be included in -lc_s. So user must not specify both libs, given that the previous undefined reference bug is fixed.

- Joey

13 Sep 2013

Joey Ye wrote:

Multiple definition problem is typically caused by linking both -lc and -lc_s. In theory all symbols in -lc should be included in -lc_s. So user must not specify both libs, given that the previous undefined reference bug is fixed.

Yes, as I said, this was a bug in my makefile. I have corrected it in my working branch of gcc4mbed. Once this fix was applied, there were no longer any errors but of course malloc_stats() still does nothing but just return.

13 Sep 2013

Adam Green wrote:

main.cpp

        // Skip past the 32-bit size field in the chunk header.
        chunkCurr += 4;
        // 8-byte align the data pointer.
        chunkCurr = (chunkCurr + 7) & ~7;
        // newlib-nano over allocates by 8 bytes, 4 bytes for the 32-bit chunk size and another 4 bytes to allow for 8
        // byte-alignment of the returned pointer.
        chunkSize -= 8;

A minor problem here: it doesn't always over allocate by 8 bytes. The 4 bytes padding is optional. If chunkCurr happen to be 8 bytes aligned, it needn't pad.

So the program should be modified as:

        // Skip past the 32-bit size field in the chunk header.
        advance = chunkCurr + 4;
        // 8-byte align the data pointer.
        advance = (advance + 7) & ~7;
        chunkSize -= (advance - chunkCurr);

        chunkCurr = advance;

- Joey

13 Sep 2013

Joey Ye wrote:

A minor problem here: it doesn't always over allocate by 8 bytes. The 4 bytes padding is optional. If chunkCurr happen to be 8 bytes aligned, it needn't pad.

From what I see in the nano_malloc code, it increases the size by 8, possibly 3 more if it needs to 4-byte align the size itself:

    alloc_size = ALIGN_TO(s, CHUNK_ALIGN); /* size of aligned data load */
    alloc_size += MALLOC_PADDING; /* padding */
    alloc_size += CHUNK_OFFSET; /* size of chunk head */
    alloc_size = max(alloc_size, MALLOC_MINCHUNK);

Besides the size is just information in this heap walk code anyway.

13 Sep 2013

Adam Green wrote:

I tested this C++ code which makes allocations and frees them. As it progresses, it walks the heap:

main.cpp

#include <malloc.h>
#include <mri.h>
#include <stdio.h>
#include <stdint.h>


extern "C" uint32_t  __end__;
extern "C" uint32_t  __malloc_free_list;
extern "C" uint32_t  _sbrk(int size);


void heapWalk(void)
{
    uint32_t chunkNumber = 1;
    // The __end__ linker symbol points to the beginning of the heap.
    uint32_t chunkCurr = (uint32_t)&__end__;
    // __malloc_free_list is the head pointer to newlib-nano's link list of free chunks.
    uint32_t freeCurr = __malloc_free_list;
    // Calling _sbrk() with 0 reserves no more memory but it returns the current top of heap.
    uint32_t heapEnd = _sbrk(0);
    
    printf("Heap Size: %lu\n", heapEnd - chunkCurr);
    
    // Walk through the chunks until we hit the end of the heap.
    while (chunkCurr < heapEnd)
    {
        // Assume the chunk is in use.  Will update later.
        int      isChunkFree = 0;
        // The first 32-bit word in a chunk is the size of the allocation.  newlib-nano over allocates by 8 bytes.
        // 4 bytes for this 32-bit chunk size and another 4 bytes to allow for 8 byte-alignment of returned pointer.
        uint32_t chunkSize = *(uint32_t*)chunkCurr;
        // The start of the next chunk is right after the end of this one.
        uint32_t chunkNext = chunkCurr + chunkSize;
        
        // The free list is sorted by address.
        // Check to see if we have found the next free chunk in the heap.
        if (chunkCurr == freeCurr)
        {
            // Chunk is free so flag it as such.
            isChunkFree = 1;
            // The second 32-bit word in a free chunk is a pointer to the next free chunk (again sorted by address).
            freeCurr = *(uint32_t*)(freeCurr + 4);
        }
        
        // Skip past the 32-bit size field in the chunk header.
        chunkCurr += 4;
        // 8-byte align the data pointer.
        chunkCurr = (chunkCurr + 7) & ~7;
        // newlib-nano over allocates by 8 bytes, 4 bytes for the 32-bit chunk size and another 4 bytes to allow for 8
        // byte-alignment of the returned pointer.
        chunkSize -= 8;
        printf("Chunk: %lu  Address: 0xlX  Size: %lu  %s\n", chunkNumber, chunkCurr, chunkSize, isChunkFree ? "CHUNK FREE" : "");
        chunkCurr = chunkNext;
        chunkNumber++;
    }
}


int main()
{
    printf("Starting at main(X)...\n", (unsigned int)&main);
    
    void* p1 = malloc(100);
    void* p2 = malloc(100);
    void* p3 = malloc(100);
    void* p4 = malloc(100);
    heapWalk();
    free(p2);
    heapWalk();
    free(p4);
    heapWalk();
    free(p1);
    heapWalk();
    free(p3);
    heapWalk();

    return 0;
}

This results in the following output:

Starting at main(000001FD)...
Heap Size: 1900
Chunk: 1  Address: 0x10000670  Size: 428  
Chunk: 2  Address: 0x10000820  Size: 1024  
Chunk: 3  Address: 0x10000C28  Size: 100  
Chunk: 4  Address: 0x10000C98  Size: 100  
Chunk: 5  Address: 0x10000D00  Size: 100  
Chunk: 6  Address: 0x10000D70  Size: 100  
Heap Size: 1900
Chunk: 1  Address: 0x10000670  Size: 428  
Chunk: 2  Address: 0x10000820  Size: 1024  
Chunk: 3  Address: 0x10000C28  Size: 100  
Chunk: 4  Address: 0x10000C98  Size: 100  CHUNK FREE
Chunk: 5  Address: 0x10000D00  Size: 100  
Chunk: 6  Address: 0x10000D70  Size: 100  
Heap Size: 1900
Chunk: 1  Address: 0x10000670  Size: 428  
Chunk: 2  Address: 0x10000820  Size: 1024  
Chunk: 3  Address: 0x10000C28  Size: 100  
Chunk: 4  Address: 0x10000C98  Size: 100  CHUNK FREE
Chunk: 5  Address: 0x10000D00  Size: 100  
Chunk: 6  Address: 0x10000D70  Size: 100  CHUNK FREE
Heap Size: 1900
Chunk: 1  Address: 0x10000670  Size: 428  
Chunk: 2  Address: 0x10000820  Size: 1024  
Chunk: 3  Address: 0x10000C28  Size: 208  CHUNK FREE
Chunk: 4  Address: 0x10000D00  Size: 100  
Chunk: 5  Address: 0x10000D70  Size: 100  CHUNK FREE
Heap Size: 1900
Chunk: 1  Address: 0x10000670  Size: 428  
Chunk: 2  Address: 0x10000820  Size: 1024  
Chunk: 3  Address: 0x10000C28  Size: 424  CHUNK FREE

The first two allocations of 428 and 1024 bytes are from the use of printf() to display text to stdout. That is why they are never freed. This output shows free and active chunks in the heap at each stage and also shows how the heap coalesces adjacent free chunks to produce larger free chunks. By the end, we end up with a single free chunk >400 bytes instead of 4 separate free chunks of 100 bytes.

I hope that helps,

Adam

Hello Adam,

Thanks a lot for your help. Yesterday I was wrapping the function _sbrk to handle the memory requested but i think that your solution is better.

I was trying your function but i don't have the same result. This is my output:

Starting at main(00000199)...
Heap Size: 1468
Chunk: 1  Address: 0x100003E8  Size: 428  
Chunk: 2  Address: 0x10000598  Size: 1024  
Heap Size: 1468
Chunk: 1  Address: 0x100003E8  Size: 428  
Chunk: 2  Address: 0x10000598  Size: 1024  
Heap Size: 1468
Chunk: 1  Address: 0x100003E8  Size: 428  
Chunk: 2  Address: 0x10000598  Size: 1024  
Heap Size: 1468
Chunk: 1  Address: 0x100003E8  Size: 428  
Chunk: 2  Address: 0x10000598  Size: 1024  
Heap Size: 1468
Chunk: 1  Address: 0x100003E8  Size: 428  
Chunk: 2  Address: 0x10000598  Size: 1024 

I'm still trying to understand why this happen, because i create a new environment with the last changes of your project (also to undo my changes).

Regards, Gustavo

::EDIT::

I solved it using the memory allocated. So i made this modification:

...
char* p1 = (char*)malloc(100); // Previously this was just a void*
p1[99] = 'c';
...

And it works.

Thanks again Adam!

Regards, Gustavo

25 May 2014

A new version of GCC4MBED is available on github at https://github.com/adamgreen/gcc4mbed#quick-start

New features include:

  • Upgraded GNU tools to GCC ARM Embedded 4.8-2014-q1-update.
  • Upgraded mbed SDK from revision 54 to revision 84.
  • Builds official mbed libraries from source. Unless the SDK file layout is modified it should be possible for the user to copy newer versions from https://github.com/mbedmicro/mbed to the external/mbed subdirectory of GCC4MBED and have it built as needed.
  • mbed libraries will automatically be built for you if the program's makefile indicates it as a dependency.
  • Samples can now be targeted for LPC11U24 and KL25Z devices in addition to the LPC1768.
  • Note: Output files such as the .bin to be uploaded to your mbed device will no longer be found in the sample directory but in a device specific directory such as LPC1768. This allows for targeting multiple devices from a single build.

Sample makefile for new GCC4MBED

PROJECT         := USBMouse
DEVICES         := LPC1768 LPC11U24 KL25Z
GCC4MBED_DIR    := ../..
NO_FLOAT_SCANF  := 1
NO_FLOAT_PRINTF := 1
MBED_LIBS       := USBDevice

include $(GCC4MBED_DIR)/build/gcc4mbed.mk

The above sample contains two variable assignments that are new to this GCC4MBED update:

  • DEVICES - Lists the devices for which this sample should be built. In this case, the sample will be built for all of the 3 currently supported devices (LPC1768, LPC11U24, and KL25Z).
  • MBED_LIBS - Which official mbed libraries in addition to the core mbed SDK library does this sample require. In this case, the sample requires the USBDevice library as well. The makefile will automatically build this official library for you if it hasn't already been built.

You can read https://github.com/adamgreen/gcc4mbed/blob/master/notes/makefile.creole#make-variables for more GCC4MBED makefile documentation.

You can add support for a new device by copying an existing *-device.mk makefile and updating it to contain variable definitions appropriate for the new device. The main GCC4MBED makefile will automatically pull in any makefile with the *-device.mk suffix, including new ones that you add. To have a project build for your new device update its makefile to include the name of your new device in its DEVICES variable setting.

I have run the new installers and performed test builds on:

  • OS Mavericks
  • Windows 7
  • Ubuntu 12.04

The previous version of GCC4MBED is archived here: https://github.com/adamgreen/gcc4mbed/tree/gcc4.7-2012-q4_mbed54

25 May 2014

Great and appreciate your efforts. Thanks.

26 May 2014

Question for you, how difficult is it to add new targets? I'm using the WiFi DIP Cortex board from Solder Splash Labs and would love to be able to use this with it.

Is this something that I could add on my own with a few instructions or is it a laborious process?

Thanks for the great work!

26 May 2014

Hello Tim,

I should first point out that another option is to use the official export support in the online compiler to export for GCC_ARM.

I take it that this is your board? It shouldn't be too hard to add support to GCC4MBED for this or any of the mbed supported platforms though. I don't have one of these boards to test on but I can try walking you through the process to add support for new devices such as this.

First let's go into the build/ subdirectory of the GCC4MBED project and copy LPC1768-device.mk to LPC1347-device.mk since it is the closest platform already supported (same vendor and same Cortex-M3 family). I recommend using uppercase characters for the LPC1347 prefix as it is used by some of the makefiles to determine all of the supported platforms and you want it to match the case of the symbols actually defined for this device.

To get an idea of what preprocessor defines should be set for building code for this platform, I kick off a build of the mbed SDK using their Python based build system in verbose mode so that I can look at the command line params they pass into GCC when performing the build. For example, I ran the following command:

workspace_tools/build.py -m LPC1347 -t GCC_ARM -v

I grabbed one of the GCC command lines from the console output and pulled out the defines onto their own line so that I could look at them more closely:

/depots/gcc4mbed/gcc-arm-none-eabi/bin/arm-none-eabi-gcc -std=gnu99 -c
    -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers
    -fmessage-length=0 -fno-exceptions -fno-builtin -ffunction-sections -fdata-sections -MMD -fno-delete-null-pointer-checks
    -mcpu=cortex-m3 -mthumb -O2
    -DTARGET_LPC1347 -DTARGET_M3 -DTARGET_NXP -DTARGET_LPC13XX -DTOOLCHAIN_GCC_ARM -DTOOLCHAIN_GCC -D__CORTEX_M3 -DARM_MATH_CM3 -DMBED_BUILD_TIMESTAMP=1401077038.66 -D__MBED__=1
    -I/depots/gcc4mbed/external/mbed/libraries/mbed/targets/hal -I/depots/gcc4mbed/external/mbed/libraries/mbed/targets/hal/TARGET_NXP -I/depots/gcc4mbed/external/mbed/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC13XX -I/depots/gcc4mbed/external/mbed/build/mbed -I/depots/gcc4mbed/external/mbed/build/mbed/TARGET_LPC1347 -I/depots/gcc4mbed/external/mbed/build/mbed/TARGET_LPC1347/TARGET_NXP -I/depots/gcc4mbed/external/mbed/build/mbed/TARGET_LPC1347/TARGET_NXP/TARGET_LPC13XX -I/depots/gcc4mbed/external/mbed/build/mbed/TARGET_LPC1347/TOOLCHAIN_GCC_ARM
    -o /depots/gcc4mbed/external/mbed/build/mbed/.temp/TARGET_LPC1347/TOOLCHAIN_GCC_ARM/TARGET_NXP/TARGET_LPC13XX/analogin_api.o /depots/gcc4mbed/external/mbed/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC13XX/analogin_api.c

Based on this output, I modified the newly created LPC1347-device.mk like so:

16,17c16,17
< MBED_DEVICE        := LPC1768
< MBED_TARGET        := NXP_LPC17XX
---
> MBED_DEVICE        := LPC1347
> MBED_TARGET        := NXP_LPC1347
21,24c21,23
< HAL_TARGET_SRC   := $(MBED_SRC_ROOT)/targets/hal/TARGET_NXP/TARGET_LPC176X
< HAL_TARGET_SRC   += $(MBED_SRC_ROOT)/targets/hal/TARGET_NXP/TARGET_LPC176X/TARGET_MBED_LPC1768
< CMSIS_TARGET_SRC := $(MBED_SRC_ROOT)/targets/cmsis/TARGET_NXP/TARGET_LPC176X
< CMSIS_TARGET_SRC += $(MBED_SRC_ROOT)/targets/cmsis/TARGET_NXP/TARGET_LPC176X/TOOLCHAIN_GCC_ARM
---
> HAL_TARGET_SRC   := $(MBED_SRC_ROOT)/targets/hal/TARGET_NXP/TARGET_LPC13XX
> CMSIS_TARGET_SRC := $(MBED_SRC_ROOT)/targets/cmsis/TARGET_NXP/TARGET_LPC13XX
> CMSIS_TARGET_SRC += $(MBED_SRC_ROOT)/targets/cmsis/TARGET_NXP/TARGET_LPC13XX/TOOLCHAIN_GCC_ARM
30c29
< GCC_DEFINES := -DTARGET_LPC1768 -DTARGET_M3 -DTARGET_NXP -DTARGET_LPC176X -DTARGET_MBED_LPC1768
---
> GCC_DEFINES := -DTARGET_LPC1347 -DTARGET_M3 -DTARGET_NXP -DTARGET_LPC13XX
32d30
<
39c37
< LSCRIPT=$(GCC4MBED_DIR)/external/mbed/libraries/mbed/targets/cmsis/TARGET_NXP/TARGET_LPC176X/TOOLCHAIN_GCC_ARM/LPC1768.ld
---
> LSCRIPT=$(GCC4MBED_DIR)/external/mbed/libraries/mbed/targets/cmsis/TARGET_NXP/TARGET_LPC13XX/TOOLCHAIN_GCC_ARM/LPC1347.ld

I then modified the samples/HelloWorld/makefile so that it DEVICES variable now contained LPC1347 as well:

-DEVICES         := LPC1768 LPC11U24 KL25Z
+DEVICES         := LPC1768 LPC11U24 KL25Z LPC1347

Running make in the HelloWorld directory will build for all 4 supported platforms. Running make LPC1347 will just build for the LPC1347 target. It does successfully build the library and final binary but I have no hardware to test on so I don't know how correct it is. You can try applying these changes and let me know how it works out for you.

Thanks and I hope that helps,

Adam

26 May 2014

Thanks for the information!

Unfortunately the online compiler won't let me export that board for the GCC_ARM. The only export targets I can choose are Keil, mbed online and ZIP.

So it seems that I'll have to try adding support on my own. Won't have time to look at this for a while but will update on progress when I have any.

26 May 2014

Hello Adam, and many thanks for your effort!

I have a LPC2378-STK and a LPC2478-STK boards from Olimex that I want to "convert" to mbed practies. :-)

So I'm trying to follow your instruction to build a LPC2378 binary. I create a new LPC2378-device.mk file as follow:

# Vendor/device for which the library should be built.
MBED_DEVICE        := LPC2378
MBED_TARGET        := NXP_LPC2378
MBED_CLEAN         := $(MBED_DEVICE)-MBED-clean

# Some libraries (mbed and rtos) have device specific source folders.
HAL_TARGET_SRC   := $(MBED_SRC_ROOT)/targets/hal/TARGET_NXP/TARGET_LPC23XX
HAL_TARGET_SRC   += $(MBED_SRC_ROOT)/targets/hal/TARGET_NXP/TARGET_LPC23XX/TARGET_MBED_LPC23XX
CMSIS_TARGET_SRC := $(MBED_SRC_ROOT)/targets/cmsis/TARGET_NXP/TARGET_LPC23XX
CMSIS_TARGET_SRC += $(MBED_SRC_ROOT)/targets/cmsis/TARGET_NXP/TARGET_LPC23XX/TOOLCHAIN_GCC_ARM

# Compiler flags which are specifc to this device.
GCC_DEFINES := -DTARGET_LPC2378 -DTARGET_NXP -DTARGET_LPC23XX

C_FLAGS   := -mcpu=arm7tdmi-s
ASM_FLAGS := -mcpu=arm7tdmi-s
LD_FLAGS  := -mcpu=arm7tdmi-s

# Linker script to be used.  Indicates what code should be placed where in memory.
LSCRIPT=$(GCC4MBED_DIR)/external/mbed/libraries/mbed/targets/cmsis/TARGET_NXP/TARGET_LPC23XX/TOOLCHAIN_GCC_ARM/LPC2378.ld

include $(GCC4MBED_DIR)/build/device-common.mk

And I modified the samples/HelloWorld/makefile so that it DEVICES variable include LPC2378.

But after running make I receive this error:

Building HelloWorld
Compiling ../../src/gcc4mbed.c
C:\Users\C9F25~1.DIC\AppData\Local\Temp\ccuTCZ5t.s: Assembler messages:
C:\Users\C9F25~1.DIC\AppData\Local\Temp\ccuTCZ5t.s:204: Error: selected processor does not support ARM mode `bkpt #0'
C:\Users\C9F25~1.DIC\AppData\Local\Temp\ccuTCZ5t.s:278: Error: selected processor does not support ARM mode `bkpt #0'
C:\Users\C9F25~1.DIC\AppData\Local\Temp\ccuTCZ5t.s:352: Error: selected processor does not support ARM mode `bkpt #0'
make[2]: *** [LPC2378/gcc4mbed.o] Error 1
make[1]: *** [HelloWorld] Error 2
make[1]: Leaving directory `C:/Users/whoamI/Contenitore/gcc4mbed-master/samples'
make: *** [samples] Error 2

I'm on the right track? :-)) Can you suggest what other files I need to modify?

TIA Clemente

26 May 2014

Tim Borland wrote:

So it seems that I'll have to try adding support on my own. Won't have time to look at this for a while but will update on progress when I have any.

To be clear, I suspect that all you will have to do are the few steps I outlined above. As I mentioned this built LPC1347 support for me successfully but I just don't have the hardware to test on.

-Adam

26 May 2014

clemente di caprio wrote:

I'm on the right track? :-)) Can you suggest what other files I need to modify?

Clement, this appears to be an issue with my GCC4MBED glue code and not the mbed SDK itself. I never wrote this code with the expectation that it would be used with anything other than Cortex-M parts. I will need to dig into this a bit more to see how hard it is for me to correct these issues and get it to build successfully for ARM7TDMI parts.

Is this even supported by the online compiler anymore? I went to add it as a platform so that I could perform an export and look at a few things but it didn't show up in the supported list of platforms to select.

-Adam

27 May 2014

Adam Green wrote:

I will need to dig into this a bit more to see how hard it is for me to correct these issues and get it to build successfully for ARM7TDMI parts.

Thanks Adam

Adam Green wrote:

Is this even supported by the online compiler anymore?

I remember that there was support for this platform. Long time ago.. :-)

But my board was not listed, and the MCU was a different type: lpc2368 instead of lpc2378. I think, can be an opportunity for many people to use this "old" MCUs or boards with a full compiler like mbed is.

Thanks

Clemente

28 May 2014

Tim Borland wrote:

So it seems that I'll have to try adding support on my own. Won't have time to look at this for a while but will update on progress when I have any.

Tim, if you are comfortable with git then you can try out the feature/lpc1347 branch I created in GCC4MBED. This enables LPC1347 support for the HelloWorld, Ticker, StdIO, and USBMouse samples.

I hope that helps,

Adam

28 May 2014

clemente di caprio wrote:

I remember that there was support for this platform. Long time ago.. :-)

Clemente,

I too remember there previously being support for the LPC2368 part. I believe that the beta version of the first mbed device was LPC2368 based.

I have tried enabling 2368 support in GCC4MBED (since the linker files for that platform already exist) but I don't have a lot of confidence in it. I was hitting linker errors with the mbed code as found in the official repository that I had to patch. I don't know if those were caused by some difference in the GCC4MBED build process or that code isn't well tested with GCC. The output that I get with my changes looks like it might now have a valid interrupt vector table and reset code path based on what I see in the disassembly. I ended up disabling my extensions in gcc4mbed.c since they make no sense for ARM7TDMI parts anyway. I also tweaked a few other things in the make files to get a build that I was happy with. I pushed them up to github as a feature/lpc2368 branch. Hopefully you can give it a test run on your hardware and let me know what happens.

I hope that helps,

Adam

28 May 2014

Adam Green wrote:

I pushed them up to github as a feature/lpc2368 branch. Hopefully you can give it a test run on your hardware and let me know what happens.

Many thanks Adam, I will test it soon...

Clemente

29 May 2014

Hello Adam,

I did a test with this simple code but without success:

/* Test which brings default HelloWorld project from mbed online compiler
   to be built under GCC.
*/
#include "mbed.h"

DigitalOut myled1(P0_21);
DigitalOut myled2(P0_13);

//Serial pc(P0_15, P0_16); // tx2, rx2

int main() 
{
	unsigned int i;
	
//	pc.printf("Hello World!");
	
    while(1) 
    {
        myled1 = 1;
		myled2 = 0;
        //wait(0.25);
		for( i=0; i<50000000; i++);
        myled1 = 0;
		myled2 = 1;
        //wait(0.25);
		for( i=0; i<50000000; i++);
    }
}

I'm using a LPC2378-STK board. The MCU is different, I know, but not so much... :-)

I'm using FlashMagic to download the .HEX file. And it works well. But after the download nothing happens.

Some suggestions?

TIA

P.S. Googling I found this link: https://mbed.org/handbook/mbed-NXP-LPC2368

:-))

29 May 2014

Clemente,

At this point, I think you will need to create a port for your specific part of interest. There are some good notes here for helping to get started with that process. If you don't already have one, a JTAG debugger would probably be a helpful aid as well.

-Adam

18 Jun 2014

I updated gcc4mbed to upgrade mbed SDK from revision 84 to revision 85.

21 Jul 2014

Has anyone successfully used gcc4mbed with the NRF51822?

I would like to use Nordic's S130 SoftDevice with their NRF51 SDK on my NRF51822 Mbed boards, but unfortunately the Mbed online IDE only supports the S110 SD.

Is gcc4mbed a good way to get set up compiling my programs offline for the NRF51822 using mbed's and Nordic's SDKs?

EDIT:

I tried it, and realised NRF51822 is not currently supported by default. Is there a way to add support for it? Or shall I pursue other options?

21 Jul 2014

Jimi, I see that some GCC_ARM support was added for the NRF51822 target in revision 86 of the mbed SDK but gcc4mbed is currently at revision 85. Are you able to export NRF51822 projects to GCC-ARM from the online compiler? If so, you could try that. If not, I could try moving the working branch of gcc4mbed up to the latest mbed SDK sources and you could experiment with that. I have no experience with these Nordic targets so I don't know what is involved with the Soft Device upgrades so you would have to take care of that yourself.

Let me know,

Adam

22 Jul 2014

Hi Adam, thanks for your help!

Unfortunately at the moment the online compiler doesn't support exporting to GCC_ARM. If you do get gcc4arm up to the latest SDK I'll give it a try and let you know how it goes.

22 Jul 2014

@Jimi,

did you test beta mode? that one might have gcc enabled for nordic. Be caution, and report problems if any with gcc.. It was merged as a step closer to have gcc export. Here's full report: https://github.com/mbedmicro/mbed/pull/337

21 Aug 2014

I updated gcc4mbed to upgrade mbed SDK from revision 85 to revision 88.

03 Nov 2014

Hi Adam. Congratulations for a nice job.

If you are interested, I have succeeded porting an online app and library to off-line gcc4mbed with a NUCLEO-F401RE target. One change in build/gcc4mbed.mk around line 335:

deploy: $(DEVICES)-deploy
#deploy: LPC1768-deploy

and then even the automatic copy to flash happens as:

LPC_DEPLOY="cp PROJECT.bin /media/larryl/NUCLEO/ ; sync"

Here is my NUCLEO-F401RE-device.mk /media/uploads/svkatielee/nucleo_f401re-device.mk which looks like this:

# Vendor/device for which the library should be built.
MBED_DEVICE        := NUCLEO_F401RE
MBED_TARGET        := NUCLEO_F4XX
MBED_CLEAN         := $(MBED_DEVICE)-MBED-clean

# Some libraries (mbed and rtos) have device specific source folders.
HAL_TARGET_SRC   := $(MBED_SRC_ROOT)/targets/hal/TARGET_STM/TARGET_NUCLEO_F401RE
HAL_TARGET_SRC   += $(MBED_SRC_ROOT)/targets/hal/TARGET_STM/TARGET_NUCLEO_F401RE/TARGET_MBED_NUCLEO_F401RE
CMSIS_TARGET_SRC := $(MBED_SRC_ROOT)/targets/cmsis/TARGET_STM/TARGET_NUCLEO_F401RE
CMSIS_TARGET_SRC += $(MBED_SRC_ROOT)/targets/cmsis/TARGET_STM/TARGET_NUCLEO_F401RE/TOOLCHAIN_GCC_ARM
RTX_TARGET_SRC   := $(GCC4MBED_DIR)/external/mbed/libraries/rtos/rtx/TARGET_M4/TOOLCHAIN_GCC
ETH_TARGET_SRC   := $(GCC4MBED_DIR)/external/mbed/libraries/net/eth/lwip-eth/arch/TARGET_STM

# Compiler flags which are specifc to this device.
GCC_DEFINES := -DTARGET_NUCLEO_F401RE -DTARGET_M4 -DTARGET_STM -DTARGET_NUCLEO_F401RE -DTARGET_MBED_NUCLEO_F401RE
GCC_DEFINES += -D__CORTEX_M4 -DARM_MATH_CM4 -D__FPU_PRESENT=1 -DTARGET_FF_ARDUINO -DTARGET_FF_MORPHO

C_FLAGS   := -mcpu=cortex-m4 -mthumb -mthumb-interwork
ASM_FLAGS := -mcpu=cortex-m4 -mthumb
LD_FLAGS  := -mcpu=cortex-m4 -mthumb

# Linker script to be used.  Indicates what code should be placed where in memory.
LSCRIPT=$(GCC4MBED_DIR)/external/mbed/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_NUCLEO_F401RE/TOOLCHAIN_GCC_ARM/NUCLEO_F401RE.ld

include $(GCC4MBED_DIR)/build/device-common.mk

I do have a couple other STM32 Discovery boards that I have not taken the time to test. This is the board I chose for the current project. I have spent many hours with other instructions/projects/IDEs and yours is the only one that I succeeded in making work several days in a row after several reboots. (eclipse CDT, mbedmicro/mbed, stm32cubef4, STM32F4-Discovery_FW_V1.1.0 with various sets of directions just to name a few) I am currently using geany on a Unbuntu 12.10 laptop on my sailboat in the Philippines (I started this near Singapore 2 months ago. Just now have a repeatable build process.)

Thanks again, Larry

03 Nov 2014

@Larry, curiosity, what have you tried and failed?

03 Nov 2014

Martin, I presume you are asking about the IDEs. It could be that I didn't try each method long enough before I tried something else. At which point I may have messed up the previous setup beyond repair without knowing. Another problem I have is I can only connect to the internet through my cell phone at low speeds, expensively, in Thailand, Malaysia, and the Philippines, as phone cords don't reach out into the bays where my boat is usually anchored. I should be able to do this, I was a senior Unix systems consultant for 20 years, but then I always had trouble with the linker!

But here are my failures.

  • 1) http://regalis.com.pl/en/arm-cortex-stm32-gnulinux/ his demo worked OK, but after about 15 hours trying to get a custom Makefile for my desired setup, not finding the includes and/or libraries, I quit.
  • 2) spent 2 days trying to modify Makefile for STM32CubeF4 from the export from online mbed as zip of blinky NUCLEO boards were only supported as zip export until lately. Decided there must be an easier way.
  • 3) got the zip and downloaded mbedmicro/mbed. The tests I tried seem to work ok. I tried to copy and modify one. Then it seemed my project had to look like the test and be in that file structure. Te second day it could not find some libraries , ie compile/link errors, where it worked before. I had rebooted several times (on batteries and solar panels so I shut it off when not actually using the laptop) Maybe an environment variable was different. Also it would not deploy to the target automatically. I had to manually coyp the binary over with openocd et al.
  • 4)next I downloaded eclipse accprding to http://mcuoneclipse.com/2013/07/21/diy-free-toolchain-for-kinetis-part-2-eclipse-ide/ then downloaded GCC4MBED accord to https://mbed.org/cookbook/eclipse-for-building-and-debugging and loaded arm for ecplise as in above. The examples work just like it says, but does not deploy (finally found out in previous post). Any larger project, using multiple files or imported mbed libraries does not compile/link missing includes. I kept searching the net with error messages, and following other suggestions. Decided the libs were listed in the wrong order but eclipse auto manage build does not easily let you change order. I could develop for 2 or 3 days then start failing to find libs again. frustrated I went back to mbed on line again
  • 5)Aftert a few more weeks of online (slow, loose work when phone drops internet, and expense) I noticed different instructions for makefile based gcc4mbed. https://github.com/adamgreen/gcc4mbed/blob/master/notes/porting.creole#readme I followed them closely and they worked. 5 days in a row, no problems. Made a github repo, checked it all in. checked it out still works fine. The IMU10DOF 3axis accel, gyro, compass and baro. hen added back in the LCD library and it can no longer find the gpio init libraries! #include "mbed_assert.h" I see them in the mbedmicro/mbed but not the gcc4mbed so it must be too many mixed versions.

But you get the idea. Mostly my fault if you don't count simple instructions for simple demo that don't scale well.