The mbed maze

October 29, 2015

Mbed and Fedora arm-none-eabi

Getting started is simple

I decided to take a look at mbed, since it looks like it is going to rule the class of chips around Cortex M3/M4 that don't have enough resources to run Linux.

Mbed clearly has a long history and, well, some "changes in direction".

First the good news, I bought a Freescale K64F eval board, they have done a great job making it easy to work with. Actually the board has the Cortex M4 that was expected, and a second Cortex M4 physical chip who acts as a JTAG and other management interface. So it actually has a JTAG TAP controller built on the board and already connected. As we'll see that comes in handy.

Connectivity-wise it presents as a USB composite device and one of the members of that is Mass Storage, you just mount it (VFAT) and cp your binary file there, it flashes it (literally, it flashes an LED while it does it) and then you reset it into the new firmware.

(There seems to be a "bootloader" concept that needed updating to "support mbed"... the update worked OK but I have no idea what that's about yet, or which Cortex chip took that update).

Another of the composite members is an ACM "modem" (ie, serial port) that's supposedly useful for debugging.

There's a nice getting started page that explains this linked to from a file on the mass storage device.

Problem 1, "hello world" doesn't print anything

I can't tell if ttyACM works or not, because the canonical "hello world" binary just flashes an LED. Well then we can just put a printf or something in "hello world", right? ----->

Problem 2, how are you meant to build things in mbed?

Mbed has been around a while and there is evidence of "geological strata" in Google about how you are supposed to actually use it.

Originally it had a concept around running the build system serverside, so you would paste your C into your browser and it would give you back a binary file. Although that's quite an interesting way to deal with building casually, it doesn't seem very scaleable and I am sure the many people making proprietary software weren't too keen on continuously sending all their sources over the internet.

So that seems to have died, and if you clone the mbed github https://github.com/mbedmicro/mbed, he has a list of 7 toolchains he supposedly supports, actually 5 of the 7 are some form of GCC, but still.

And if you believe that README there are dozens of boards that it supports, however after much googling you will find that is what they now call "mbed classic".

The new shiny mbed that is completely different, invalidating all the accreted google knowledge, is "mbed3". Although a lot of the knowledge the mbed formus and google accreted was of limited usefulness, eg

http://forums.mbed.com/t/mbed-os-what-does-it-really-mean/477

What this means is when googling, you have to first categorize what you're looking at as to if it is related to mbed3 or not. If "not", it's just going to confuse you. The right starting point for mbed3 is here -->

https://docs.mbed.com/docs/getting-started-mbed-os/en/latest/FirstProjectmbedOS/

Yotta

Yotta is the new mbed3 python-based build-and-package-management system. I think this is a good move, because the previous mbed seemed to have a huge job cut out supporting many different compilers and IDEs. Yotta seems to take config plugins that are each in their own git repo to configure it for the various toolchains. Yotta is fundamentally doing the job of "make". It has concepts like "yotta clean", "yotta build"... I guess as I see more of it, it might become apparent why something new got created.

I was able to install it by following the docs and the provided Fedora-specific dependency install stuff. But I was surprised the first time I set the target, he wants me to log in to yotta.mbed.com with a verified email. That's quite a cultural difference compared to, eg, github that they also use and integrate with. Their default license is Apache, but this "public repo" wants a verified email, I am not quite sure of the logic of that.

Yotta builds something...

However once I told it my target was frdm-k64f-gcc, in one step it (as suggested by the target name) also understood it should be using the gcc toolchain. Like Ubuntu, Fedora also has a handy prepackaged prebuilt arm-eabi-none toolchain and associated newlib you can just install, so this seems pretty sane.

After that I cut and pasted the 10-line new mbed3 hello world code that actually prints something on serial as well as flash the LED, and it nearly built.

It got confused because the build system it uses, ninja, has the executable name "ninja-build" on Fedora, not "ninja" that it was expecting. I just symlinked to it

$ sudo ln -sf /usr/bin/ninja-build /usr/bin/ninja

and it completed the build, but with warnings

$ yotta build
info: generate for target: frdm-k64f-gcc 0.2.0 at /home/agreen/projects/mbed/test1/yotta_targets/frdm-k64f-gcc
GCC version is: arm-none-eabi-g++ (Fedora 5.2.0-2.fc22) 5.2.0
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


-- Configuring done
-- Generating done
-- Build files have been written to: /home/agreen/projects/mbed/test1/build/frdm-k64f-gcc
[88/131] Building C object ym/mbed-hal...lities/src/fsl_os_abstraction_mbed.c.o
In file included from /home/agreen/projects/mbed/test1/yotta_modules/mbed-hal-ksdk-mcu/source/TARGET_KSDK_CODE/utilities/src/fsl_os_abstraction_mbed.c:19:0:
/home/agreen/projects/mbed/test1/yotta_modules/mbed-drivers/mbed/wait_api.h:19:2: warning: #warning mbed/wait_api.h is deprecated. Please use mbed-drivers/wait_api.h instead. [-Wcpp]
 #warning mbed/wait_api.h is deprecated.  Please use mbed-drivers/wait_api.h instead.
  ^
[130/131] Building CXX object source/C...n/projects/mbed/test1/source/app.cpp.o
In file included from /home/agreen/projects/mbed/test1/source/app.cpp:1:0:
/home/agreen/projects/mbed/test1/yotta_modules/mbed-drivers/mbed/mbed.h:19:2: warning: #warning mbed/mbed.h is deprecated. Please use mbed-drivers/mbed.h instead. [-Wcpp]
 #warning mbed/mbed.h is deprecated.  Please use mbed-drivers/mbed.h instead.
  ^
[131/131] Linking CXX executable source/test1

Well they said mbed3 was just in beta, these don't seem fatal. It generated a .bin file down ./build.

Actually that was all pretty painless.

Problem 3: ... it built but doesn't boot

I copied it to the mass storage mountpoint and umounted, but it just sits there not flashing an LED.

As I mentioned at the beginning, this Freescale K64F board is very cool, he has an OpenOCD compatible companion chip already wired up to the main chip's JTAG. So it is very easy to start up some Jtag-fuelled GDB necromancy on its dead body.

[root@localhost test1]# yt debug test1
info: found test1 at source/test1
info: preparing PyOCD gdbserver...
info: finding connected board...
info: new board id detected: 02400201A0BA1E755D44E3CD
info: board allows 5 concurrent packets
info: DAP SWD MODE initialised
info: IDCODE: 0x2BA01477
info: K64F not in secure state
info: 6 hardware breakpoints, 4 literal comparators
info: CPU core is Cortex-M4
info: FPU present
info: 4 hardware watchpoints
info: starting PyOCD gdbserver...
info: Telnet: server started on port 4444
info: GDB server started at port:3333
GNU gdb (GDB) 7.6.2
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-unknown-linux-gnu --target=arm-none-eabi".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /root/test1/build/frdm-k64f-gcc/source/test1...done.
info: One client connected!
HardFault_Handler ()
    at /home/agreen/projects/mbed/test1/yotta_modules/mbed-hal-k64f/source/bootstrap_gcc/startup_MK64F12.S:259
259 /home/agreen/projects/mbed/test1/yotta_modules/mbed-hal-k64f/source/bootstrap_gcc/startup_MK64F12.S: No such file or directory.
(gdb) 

Hmm OK well I am running this on an intermeidary laptop that is physically close to the board, unlike my build machine so I missed copying some files. But looking at line 259, it's the debugging interrupt itself. So I tried gdb backtrace

(gdb) bt
#0  HardFault_Handler ()
    at /home/agreen/projects/mbed/test1/yotta_modules/mbed-hal-k64f/source/bootstrap_gcc/startup_MK64F12.S:259
#1  <signal handler called>
#2  _GLOBAL__sub_I___cxa_allocate_exception ()
    at ../../../../gcc-5.2.0/libstdc++-v3/libsupc++/eh_alloc.cc:307
#3  0x0000773e in __libc_init_array ()
    at ../../../../../../newlib/libc/misc/init.c:41
#4  0x00001ac0 in _start () at ../../../../../libgloss/arm/crt0.S:416

#5  0x00001ac0 in _start () at ../../../../../libgloss/arm/crt0.S:416
#6  0x00001ac0 in _start () at ../../../../../libgloss/arm/crt0.S:416
#7  0x00001ac0 in _start () at ../../../../../libgloss/arm/crt0.S:416
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
(gdb) 

Uhhhh he blew up while trying to init an array in newlib? I installed the matching newlib sources and line 41 in init.c there is calling an array of init functions that seem to be in its own hidden section.

Fedora arm-none-eabi-newlib package did not provide a couple of _nano library variants, for libc++ and libsupc++.... I symlinked them to the non-nano versions of the library. But it seems that will not fly... well it sounded a bit risky, but things linked without errors. Anyway it has to be solved another way, but the root cause for this problem in Fedora turned out to be interesting.

Ubuntu is not the only distro...

The mbed stuff basically assumes you got your toolchain from Ubuntu's gcc-arm-none-eabi package, like this

https://launchpad.net/ubuntu/+source/gcc-arm-none-eabi/15:4.9.3+svn227297-1

however Fedora does have his own arm-none-eabi-newlib package. I downloaded the source RPM and compared it to what's in the specfile for the RPM. There are differences but since the Fedora one is able to generate the non-nano libc++.a and _nano versions of some libraries, clearly the actual problem was something a bit subtle. After poking around in there for a while I noticed a renaming hack in the build scripting preparing the libs it's interested in into the right install place. However hacking that and rebuilding the RPM from scratch did not help nor checking the build flags used in the Ubuntu package generated the C++ libraries.

The actual differences with _nano libraries

Finally I realized although these are from newlib, newlib and the compiler have a very complicated and messy elationship: the missing libraries are packaged in arm-none-eabi-gcc-cs, and any fixing will have to be done in that package.

Googling around I found Arch had the same problem a while ago, and found their packaging delta used to solve it:

https://projects.archlinux.org/svntogit/community.git/commit/trunk?h=packages/arm-none-eabi-gcc&id=628c8cbc26ee5773937615f91a79a65819cbdc9a

Basically this _nano malarky for libstdc++ and libsupc++ boils down to one different compiler option: -fno-exceptions. But in order to get that, we have to rebuild the whole gcc toolchain again, then patch in just those two .a archives into the binary RPM.

So we learned something about the _nano.a libc++ libraries.

I got the Fedora arm-none-eabi-gcc-cs source rpm, unpacked it, and edited the spec file to build twice to different places, and set it going up to the packaged file install to DESTDIR phase (-bi). After letting it build once and seeing what it installed in DESTDIR, I added some shellscript to transfer just the libstdc++ and libsupc++ .a's as _nano.a versions to the main DESTDIR.

The final diff is

--- a/arm-none-eabi-gcc-cs.spec 2015-10-30 10:09:04.605086992 +0800
+++ b/arm-none-eabi-gcc-cs.spec 2015-10-30 13:11:01.587794224 +0800
@@ -91,8 +91,12 @@


 %build
-mkdir -p gcc-%{target}
+mkdir -p gcc-%{target} gcc-nano-%{target}
+
+#### normal version
+
 pushd gcc-%{target}
+
 CC="%{__cc} ${RPM_OPT_FLAGS}  -fno-stack-protector" \
 ../gcc-%{gcc_ver}/configure --prefix=%{_prefix} --mandir=%{_mandir} \
   --with-pkgversion="Fedora %{version}-%{release}" \
@@ -127,6 +131,48 @@
 %endif
 popd

+######### nano version
+
+pushd gcc-nano-%{target}
+
+export CFLAGS_FOR_TARGET="$CFLAGS_FOR_TARGET -fno-exceptions"
+export CXXFLAGS_FOR_TARGET="$CXXFLAGS_FOR_TARGET -fno-exceptions"
+
+CC="%{__cc} ${RPM_OPT_FLAGS}  -fno-stack-protector " \
+../gcc-%{gcc_ver}/configure --prefix=%{_prefix} --mandir=%{_mandir} \
+  --with-pkgversion="Fedora %{version}-%{release}" \
+  --with-bugurl="https://bugzilla.redhat.com/" \
+  --infodir=%{_infodir} --target=%{target} \
+  --enable-interwork --enable-multilib \
+  --with-python-dir=%{target}/share/gcc-%{version}/python \
+  --with-multilib-list=armv6-m,armv7-m,armv7e-m,armv7-r \
+    --enable-plugins \
+    --disable-decimal-float \
+    --disable-libffi \
+    --disable-libgomp \
+    --disable-libmudflap \
+    --disable-libquadmath \
+    --disable-libssp \
+    --disable-libstdcxx-pch \
+    --disable-nls \
+    --disable-shared \
+    --disable-threads \
+    --disable-tls \
+%if %{bootstrap}
+   --enable-languages=c --with-newlib --disable-nls --disable-shared --disable-threads --with-gnu-as --with-gnu-ld --with-gmp --with-mpfr --with-mpc --without-headers --with-system-zlib
+%else
+   --enable-languages=c,c++ --with-newlib --disable-nls --disable-shared --disable-threads --with-gnu-as --with-gnu-ld --with-gmp --with-mpfr --with-mpc --with-headers=/usr/%{target}/include --with-system-zlib
+%endif
+#  --enable-lto \
+
+%if %{bootstrap}
+make all-gcc  INHIBIT_LIBC_CFLAGS='-DUSE_TM_CLONE_REGISTRY=0'
+%else
+make  INHIBIT_LIBC_CFLAGS='-DUSE_TM_CLONE_REGISTRY=0'
+%endif
+popd
+
+

 %install
 pushd gcc-%{target}
@@ -138,6 +184,25 @@
 make install DESTDIR=$RPM_BUILD_ROOT
 %endif
 popd
+
+##### nano version
+
+pushd gcc-nano-%{target}
+mkdir -p $RPM_BUILD_ROOT/nano
+make install DESTDIR=$RPM_BUILD_ROOT/nano
+pushd $RPM_BUILD_ROOT/nano
+for i in libstdc++.a libsupc++.a ; do
+   find . -name "$i" | while read line ; do
+       R=`echo $line | sed "s/\.a/_nano\.a/g"`
+       echo "$RPM_BUILD_ROOT/nano/$line -> $RPM_BUILD_ROOT/$R"
+       cp $line $RPM_BUILD_ROOT/$R
+   done 
+done
+popd
+
+rm -rf $RPM_BUILD_ROOT/nano
+popd
+
 # we don't want these as we are a cross version
 rm -r $RPM_BUILD_ROOT%{_infodir}
 rm -r $RPM_BUILD_ROOT%{_mandir}/man7

After upgrading to the RPMs created by the modified specfile, the missing libstdc++_nano.a and libsupc++_nano.a libraries get installed properly.

Yotta can link against them... and the LED flashes on the target.

End result of initial mbed "Getting Started"

Next post about mbed