Skip to content
This repository has been archived by the owner on Jun 24, 2022. It is now read-only.

Open Discussion #63

Closed
adamgreen opened this issue May 18, 2017 · 32 comments
Closed

Open Discussion #63

adamgreen opened this issue May 18, 2017 · 32 comments

Comments

@adamgreen
Copy link
Owner

adamgreen commented May 18, 2017

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
Copy link
Owner Author

adamgreen commented May 19, 2017

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 6-2017-q1-update.
  • Upgraded mbed SDK from revision 119 to revision 142.
  • With the upgrade to mbed SDK revision 142, the multithreaded mbed-os version 5 is now the default version of mbed used:
    • If you want the smaller single-threaded mbed 2 version of the library then add MBED_OS_ENABLE := 0 to your project's Makefile.
  • GCC4MBED_TYPE now supports these following types to match the mbed build system:
    • Debug with optimization disabled. CPU sleep not used from RTOS and asserts are enabled. Best debugging experience but largest code size.
    • Develop with -Os, space saving optimizations enabled. CPU sleep not used from RTOS and asserts are enabled.
    • Release with -Os, space saving optimizations enabled. CPU sleep is used from RTOS and asserts are disabled by setting the NDEBUG macro.
  • The GCC4MBED_TYPE alone never enables the MRI debug monitor anymore. You must now set the MRI_ENABLE variable to value of 1 to enable it.
  • The mbed build system now force includes a mbed_config.h into every source file compiled. GCC4MBED has the MBED_CONFIG_H variable to allow the user to specify the config file to use. It defaults to src/mbed_config.h
  • The build/ folder now contains *-device.mk makefiles for every target that has been marked in targets.json as supporting the GCC_ARM toolchain.
    • You can run make help for any of the samples to see a list of all currently supported devices.
    • I have only tested building the targets which indicate that they are part of mbed's version 2 or 5 releases in targets.json.
    • While I make sure that the samples build for most of the targets, I only deploy and run on the following set:
      • LPC1768
      • KL25Z
      • K64F
      • NRF51_DK
    • Please feel free to open GitHub issues to let me and the community know if you hit any issues for a target that should be supported with the GCC_ARM toolchain so that we can investigate.
    • See device notes for more information about the expanded target support.
  • Sample updates:
    • Some were deleted:
      • USBHost samples since none of the USB libraries are officially supported in the latest mbed tree (they are in the features/unsupported folder). I did use the unsupported USBDevice library as a user library in the USBMouse sample though.
      • rtos_basic since even HelloWorld now uses the RTOS.
    • Updated Blink sample to get it as small as possible:
      • Set MBED_OS_ENABLE to 0 since it doesn't need any RTOS functionality.
      • Provides an implementation of _exit() since the mbed version flushes the stdout/stderr streams and uses mbed APIs to blink LEDs. This pulls in a bunch of stream, UART, timer, and GPIO mbed code.
    • Updated SdPerf to use the SD card driver compatible with the new driver model of the mbed-os. The SDBlockDevice implementation comes from https://github.com/ARMmbed/sd-driver where before it was shipped as part of the mbed SDK.
    • Updated TCPSocket_HelloWorld to use the new mbed-os networking APIs.
  • I updated the documentation and added a few new documents as well:

@BlackstoneEngineering
Copy link

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
Copy link
Owner Author

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:

  • I don't want to take Python as a dependency for building my C/C++ open source projects. I don't regularly use Python and don't have tools like PIP installed on my machine so ofcourse the first step in the mbed-cli install steps fails for me. I don't want to have to install Python and its related tools just to build my C/C++ code. Tools should be distributed in ready to execute forms. This had been done with pyOCD in the past and it was the only version I successfully got to work on my main build machine.
  • I still primarily use the LPC1768 based mbed board in my projects and I prefer to use my MRI debug monitor rather than the CMSIS-DAP solution for debugging the 1768. GCC4MBED has MRI support tightly integrated.
  • I am used to the GCC4MBED workflow and I don't want to change :)

@satish040
Copy link

satish040 commented Aug 3, 2017

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
Copy link
Owner Author

@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
Copy link

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
Copy link
Owner Author

@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
Copy link

AchmadFathoni commented Oct 14, 2017

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
Copy link
Owner Author

@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
Copy link

@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
Copy link

@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
Copy link
Owner Author

adamgreen commented Oct 31, 2017

@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
Copy link

BramOoms commented Nov 1, 2017

@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
Copy link
Owner Author

@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
Copy link

BramOoms commented Nov 6, 2017

@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
Copy link
Owner Author

@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
Copy link

BramOoms commented Nov 7, 2017

@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
Copy link

BramOoms commented Nov 7, 2017

@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:

  • Timer thread
  • Main Thread
  • LWIP TCP/IP thread
  • GMAC thread
  • UART data input thread
  • Idle thread

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
Copy link
Owner Author

@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
Copy link

@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
Copy link
Owner Author

@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
Copy link

@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
Copy link
Owner Author

@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.

@DouglasPearless
Copy link

DouglasPearless commented Dec 1, 2017 via email

@adamgreen
Copy link
Owner Author

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
Copy link

DouglasPearless commented Dec 2, 2017 via email

@adamgreen
Copy link
Owner Author

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
Copy link

DouglasPearless commented Dec 2, 2017 via email

@VladasZ
Copy link

VladasZ commented Dec 17, 2018

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

@adamgreen
Copy link
Owner Author

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

@VladasZ
Copy link

VladasZ commented Dec 18, 2018

@adamgreen Thank you.

@adamgreen
Copy link
Owner Author

This project is no longer under active development.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants