adamgreen / gcc4mbed

Project to allow GCC compilation of code using mbed SDK libraries.
172 stars 68 forks source link

Open Discussion #63

Closed adamgreen closed 3 years ago

adamgreen commented 7 years ago

Please feel free to use this GitHub issue for general discussion about the GCC4MBED project. If you just want to ask me or the community a general question, then this issue is the place to do it.

GitHub gives you the option of subscribing to get notifications when people post new content to this issue. You should find this subscribe option in the pane on the right-hand side of the issue.

adamgreen commented 7 years ago

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

New features include:

BlackstoneEngineering commented 7 years ago

FYI GCC is now supported natively in the mbed project via mbed-CLI. This includes internal extensive testing in both nightlies and for each release.

adamgreen commented 7 years ago

FYI GCC is now supported natively in the mbed project via mbed-CLI. This includes internal extensive testing in both nightlies and for each release.

Thanks for the link! If mbed-cli works for people, then I definitely recommend that they use it. GCC4MBED was created back in 2011 before there was any official offline support from the mbed team. Why have I continued to maintain it after the mbed team has added this support? Mostly because I still find it useful for my own projects:

satish040 commented 7 years ago

Hi Adam,

I am working on NCS36510 cortex m3 based platform and trying to port your working branch https://github.com/adamgreen/gcc4mbed/tree/working and i am stuck. The code fails at the point,

SVC_0_1(svcKernelStart, osStatus, RET_osStatus)

The disassembly of the above is as follows, 461 SVC_0_1(svcKernelStart, osStatus, RET_osStatus) 00104102: ldr.w r12, [pc, #24] ; 0x10411c 00104106: svc 0 00104108: mov r3, r0 605 return __svcKernelStart(); 0010410a: nop
606 }

At this point pc goes for a toss and has the value ffffffc2.

Not sure what is causing the problem.

Thanks, Satish.

adamgreen commented 7 years ago

@satish040 First I would recommend you use the master branch as it is the tested one. The working branch contains my work in progress and hasn't gone through a full test pass yet. That said, I doubt your problem is related to that.

Can you enter a new issue here to track this problem? In that issue, please try to give me as much information about what you have done to get to this point? You mention that you are "trying to port" so it would be good to say what type of modifications you have made as part of that port. What sample are you attempting to build and run when this happens? Give me enough information in that issue that I can build the same image here to take a look at it to see if I notice anything obvious.

StarDev-it commented 7 years ago

Hi Adam, thanks for you guide. I followed the guide and I've try to setup the autodeploy actions after build. I've added the LPC_DEPLOY/GCC4MBED_DEPLOY environment variable, but when i try to compile the project the compiler return this error:

make[1]: *** No rule to make target 'deploy'.  Stop.
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:26: all] Error 2

Can you help me?

adamgreen commented 7 years ago

@StarCod3 One thing that might cause this is if your makefile is configured to build for devices that don't include LPC1768 since make deploy is actually a shortcut for make LPC1768-deploy. If you want it to build and deploy for a different device then change the LPC1768- prefix to match that device (Example:make KL25Z-deploy).

AchmadFathoni commented 7 years ago

I tried to include mbed.h and the DigitialOut class is resolved but the rest like Serial, pirntf, LED1, SERIAL_RX, SERIAL_TX could not be resolved and Program "echo" not found in path. My include directory is ${ProjDirPath}/../../external/mbed-os/ Also there is no ARM Linux GCC in Eclipse's toolchain as the tutorial says so I use GNU Autotools Toolschain because Cross ARM GCC can't execute make command. Anyway I success to build and upload.

adamgreen commented 7 years ago

@AchmadFathoni The documentation for gcc4mbed usage with Eclipse is out of date and was written before mbed had support for exporting to Eclipse. I recommend you checkout mbed's official Eclipse export features.

I hope that helps.

bqam-ublox commented 7 years ago

@adamgreen just wanted to tell you that you are doing a wonderful job (y). This project helped us getting hands on with mbed2. Looking forward to mbed5 now.

BramOoms commented 7 years ago

@adamgreen I was wondring why newlib-nano is used by default in combination with mbed-os 5, because as far as I know newly-nano is not thread save, while mbed-os 5 is promoted as multithreaded, or am I wrong?

adamgreen commented 7 years ago

@BramOoms I chose to stick with newlib-nano as the default to keep the binaries as small as possible and because mbed-os isn't really all that thread safe with either version of newlib anyway.

One of the few things that used to be thread safe in newlib but not newlib-nano were malloc/free accesses to the heap. If memory serves correct, that should now be thread safe as well with more recent versions of newlib-nano.

The use of newlib-nano can always be disabled via the NEWLIB_NANO variable in your makefile.

BramOoms commented 7 years ago

@adamgreen That makes sense! Thanks for the quick reply. Let me explain my situation: I'm using your project as a reference in my project with support for Atmel's SAM4E MCU (Cortex M4).

I started my project a while ago when the gcc4mbed project was using mbed classic. However, I'm getting bus/hard faults every now and than which seems to be caused by memory corruption (invalid program counter, lr register values on stacked exception frame). Or my watchdog kicks in because RTX keeps executing the idle thread.

I read about the thread safety issues regarding the standard c libraries and therefore decided to make my application (almost) single threaded. I'm just using the lwip threads (ethernet gmac thread and lwip tcpip thread) and the timer thread. Callbacks from the timer thread are immediately scheduled for execution on the main thread by posting them in my main thread's mail box. This seemed to be working fairly well. However, I'm still gettings hard or bus faults every now and than (system could run for day's or even weeks sometings). I decided to update to your latest gcc4mbed version with mbed-os 5, however, without improvements.

Could the faults I'm experiencing be related to the thread safety issues regarding newlib(nano)? Even if I'm not allocating or freeing memory outside the main thread? It seems to be worse with newlib compared to newlib-nano. Thanks for helping!

adamgreen commented 7 years ago

@BramOoms

Could the faults I'm experiencing be related to the thread safety issues regarding newlib(nano)? Even if I'm not allocating or freeing memory outside the main thread? It seems to be worse with newlib compared to newlib-nano.

Maybe. A few things could lead to such problems. I will say that when working with RTX, the thing which most often caused memory corruption for me was a thread overflowing its stack. This will end up corrupting the contents of another thread's stack or some global variables. This was even more common for me when I used full newlib since newlib-nano required less stack space for local variables.

If you don't get to the root cause of your problem soon and want some more help then maybe I could work with you to get me a crash dump that I could debug.

BramOoms commented 7 years ago

@adamgreen I really appreciate it if you could help me out! The problem I'm facing now is that my watchdog kicks in because the system keeps executing the idle thread (after the system has run ok a couple of days). So I don't have a crash dump. I looked at the thread control blocks and they looked ok, (not corrupted). I made a complete print out of my RAM to my debug UART to find out if I could see any corruption.

I noticed a remarkable issue: My main stack (12 kb) looks fragmentated, in the sense that it contains blocks filled with the "magic fill" pattern (0xCCCCCCCC) and other data alternating. This is the case right after start up when the systems runs ok. As far as I know a stack can only be a continuous memory block, is that correct? The stacks of the other threads looks ok: real stack data, followed by a continuous block containing 0xCCCCCCCC until the top-of-stack-magic word. To you have any Idea how this could happen and how I can debug this?

adamgreen commented 7 years ago

@BramOoms

The problem I'm facing now is that my watchdog kicks in because the system keeps executing the idle thread (after the system has run ok a couple of days)

It typically is ok if the idle thread is running. That just means that no other thread has anything else to do at the moment. Which thread is supposed to tickle the watchdog? Can you dump that thread's stack when the watchdog fires?

I noticed a remarkable issue: My main stack (12 kb) looks fragmentated, in the sense that it contains blocks filled with the "magic fill" pattern (0xCCCCCCCC) and other data alternating.

That can be expected behavior. If you have a buffer defined on the stack but you don't completely fill that buffer then it could lead to such a pattern of stack usage. For example:

{
    char buffer[256];

    strcpy(buffer, "Small usage!");
}

What device are you targeting? When the watchdog kicks in, is it reseting your device or do you have it setup to fire an interrupt from which you can debug the state of the device at the time of the watchdog event? Are you comfortable enough with the GDB command line to start it up and issue commands that I would give you to create a dump that I could debug? I would need access to the .elf file as well. Is your project too confidential for me to have access to the .elf? Usually I don't need access to the source code.

BramOoms commented 7 years ago

@adamgreen

Which thread is supposed to tickle the watchdog? Can you dump that thread's stack when the watchdog fires?

My code is executed as much as possible from the main thread. I post a callback object in the main thread's queue when a timer expires or when code needs to be executed after an interrupt. The main thread tickles the watchdog every time it processes a message from its queue. I have a about a hand full of timers for ADC conversion and polling data on tcp sockets. The timers expire every 20 ms and are restarted in the timer callback function.

void AsyncTask::postCallback(Callback* callback)
{
    _queue.put(callback);
}

void AsyncTask::waitForCallbacks()
{
    while (true)
    {
        osEvent e = _queue.get();
        if (e.status == osEventMessage) {
            irc::Watchdog::WATCHDOG.kick();
            Callback* callback = (Callback*)e.value.p;
            callback->invoke();
        }
    }
}

What device are you targeting? When the watchdog kicks in, is it reseting your device or do you have it setup to fire an interrupt from which you can debug the state of the device at the time of the watchdog event?

I'm targeting an Atmel SAM4E16C. I have it setup the fire an interrupt when the watchdog expires. I have attached a text file containing a RAM dump made from my watchdog fault interrupt handler. My main thread stack is from 0x20007E64 - 0x2000AE64. ram-dump.txt

Are you comfortable enough with the GDB command line to start it up and issue commands that I would give you to create a dump that I could debug? I would need access to the .elf file as well. Is your project too confidential for me to have access to the .elf? Usually I don't need access to the source code.

I'm not an GDB expert, but I can launch it and issue commands you give me! I'm using OpenOCD as GDB server and able to connect to it using arm-none-eabi-gdb. I can provide the elf file, no problem! Would you recommend using newlib or newlib-nano?

BramOoms commented 7 years ago

@adamgreen

Discovered that the RAM dump made from the watchdog fault handler seems to contain 7 thread stacks (7 times the magic stack top pattern (0xA52E5AE2), while there suppose to be only 6:

The os_active_TCB array contains only 6 threads when a watchdog fault occurs, so I don't understand why my RAM contains 7 thread stacks. Do you have any idea?

I had a look at the task control blocks for each thread during a watchdog fault and it seems that the main thread is waiting for a semaphore (state 7 - WAIT_SEM), however, I'm not waiting for a semaphore in code executed in the main thread as far as I can see.

adamgreen commented 7 years ago

@BramOoms

I'm targeting an Atmel SAM4E16C

Did you have to add this support yourself? I don't see this target supported by mbed-os.

The main reason I was asking for the device type was so that I could look at its linker script to get the RAM regions so that I knew what to have dumped. What are the RAM regions for your device? I think it is 128K starting at 0x20000000. If that is the case, these GDB commands should create a crash dump that I can debug:

select-frame 0

# Starts with a header that indicates this is a CrashCatcher dump file.
dump binary value crash.dump (unsigned int)0x00024363

# Hardcoding flags to indicate that there will be floating point registers in dump file.
append binary value crash.dump (unsigned int)0x00000001

# Dump the integer registers.
append binary value crash.dump (unsigned int)$r0
append binary value crash.dump (unsigned int)$r1
append binary value crash.dump (unsigned int)$r2
append binary value crash.dump (unsigned int)$r3
append binary value crash.dump (unsigned int)$r4
append binary value crash.dump (unsigned int)$r5
append binary value crash.dump (unsigned int)$r6
append binary value crash.dump (unsigned int)$r7
append binary value crash.dump (unsigned int)$r8
append binary value crash.dump (unsigned int)$r9
append binary value crash.dump (unsigned int)$r10
append binary value crash.dump (unsigned int)$r11
append binary value crash.dump (unsigned int)$r12
append binary value crash.dump (unsigned int)$sp
append binary value crash.dump (unsigned int)$lr
append binary value crash.dump (unsigned int)$pc
append binary value crash.dump (unsigned int)$xpsr

# The exception PSR and crashing PSR are one in the same.
append binary value crash.dump (unsigned int)$xpsr

# Dump the floating point registers
append binary value crash.dump (float)$s0
append binary value crash.dump (float)$s1
append binary value crash.dump (float)$s2
append binary value crash.dump (float)$s3
append binary value crash.dump (float)$s4
append binary value crash.dump (float)$s5
append binary value crash.dump (float)$s6
append binary value crash.dump (float)$s7
append binary value crash.dump (float)$s8
append binary value crash.dump (float)$s9
append binary value crash.dump (float)$s10
append binary value crash.dump (float)$s11
append binary value crash.dump (float)$s12
append binary value crash.dump (float)$s13
append binary value crash.dump (float)$s14
append binary value crash.dump (float)$s15
append binary value crash.dump (float)$s16
append binary value crash.dump (float)$s17
append binary value crash.dump (float)$s18
append binary value crash.dump (float)$s19
append binary value crash.dump (float)$s20
append binary value crash.dump (float)$s21
append binary value crash.dump (float)$s22
append binary value crash.dump (float)$s23
append binary value crash.dump (float)$s24
append binary value crash.dump (float)$s25
append binary value crash.dump (float)$s26
append binary value crash.dump (float)$s27
append binary value crash.dump (float)$s28
append binary value crash.dump (float)$s29
append binary value crash.dump (float)$s30
append binary value crash.dump (float)$s31
append binary value crash.dump (unsigned int)$fpscr

# Dump 128k of RAM starting at 0x20000000.
#   First two words indicate memory range.
append binary value crash.dump (unsigned int)0x20000000
append binary value crash.dump (unsigned int)(0x20000000 + 128*1024)
append binary memory crash.dump 0x20000000 (0x20000000 + 128*1024)

# Dump the fault status registers as well.
append binary value crash.dump (unsigned int)0xE000ED28
append binary value crash.dump (unsigned int)(0xE000ED28 + 5*4)
append binary memory crash.dump 0xE000ED28 (0xE000ED28 + 5*4)

More information on what I am dumping with those commands can be found here.

You can email me the resulting crash.dump and corresponding ELF file. I have an electronic mail account at yahoo.com. The alias I use there is adamgrym.

BramOoms commented 7 years ago

@adamgreen

Yes, I've added support for the SAM4E target and you are correct about the RAM regions: 128K starting from 0x20000000. I have tried to create a dump using your GDB commands while my program loops in the watchdog fault handler ISR, but got an "Invalid cast." error while trying to dump the xpsr, floating point and fpscr registers. What could be wrong?

adamgreen commented 7 years ago

@BramOoms OpenOCD must call xpsr something else. Maybe cpsr or xPSR? You can issue a info all-registers in GDB to see a list of what OpenOCD calls all of the registers it reports to GDB. You can also check that output to see if it is giving you floating point registers.

DouglasPearless commented 7 years ago

@adamgreen I am working on a Smoothie project, and as Smoothie V1 uses your gcc4mbed I guess the issue is one I am hoping you can provide some guidance / help on.

I have found a situation where the SerialConsole UART is being interrupted while it is receiving by the USB end-point code, and while still in there, it is further interrupted to send on the UART.

The result is that in the below code snipped from the MBED library is that the flush(_file) does not actually flush the input (i.e. throw away unread chars), but instead flushes the buffer to UART which I believe is due to the sequence of interrupts. I have spent more that a few days to get to this point!!

mbed::Stream::getc() at Stream.cpp:43

int Stream::getc() { fflush(_file); return std::fgetc(_file); }.

I can go into greater details if you want, but the root cause of this appears to be due to Smoothie using an older version of gcc4mbed that itself is using MBED 2 which I believe is not thread safe for Stream, and reading the source code for Stream.cpp in MBED OS 5 it now uses locks and therefore should be thread safe.

The latest version on the MBED site:

int Stream::getc() { lock(); fflush(_file); int ret = mbed_getc(_file); unlock(); return ret; }

So the question is, what is required to migrate Smoothie V1 to use your latest code base, and can it be done?

Cheers Douglas

adamgreen commented 7 years ago

@DouglasPearless It has been a long time since I last touched the Smoothie v1 code base. I don't know what it would take to upgrade it to a newer version of the mbed SDK. I know that they made a few local changes to the SDK code that you would need to maintain during such an upgrade.

I have a few comments/questions:

I don't understand this comment. That is what I would expect fflush() to do. Push through all outstanding buffered writes to the UART peripheral before returning to the caller.

I hope that helps.

DouglasPearless commented 7 years ago

@adamgreen thanks for the quick response.

You are right it may well be a bug about interacting with a Stream from multiple “threads”.

I have discussed the issue with the Smoothie team but not this specific scenario.

The issue I traced with the flush is that it is called in the getc routine and should have discarded the unread input BUT instead flushed the UART input buffer to the output of the UART!

In this instance Smoothie is returning an “ok” but this gets corrupted with characters that are still in the input buffer 😩

Sent from my iPhone

On 2/12/2017, at 11:54 AM, Adam Green notifications@github.com wrote:

@DouglasPearless It has been a long time since I last touched the Smoothie v1 code base. I don't know what it would take to upgrade it to a newer version of the mbed SDK. I know that they made a few local changes to the SDK code that you would need to maintain during such an upgrade.

I have a few comments/questions:

Is it not a bug that the Smoothie firmware is interacting with the same stream from multiple 'threads' of execution? I thought it tried to maintain single threaded access to generic (Standard C/C++ Library, mbed SDK, etc) features. It would probably be better to ask the Smoothie team what would be involved in such an upgrade. They have probably tried to do it before and know what hiccups have been encountered. If it was me and I knew that this was really the bug and not the multithreaded access itself, I would just upgrade the parts required to fix the specific issue. The result is that in the below code snipped from the MBED library is that the flush(_file) does not actually flush the input (i.e. throw away unread chars), but instead flushes the buffer to UART

I don't understand this comment. That is what I would expect fflush() to do. Push through all outstanding buffered writes to the UART peripheral before returning to the caller.

I hope that helps.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

adamgreen commented 7 years ago

The issue I traced with the flush is that it is called in the getc routine and should have discarded the unread input BUT instead flushed the UART input buffer to the output of the UART!

I don't think that fflush() would ever discard characters in the input buffer. It is used here to make sure that all outstanding output data on the stream is sent to the user before waiting for input data so that the user knows to what they are responding.

DouglasPearless commented 7 years ago

@adamgreen

My thoughts on the fflush are based on:

https://stackoverflow.com/questions/16780908/understanding-the-need-for-fflush-and-problems-associated-with-it

And what I am observed is:

While the MBED library was writing to the SPI interface to read the SD Card, a character arrived from the UART, the getc() routine was called BUT for some reason it was also written to the UART:

serial_putc() at serial_api.c:378 0x3ec88
mbed::Serial::_putc() at Serial.cpp:64 0x3f502
mbed::Stream::write() at Stream.cpp:59 0x3f5e0
_write() at stdio.cpp:195 0x3f97a
_write_r() at 0x47f70
__sflush_r() at 0x44240 mbed::Stream::getc() at Stream.cpp:43 0x3f6de
SerialConsole::on_serial_char_received() at SerialConsole.cpp:46 0xeb3a void mbed::FunctionPointer::membercaller() at FunctionPointer.h:73 0xeb0e
mbed::FunctionPointer::call() at FunctionPointer.cpp:33 0x3f30a uart0_irq() at serial_api.c:312 0x3e62e

() at 0xfffffff9 spi_master_write() at spi_api.c:252 0x3fff8 SDCard::_read() at SDCard.cpp:472 0x18904 SDCard::disk_read() at SDCard.cpp:324 0x18972 USBMSD::memoryRead() at USBMSD.cpp:654 0x1931a USBMSD::USBEvent_EPIn() at USBMSD.cpp:272 0x19388 USB::USBEvent_EPIn() at USB.cpp:281 0xd548 USBHAL::usbisr() at USBHAL_LPC17.cpp:947 0x183ea Kernel::call_event() at Kernel.cpp:319 0x8d2e main() at main.cpp:275 0x76b2 I think that USB stuff is not related to the issue (famous last words) as reviewing that code, the buffers etc seem to be in totally different memory locations an relate only to the USB modules. () at 0xfffffff9 shows that the ARM core interrupted that because the UART interrupt occurred, and that (eventually) called the SerialConsole::on_serial_char_received() at SerialConsole.cpp:46 0xeb3a which is where it starts to get interesting, the mbed::Stream::getc() at Stream.cpp:43 0x3f6de looks like: int Stream::getc() { fflush(_file); return std::fgetc(_file); } and the fflush(_file) I stepped through and it flushed the contents on the INPUT buffer itself to the UART appears to be the reason Smoothie is now writing BACK to the UART, though I need to understand WHY it is doing that. I was wondering if Stream is not thread safe as under MBED is 5 it now has locking? Thoughts? Sent from my iPhone > On 2/12/2017, at 1:05 PM, Adam Green wrote: > > The issue I traced with the flush is that it is called in the getc routine and should have discarded the unread input BUT instead flushed the UART input buffer to the output of the UART! > > I don't think that fflush() would ever discard characters in the input buffer. It is used here to make sure that all outstanding output data on the stream is sent to the user before waiting for input data so that the user knows to what they are responding. > > — > You are receiving this because you were mentioned. > Reply to this email directly, view it on GitHub, or mute the thread. >
adamgreen commented 7 years ago

As you say, the stream implementation on that version of the MBED SDK isn't thread safe. Whether that is causing your issue, I am not sure. If another 'thread' was writing data to the stream's buffer when a character comes in on the UART then yes, the stream's write buffer could get corrupted because of the fflush() that gets called in the UART's ISR context.

Probably best to move this issue over to the Smoothie project.

DouglasPearless commented 7 years ago

@adamgreen

Thanks for the pointers.

Cheers Douglas

On 2/12/2017, at 3:38 PM, Adam Green notifications@github.com wrote:

As you say, the stream implementation on that version of the MBED SDK isn't thread safe. Whether that is causing your issue, I am not sure. If another 'thread' was writing data to the stream's buffer when a character comes in on the UART then yes, the stream's write buffer could get corrupted because of the fflush() that gets called in the UART's ISR context.

Probably best to move this issue over to the Smoothie project.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/adamgreen/gcc4mbed/issues/63#issuecomment-348661938, or mute the thread https://github.com/notifications/unsubscribe-auth/ADkh-w9EPPHUzVhjGe3gVHxvXGHP7Ev4ks5s8LhAgaJpZM4Nf7ZI.

VladasZ commented 5 years ago

Hello Adam. Is there a way to build gcc4mbed project using CMake?

adamgreen commented 5 years ago

@VladasZ You can generate a CMake'able mbed project from the mbed online compiler as one of the export options.

VladasZ commented 5 years ago

@adamgreen Thank you.

adamgreen commented 3 years ago

This project is no longer under active development.