high12noon blog

Adventures with NuttX

Back to main page

This page is a work in progress. I am documenting my adventures with the Real Time Operating System (RTOS) NuttX in "Real Time" as I learn the system. Last updated March 31st, 2021.

Table of Contents

Video: NuttX RTOS Beginnings

This is a video of a presentation by Gregory Nutt, the creator of NuttX, at the recent NuttX 2019 International Workshop at Gouda, South Holland.

Conventions Used In This Article

In this article, $HOME will refer to the Linux user's home directory (/home/your-user-name-here).

$TOPDIR will refer to the NuttX RTOS source repository's top-level directory. We'll clone several NuttX-related Git repositories under $HOME/NuttX, so $TOPDIR would resolve to $HOME/NuttX/nuttx in our case.

July 11, 2019: The Adventure Begins

Okay, so I have a cacophony of different microcontroller architectures around here, including: formerly Atmel now Microchip AVR and XMega, Microchip PIC32 (MIPS core), Texas Instruments Tiva-C Series (TM4C12x, ARM core), ST Microelectronics STM32 (ARM core), and probably a few others that have fallen by the wayside. And I also write programs for the PC side of things.

The problem with writing programs for all these different chips is that the programming is different and non-portable between them. That goes for low-level stuff like register programming to operate the various on-chip peripherals as well as high-level stuff like network or USB support.

The different hardware vendors have tried to address portability by implementing software libraries, but generally this is only good within one part family. It's not helpful if your next board uses a different vendor's part.

Why not stick with just one part family then? Well I've tried that. But it's not realistic. Every project has different requirements and ultimately you have to pick the MCU that best fits the requirements.

So recenty I discovered a RTOS called NuttX. It's been around for well over a decade, supports chips from all the part families I mentioned (and then some), has some features I consider very interesting, and comes with a permissive open-source-friendly and business-friendly BSD license. Whether NuttX is the answer to my microcontroller software needs is something I don't know yet, but I've decided to document my adventures...

Getting Started

I have Mac, Windows, and Linux (among others) available to me. The NuttX documentation states that the development environment must be POSIX such as Linux or macOS. It could be Windows if a POSIX layer is installed, such as Cygwin, MSYS, MSYS2, Ubuntu/Bash shell on Windows 10, etc. But it looked to me like the path of least resistance would be to go with Linux. I might try on the other operating systems in the future and document that as well... we'll see.

My preferred Linux distribution is Debian because it's arguably the biggest one in terms of distribution. It seems like most Linux distributions are based on Debian (including Ubuntu and all the ones that are based on it). Debian just released Debian 10 "Buster" but I am still using Debian 9 "Stretch."

In my home directory I made a directory to hold all the NuttX stuff:

$ mkdir NuttX
$ cd NuttX

NuttX and related things come in a bunch of different Git repos hosted on BitBucket.

(On a side note, I've seen projects get split across multiple repositories before; one of these days in my writings on Version Control I'll explain why that's less than optimal. I will say, here, that I strongly prefer Apache Subversion over Git because Subversion is both more capable and much simpler and easier to use than Git. That's a subject for another day.)

Anyway so I cloned the Git repos:

$ git clone https://bitbucket.org/nuttx/nuttx.git
$ git clone https://bitbucket.org/nuttx/apps.git
$ git clone https://bitbucket.org/nuttx/buildroot.git
$ git clone https://bitbucket.org/nuttx/tools.git
$ git clone https://bitbucket.org/nuttx/pascal.git
$ git clone https://bitbucket.org/nuttx/uclibc.git

I don't know if there are others but I wanted to have all the code available on my system.

Now to get something built.

I have a Texas Instruments (TI) Tiva C Series Crypto Connected LaunchPad, specifically called EK-TM4C129EXL, so I wanted to build NuttX for it. The latest NuttX release at this writing, 7.30, does not contain a port for that specific board but does contain one for the similar Tiva C Series Connected LaunchPad, EK-TM4C1294XL. So I thought I'd start with that.

$ cd $HOME/NuttX/nuttx
$ tools/configure.sh -l tm4c1294-launchpad/nsh

And I was met with an error related to lack of kconfig-conf.

After some searching, I found this page and this page, which led me to install some additional Linux packages that I was missing:

$ sudo apt-get install \
      bison \
      flex \
      gperf \
      libgmp-dev \
      libmpc-dev \
      libmpfr-dev \
      libisl-dev \
      binutils-dev \
      libelf-dev \

(My system has numerous other packages on it which are related to development. I'll try to update this page later with all the ones needed, from a default Debian install, to work with NuttX.)

Even after installing all that stuff, kconfig-conf remained missing. After more searching I discovered that this tool is actually packaged with NuttX, in the "tools" repository. I had it under my $HOME/NuttX/tools/kconfig-frontends). So...

$ cd $HOME/NuttX/tools/kconfig-frontends
$ ./configure --enable-mconf --disable-gconf --disable-qconf
$ make
$ sudo make install

Back in $HOME/NuttX/nuttx, when I tried to use it:

cd $HOME/NuttX/nuttx
$ tools/configure.sh -l tm4c1294-launchpad/nsh

It failed with:

kconfig-mconf: error while loading shared libraries: libkconfig-parser-3.8.0.so:
cannot open shared object file: No such file or directory
make: *** [menuconfig] Error 127

I found a clue in $HOME/NuttX/tools/README.txt, under "kconfig-mconf Path Issues" where it mentioned that exact error. It turns out that ld didn't know where to find the shared library. There's a file called /etc/ld/so.conf that lists places ld should search, but ld doesn't read that file; you have to run ldconfig as root to make those settings take effect. It turns out that kconfig-conf was installed in /usr/local/bin, the library was installed in /usr/local/lib, and /etc/ld.so.conf did have /usr/local/lib in it (via /etc/ld.so.conf.d/libc.conf). I ran ldconfig as root and the problem went away:

$ sudo ldconfig

Having successfully configured NuttX for this board, I now needed a toolchain.

$ cd $HOME/NuttX/buildroot
$ cp configs/cortexm4f-eabi-defconfig-7.3.0 .config
$ make menuconfig
$ make

Well, that ran for a while but failed somewhere in the middle because texinfo wasn't installed. So:

$ sudo apt-get install texinfo
$ make

After a while, that succeeded.

To be continued! I'm going to call it quits for today. Let's recap where we are so far. I have cloned all the NuttX repositories into a NuttX directory under my home directory. I installed a bunch of needed packages and need to come back and make an exhaustive list. I built an ARM Cortex M4F EABI toolchain using the NuttX-provided buildroot, and now I think I'm ready to start building NuttX to run a test on my LaunchPad. Check back for more and feel free to write me with questions, comments, suggestions, criticisms, etc., at high12noon (the name of this blog), at mail, dot com.

July 18, 2019: The Adventure Continues

Building NuttX:

$ cd $HOME/NuttX/nuttx
$ export TOOLCHAIN_BIN=(path to buildroot binaries)
$ make menuconfig

In make menuconfig, make sure System type, Toolchain selection is set to buildroot.

$ make

This ran for a surprisingly short time! I expected a lengthy build given the size of the repository and the sheer number of source files. But then again, this is an operating system for very resource constrained devices and therefore it stands to reason that only a fraction of that code actually gets built.

It produced the files nuttx and nuttx.bin under $HOME/NuttX/nuttx.

Now, to get the code flashed to my microcontroller...

After my first post on July 11, 2019, and this one a week later, I found a bunch of resources regarding NuttX specifically, toolchains, developing for microcontrollers on Linux, etc. Until now, my development has always taken place on a Windows platform using MCU vendor-supplied IDE (Integrated Development Environments, usually based on Eclipse, NetBeans, MS Visual Studio, or a custom interface). This is the first time that I really have to get into the nitty gritty of getting all these different details setup and working. Suddenly compiling, flashing, and debugging are separate things supplied by separate unrelated pieces of software. That's why this is an adventure!

Among other things, I watched some videos on the NuttX YouTube channel, including:

I also watched the following:

I opted to build OpenOCD (Open On Chip Debugger) from source as shown in #001 - Setting the Development Environment for NuttX. Note that my commands below contain some modification to the commands shown in the video based on differences in my Linux install (such as installed packages) and the newer available version of OpenOCD since the video was made.

First I needed these packages:

$ sudo apt-get install \
  minicom \
  libncurses5-dev \
  libusb-dev \

Clone the OpenOCD Git repository:

$ cd $HOME/NuttX
$ git clone http://repo.or.cz/r/openocd.git
$ cd openocd/
$ ./bootstrap

There are many options. To list them all:

$ ./configure --help

This is how I configured it:

$ ./configure \
  --enable-internal-jimtcl \
  --enable-maintainer-mode \
  --disable-werror \
  --disable-shared \
  --enable-stlink \
  --enable-ti-icdi \
  --enable-xds110 \
  --enable-jlink \
  --enable-rlink \
  --enable-vsllink \
$ make
$ sudo make install
$ sudo cp contrib/60-openocd.rules /etc/udev/rules.d/
$ sudo udevadm control --reload

With the board NOT connected to the computer's USB port:

$ lsusb

Showed a bunch of USB devices.

I connected the board to the computer's USB port and:

$ lsusb

Showed a bunch of USB devices, which now included (on my computer):

Bus 001 Device 005: ID 1cbe:00fd Luminary Micro Inc. In-Circuit Debug Interface

Starting up OpenOCD requires either a bunch of command line options or some configuration files that encapsulate the needed options.

According to the OpenOCD documentation, if no configuration files or commands are given on the command line (that is, no -f or -c options), OpenOCD will try to read a configuration file called openocd.cfg by default. In any event, it searches for the configuration file(s) at the following locations, until it finds one with the name it's looking for:

My computer didn't have a .openocd directory under $HOME. I guessed that pkgdatadir would be something like /usr/local/share/openocd/scripts so:

$ ls /usr/local/share/openocd/scripts/interface


altera-usb-blaster2.cfg  imx-native.cfg           stlink.cfg
altera-usb-blaster.cfg   jlink.cfg                stlink-v1.cfg
arm-jtag-ew.cfg          jtag_vpi.cfg             stlink-v2-1.cfg
at91rm9200.cfg           kitprog.cfg              stlink-v2.cfg
buspirate.cfg            nds32-aice.cfg           sysfsgpio-raspberrypi.cfg
calao-usb-a9260.cfg      opendous.cfg             ti-icdi.cfg
chameleon.cfg            openjtag.cfg             ulink.cfg
cmsis-dap.cfg            osbdm.cfg                usb-jtag.cfg
dummy.cfg                parport.cfg              usbprog.cfg
estick.cfg               parport_dlc5.cfg         vsllink.cfg
flashlink.cfg            raspberrypi2-native.cfg  xds110.cfg
ft232r.cfg               raspberrypi-native.cfg
ftdi                     rlink.cfg


$ ls /usr/local/share/openocd/scripts/target


1986ве1т.cfg                       lpc1xxx.cfg
adsp-sc58x.cfg                     lpc2103.cfg
aduc702x.cfg                       lpc2124.cfg
aducm360.cfg                       lpc2129.cfg
allwinner_v3s.cfg                  lpc2148.cfg
alphascale_asm9260t.cfg            lpc2294.cfg
altera_fpgasoc_arria10.cfg         lpc2378.cfg
altera_fpgasoc.cfg                 lpc2460.cfg
am335x.cfg                         lpc2478.cfg
am437x.cfg                         lpc2900.cfg
amdm37x.cfg                        lpc2xxx.cfg
ar71xx.cfg                         lpc3131.cfg
armada370.cfg                      lpc3250.cfg
arm_corelink_sse200.cfg            lpc40xx.cfg
at32ap7000.cfg                     lpc4350.cfg
at91r40008.cfg                     lpc4357.cfg
at91rm9200.cfg                     lpc4370.cfg
at91sam3ax_4x.cfg                  lpc84x.cfg
at91sam3ax_8x.cfg                  lpc8nxx.cfg
at91sam3ax_xx.cfg                  lpc8xx.cfg
at91sam3nXX.cfg                    ls1012a.cfg
at91sam3sXX.cfg                    marvell
at91sam3u1c.cfg                    max32620.cfg
at91sam3u1e.cfg                    max32625.cfg
at91sam3u2c.cfg                    max3263x.cfg
at91sam3u2e.cfg                    mc13224v.cfg
at91sam3u4c.cfg                    mdr32f9q2i.cfg
at91sam3u4e.cfg                    nds32v2.cfg
at91sam3uxx.cfg                    nds32v3.cfg
at91sam3XXX.cfg                    nds32v3m.cfg
at91sam4c32x.cfg                   nhs31xx.cfg
at91sam4cXXX.cfg                   nrf51.cfg
at91sam4lXX.cfg                    nrf51_stlink.tcl
at91sam4sd32x.cfg                  nrf52.cfg
at91sam4sXX.cfg                    nuc910.cfg
at91sam4XXX.cfg                    numicro.cfg
at91sam7a2.cfg                     omap2420.cfg
at91sam7se512.cfg                  omap3530.cfg
at91sam7sx.cfg                     omap4430.cfg
at91sam7x256.cfg                   omap4460.cfg
at91sam7x512.cfg                   omap5912.cfg
at91sam9260.cfg                    omapl138.cfg
at91sam9260_ext_RAM_ext_flash.cfg  or1k.cfg
at91sam9261.cfg                    pic32mx.cfg
at91sam9263.cfg                    psoc4.cfg
at91sam9.cfg                       psoc5lp.cfg
at91sam9g10.cfg                    psoc6.cfg
at91sam9g20.cfg                    pxa255.cfg
at91sam9g45.cfg                    pxa270.cfg
at91sam9rl.cfg                     pxa3xx.cfg
at91samdXX.cfg                     qualcomm_qca4531.cfg
at91samg5x.cfg                     quark_d20xx.cfg
atheros_ar2313.cfg                 quark_x10xx.cfg
atheros_ar2315.cfg                 readme.txt
atheros_ar9331.cfg                 renesas_r7s72100.cfg
atheros_ar9344.cfg                 renesas_r8a7790.cfg
atmega128.cfg                      renesas_r8a7791.cfg
atmega128rfa1.cfg                  renesas_r8a7794.cfg
atsame5x.cfg                       renesas_rcar_gen3.cfg
atsaml1x.cfg                       renesas_s7g2.cfg
atsamv.cfg                         samsung_s3c2410.cfg
avr32.cfg                          samsung_s3c2440.cfg
bcm281xx.cfg                       samsung_s3c2450.cfg
bcm4706.cfg                        samsung_s3c4510.cfg
bcm4718.cfg                        samsung_s3c6410.cfg
bcm47xx.cfg                        sharp_lh79532.cfg
bcm5352e.cfg                       sim3x.cfg
bcm6348.cfg                        smp8634.cfg
bluenrg-x.cfg                      spear3xx.cfg
c100.cfg                           stellaris.cfg
c100config.tcl                     stellaris_icdi.cfg
c100helper.tcl                     stm32f0x.cfg
c100regs.tcl                       stm32f0x_stlink.cfg
cc2538.cfg                         stm32f1x.cfg
cs351x.cfg                         stm32f1x_stlink.cfg
davinci.cfg                        stm32f2x.cfg
dragonite.cfg                      stm32f2x_stlink.cfg
dsp56321.cfg                       stm32f3x.cfg
dsp568013.cfg                      stm32f3x_stlink.cfg
dsp568037.cfg                      stm32f4x.cfg
efm32.cfg                          stm32f4x_stlink.cfg
efm32_stlink.cfg                   stm32f7x.cfg
em357.cfg                          stm32h7x.cfg
em358.cfg                          stm32h7x_dual_bank.cfg
epc9301.cfg                        stm32l0.cfg
esi32xx.cfg                        stm32l0_dual_bank.cfg
exynos5250.cfg                     stm32l1.cfg
faux.cfg                           stm32l1x_dual_bank.cfg
feroceon.cfg                       stm32l4x.cfg
fm3.cfg                            stm32lx_stlink.cfg
fm4.cfg                            stm32_stlink.cfg
fm4_mb9bf.cfg                      stm32w108_stlink.cfg
fm4_s6e2cc.cfg                     stm32w108xx.cfg
gp326xxxa.cfg                      stm32xl.cfg
hi3798.cfg                         stm8l152.cfg
hi6220.cfg                         stm8l.cfg
hilscher_netx10.cfg                stm8s003.cfg
hilscher_netx500.cfg               stm8s105.cfg
hilscher_netx50.cfg                stm8s.cfg
icepick.cfg                        str710.cfg
imx21.cfg                          str730.cfg
imx25.cfg                          str750.cfg
imx27.cfg                          str912.cfg
imx28.cfg                          swj-dp.tcl
imx31.cfg                          test_reset_syntax_error.cfg
imx35.cfg                          test_syntax_error.cfg
imx51.cfg                          ti-ar7.cfg
imx53.cfg                          ti_calypso.cfg
imx6.cfg                           ti_cc13x0.cfg
imx6sx.cfg                         ti_cc13x2.cfg
imx6ul.cfg                         ti_cc26x0.cfg
imx7.cfg                           ti_cc26x2.cfg
imx7ulp.cfg                        ti_cc3220sf.cfg
imx8m.cfg                          ti_cc32xx.cfg
imx.cfg                            ti-cjtag.cfg
is5114.cfg                         ti_dm355.cfg
ixp42x.cfg                         ti_dm365.cfg
k1921vk01t.cfg                     ti_dm6446.cfg
k40.cfg                            ti_msp432.cfg
k60.cfg                            ti_rm4x.cfg
ke0x.cfg                           ti_tms570.cfg
ke1xf.cfg                          ti_tms570ls20xxx.cfg
ke1xz.cfg                          ti_tms570ls3137.cfg
kl25.cfg                           tmpa900.cfg
kl25z_hla.cfg                      tmpa910.cfg
kl46.cfg                           u8500.cfg
klx.cfg                            vybrid_vf6xx.cfg
ks869x.cfg                         xilinx_zynqmp.cfg
kx.cfg                             xmc1xxx.cfg
lpc11xx.cfg                        xmc4xxx.cfg
lpc12xx.cfg                        xmos_xs1-xau8a-10_arm.cfg
lpc13xx.cfg                        zynq_7000.cfg
lpc17xx.cfg                        к1879xб1я.cfg

When I tried to start OpenOCD with:

$ openocd -f interface/ti-icdi.cfg -f target/stellaris.cfg

it didn't work. After some searching, I somehow figured out to start it like this:

$ openocd -f interface/ti-icdi.cfg -c "transport select hla_jtag" -f target/stellaris.cfg
Open On-Chip Debugger 0.10.0+dev-00921-g263deb38 (2019-07-18-17:17)
Licensed under GNU GPL v2
For bug reports, read
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : clock speed 21847 kHz
Info : ICDI Firmware version: 1224
Info : lm3s.cpu: hardware has 6 breakpoints, 4 watchpoints
Info : Listening on port 3333 for gdb connections

And of course I have no idea if that's the right way to do it but it seems to indicate that it connected to the board and is able to communicate.

To be continued! Once again I'm going to call it quits for the day... So far, I have cloned all the NuttX repositories and the OpenOCD repository into a NuttX directory under my home directory. I installed all kinds of needed packages and still need to come back and make that exhaustive list I promised. I built an ARM Cortex M4F EABI toolchain using the NuttX-provided buildroot. I built the NuttX nsh (Nutt Shell) example for TM4C1294 (which is very similar to the TM4C129ENCPDT on my EK-TM4C129EXL Crypto Connected LaunchPad). I built OpenOCD from source and I think it's actually communicating with my board. Check back for more and feel free to write me with questions, comments, suggestions, criticisms, etc., at the name of this blog, which is high12noon, of course, at mail dot com.

July 21, 2019: Using Code::Blocks IDE

Code::Blocks is a free, open source, cross platform, Integrated Development Environment (IDE). It is cross platform and is written with a graphics toolkit I like very much, wxWidgets. Also, it is much lighter weight than Eclipse.

Last time I built OpenOCD from source in preparation to use Code::Blocks IDE to edit, compile, flash program, and single-step debug NuttX. I even built NuttX successfully on the command line but sadly I didn't document it here. I think it was pretty straightforward. The only important thing was to set the PATH environment variable so that make could find the toolchain I built with buildroot. Once I did that, NuttX built.

But I like to work in an IDE. So I watched the following videos:

So I configured Code::Blocks approximately as described in those videos:

I installed Code::Blocks with:

$ sudo apt-get install codeblocks codeblocks-contrib

The NuttX Channel video did not show installing codeblocks-contrib but I thought what the heck, I might as well.

Once Code::Blocks was installed, I ran it and began configuring it to use the buildroot-based GCC ARM compiler and OpenOCD tools that I built earlier, as shown in the above-mentioned NuttX Channel video. I will repeat the steps I took (as well as I can given my sometimes hazy memory) because I diverged in some areas and also for my future reference in case the video becomes inaccessible or something. Most of the following instructions are very similar to the video, though:

  1. From the menu, I opened "Settings" → "Debugger..." The "Debugger settings" dialog appeared. In its sidebar, I highlighted "GDB/CDB debugger" which caused three buttons to appear to the right: "Create Config," "Delete Config," and "Reset defaults." I created a new configuration using "Create Config" and named it OpenOCD. For the Executable path, I entered $HOME/NuttX/buildroot/build_arm_hf/staging_dir/bin/arm-nuttx-eabi-gdb (I actually entered the full "hardcoded" path without the $HOME variable because I don't know if that would work). I left the settings at their defaults, which were:
    • Debugger Type was set to GDB
    • Disable startup scripts (-nx) (GDB only) (checked)
    • Watch function arguments (checked)
    • Watch local variables (checked)
    • Enable watch scripts (checked)
    • Catch C++ exceptions (checked)
    • The other items were not checked.
    • As for "Choose disassembly flavor (GDB only)" I left the value "System default."
    I closed this dialog with OK.
  2. From the menu, I opened "Settings" → "Compiler..." For this step, I diverged a bit from what was shown in the video. With "Global compiler settings" highlighted in the sidebar, I set "Selected compiler" to "GNU GCC Compiler for ARM." Because I have so many different ARM-based platforms, I decided to create a specific one for NuttX and for ARM Cortex M4F. So I used the Copy button to make a copy of the GNU GCC Compiler for ARM profile and named my copy "NuttX GCC ARM Cortex M4F." I then went to the "Toolchain executables" tab and configured the compiler as follows:
    • For "Compiler's installation directory" I set: $HOME/NuttX/buildroot/build_arm_hf/staging_dir (once again I actually entered the full "hardcoded" path without the $HOME variable)
    • C compiler: arm-nuttx-eabi-gcc
    • C++ compiler: arm-nuttx-eabi-g++
    • Linker for dynamic libs: arm-nuttx-eabi-g++
    • Linker for static libs: arm-nuttx-eabi-gcc-ar
    • Debugger: GDB/CDB debugger : OpenOCD
    • Resource compiler: (left blank)
    • Make program: make
    Now, I will say that for whatever reason(s), I had trouble with Code::Blocks accepting this. I tried various things and eventually tried rebooting and redoing the setup. I'm not exactly sure whether rebooting "fixed" anything or whether I had made a typo earlier. But I kept at it and eventually Code::Blocks accepted this compiler setup. I closed the dialog with OK.
  3. I created a new empty project by going to "File" → "New" → "Project..." and selecting "Empty project" in the dialog that appeared. In the project wizard, I gave the project the title "nuttx" and placed it in the $HOME/NuttX directory, which is the parent directory of my nuttx repository. I think it was significant that the project was named nuttx with the same spelling and lowercase letters as the binary file produced by NuttX's makefile. As the above-mentioned NuttX Channel video shows, I removed the values from "Output dir" and "Objects output dir" for the Debug configuration. I renamed the Debug configuration to "all" (in the text field next to "Create 'Debug' configuration." I removed the Release configuration by removing the checkmark from "Create 'Release' configuration." I exited this dialog by clicking "Finish."
  4. In the Projects view, which by default runs down the left side of the Code::Blocks window, I right-clicked the "nuttx" project and opened Properties from the context menu. This opened the "Project/targets options" dialog. In the "Project settings" tab, I placed a checkmark at "This is a custom Makefile." I then went to the Debugger tab, as shown in the video. Under "Select target" I selected "all" and in the "Remote Connection" sub-tab (located within the "Debugger" tab) I set the IP address to (the loopback address) and port 3333. (Remember earlier, when OpenOCD said it was listening on port 3333 for gdb connections? That's why.) Then, in the Additional GDB commands sub-tab, I entered slightly different commands than shown in the video for "After connection," namely:
    • On the first line: "monitor reset init"
    • On the second line: "load nuttx"
    • On the third line, here is where we diverge from the video, I entered "b nx_start" instead of what the video shows. (The video shows "b os_start".) This command puts a breakpoint at the nx_start() function and causes the board to run to that breakpoint. It didn't work for me with os_start because, as I understood from scouring various places, the function was renamed sometime between when the video was made and now.
    I exited this dialog with OK.
  5. The video shows nuttx being configured on the command line using the tools/configure.sh script and make menuconfig. I didn't need to do this because my nuttx was already configured. Caveat: I think I did do make menuconfig to turn on debugging information and to suppress optimization. You always want to suppress optimization when single-step debugging; otherwise the debugger seems to jump all over the place for no rhyme or reason, because actually the compiler reorders instructions for best performance and/or smallest code when you optimize.
  6. The video also shows editing the linker script (in the video's case under configs/stm32f103-minimum/scripts/ld.script, but I'm using a TI TM4C129ENCPDT). If I understand correctly, the purpose of this edit was to lie to the linker about the processor's flash storage capacity. Otherwise the video maker reported that the linker was failing, presumably because debugging information made the code too big. I didn't do this and my code did link successfully without it. Of course, depending on your MCU and its size, your mileage may vary.
  7. Back in Code::Blocks, the video shows right-clicking the nuttx project in the Projects view, selecting "Add files recursively," choosing the nuttx directory, using Select All to select all the files and directories therein, and adding them to the project. This worked for me, but after doing it, the IDE started going haywire, locking up, crashing, windows not sizing correctly... I don't know why. So after several attempts, I decided to skip this step and not add any files to the IDE project. They'll still build correctly (because building is done by the makefile) and single-stepping still worked correctly, though I'll talk more about that in a moment.
  8. At this point, I built the project by going to "Build" → "Build" in the menu. NuttX built. The Code::Blocks "Build log" tab showed the same kind of output I had come to expect from building NuttX on the command line previously.
  9. Back on the command line, I started OpenOCD. This time, I used a script that comes with NuttX:
    $ $TOPDIR/configs/tm4c1294-launchpad/tools/oocd.sh $HOME/NuttX/nuttx
  10. Back in Code::Blocks, I went to "Debug" → "Start / Continue." This opened some kind of blank Xterm window, FLASH-programmed the nuttx executable to the board, and started the debugger, placing the cursor at nx_start().

The above worked, but I had a couple of problems.

First of all, single-stepping was rather slow. Specifically, single-stepping through C came with a frustrating and very noticeable delay between each step. Single-stepping through assembly was reasonably quick.

Secondly, I like how other IDEs show an easy-to-interpret gauge that tells me how much of Flash and RAM I'm using as a percentage of my MCU's Flash and RAM capacity. I couldn't figure out how to do this with Code::Blocks.

So, even though everything technically worked, I decided to try TI's Code Composer Studio (CCS). That's a job for next time.

I do like Code::Blocks and have worked with it (and still work with it) pretty extensively, so if you know of a way to speed up single-step debugging or what to do about the IDE going haywire and crashing when I added all the NuttX files to the project, please drop me a line!

July 22, 2019: Using TI's CCSv9

Previously, I had set up Code::Blocks IDE to work on NuttX and my programs for it, but I ran into an issue where single-stepping was slow and there was no memory usage gauge. So I decided to try TI's Code Composer Studio (CCS). Recently they released CCS version 9 (which I'll call CCSv9).

I started by installing CCS in my Linux machine. I went to ti.com and searched for "CCS" in the website's Search bar. Then, I selected the first search result, "Code Composer Studio (CCS) Integrated Development Environment (IDE) CCSTUDIO (ACTIVE)." From here, there was a download link. Clicking on that link took me to another page, where I could download actual files as well as read the Linux Installation Instructions. At the time of this writing, the latest version of CCS is version According to TI, they test CCS on Ubuntu LTS distributions and one CentOS distribution. All other installation instructions are provided for reference (and are sometimes contributed by community members). Despite this notice, I found that CCS installed perfectly on my Debian "Stretch" machine. Note: As far as I know, Ubuntu is based on Debian, so I think they're close cousins. I didn't have any of the potential issues mentioned on that page. Back at the download page, I downloaded the latest available Linux off-line installer, which came out to some 850 MB. I untarred this and ran the installer. I followed the screens in the graphical installers and everything went smoothly.

I opened CCS and began to setup a project to build, load, and run NuttX as follows:

In the command line, I created a directory at $HOME/NuttX/NuttxCCS to hold the TI Code Composer Studio 9 (CCSv9) project, adjacent to the nuttx and apps directories.

In CCSv9, I created a new CCS project by going to "Project" → "New CCS Project." In the dialog that appeared:

In the "Project Explorer" (by default this view appears along the left side of the CCS window), I right-clicked the NuttxCCS project and opened Properties (located all the way at the bottom of the context menu). In the Project Properties dialog that appeared (while Debug build configuration is selected), I made the following changes. Note that I've experienced CCS "forgetting" some changes when I make too many to a project, so I recommend changing a few settings, applying and closing the dialog, and then reopening it to make more changes.

Note: The following is a bit messy because I wanted to document it all as quickly as possible, before I forget the steps. At some point I plan to come back, clean this up, and improve the instructions.

Project properties dialog:

  1. Show advanced settings (link at bottom)
  2. CCS Build:
    • No checkmark on "Use default build command"
    • No checkmark on "Generate Makefiles automatically"
    • Set "Build location" → "Build directory" to "${PROJECT_LOC}/../nuttx"
    • No checkmark on "Enable parallel build"
    • No checkmark on "Build on resource save (Auto build)
    • Checkmark on Build (Incremental build) and "all" in text field.
    • Checkmark on Clean and "clean" in text field.
  3. GNU Compiler, GNU Linker, GNU Objcopy Utility: These settings have no effect on the build because it is controlled by the NuttX makefile. However, to avoid displaying misleading information, you can remove any include paths from CCS Build → GNU Compiler → Directories and any predefined preprocessor symbols from CCS Build → GNU Compiler → Preprocessor.
  4. C/C++ Build:
    • Builder type: External builder
    • Build command: make -k
    • No checkmark on "Generate Makefiles automatically"
    • Set "Build location" → "Build directory" to "${PROJECT_LOC}/../nuttx"
    • C/C++ Build → Environment: Prepend PATH with: "${ccs_install_root}/tools/compiler/gcc-arm-none-eabi-7-2017-q4-major/bin:" using that last colon as the delimiter between that and the rest of the path.
    • Settings: Binary Parsers: Check mark on Elf Parser only.
    • Settings: Error Parsers: Check marks on GNU gmake Error Parser 7.0, GNU Assembler Error Parser, GNU Linker Error Parser, and GNU gcc/g++ Error Parser.
  5. Debug:
    • Device: Stellaris In-Circuit Debug Interface_0/CORTEX_M4_0
    • Auto Run and Launch Options:
      Auto Run Options:
      • Run to symbol: nx_start
      • Check mark on "On a program load or restart"
      • Check mark on "On a reset"
  6. Run/Debug Settings:
    • Launch configurations: Select the launch configuration and Edit.
    • Program tab:
      • Device: Stellaris In-Circuit Debug Interface_0/CORTEX_M4_0
      • Project: NuttxCCS (or the project name)
      • Program: Path to the nuttx binary (e.g., $HOME/NuttX/nuttx/nuttx)
      • Loading options: Check mark on "Load program"
    • Source tab:
      • Add source lookup path, being the nuttx directory (e.g., $HOME/NuttX/nuttx)
      • Put that directory at the top of the list with the Up button.

In command line, go to nuttx $TOPDIR and:

$ make clean
$ make menuconfig

In menu config:

In CCS, Project → Clean (and perform build). If everything is configured correctly above, the project will build.

Debug: If all is configured correctly above, the project will load and run.

To get the Memory Allocation view to work, the linker needs to generate a "map" file usable by CCS. The NuttX build system produces a file called System.map but CCS cannot parse it. Therefore it is necessary to add a custom linker option. According to patacongo, "Make.defs is a part of your board and you are free to modify it as you like." The Make.defs actually used during the build process is in $TOPDIR, but it gets there by being copied when $TOPDIR/tools/configure.sh is run to select a board and configuration. So it is best to make the edit in our board's config directory (in our case that's $TOPDIR/configs/tm4c1294-launchpad/Make.defs), and then copy that over the one in $TOPDIR. Edit Make.defs and add the following at or near the bottom of the file:

LDFLAGS += -Map=$(TOPDIR)/nuttx.map

According to Chester Gillon in a post on TI's e2e forum, the CCS Memory Allocation view is hard-coded to parse a .map file located at ${BuildDirectory}/${ProjName}.map. In our case, that would be $HOME/NuttX/NuttxCCS/Debug/NuttxCCS.map. This appears to be true as of this writing with CCS Version: Since we do not know of a user-accessible setting to change it, we work around this by creating a symbolic link:

$ cd $HOME/NuttX/NuttxCCS/Debug
$ ln -s ../../nuttx/nuttx.map NuttxCCS.map

Alternately, if you don't want to create the symbolic link, you can open any (properly formatted) .map file in the Memory Allocation view: Go to that view's menu (small down-pointing triangle) and select "Open TI link-info or GNU linker-map file..." and choose the nuttx.map file, at $TOPDIR/nuttx.map (or any other .map file you wish to examine).

With CCS, I got both of the things that I found lacking in yesterday's Code::Blocks setup, namely that single-step debugging through C code was sped up considerably and I got a working Memory Allocation view that shows Flash and RAM usage as a percentage of total available on the microcontroller. Once again, I do like Code::Blocks so if you know how to speed up single-step debugging there, please let me know!

July 30, 2019: More on Using TI's CCSv9 with NuttX

Increasing Scroll Back Buffer for the CDT Build Console

CCS is based on Eclipse and uses a part of Eclipse called CDT (C Development Tools). When building, the build output (all that text from make that scrolls up the screen) is displayed in a view called Console, which shows the CDT Build Console.

I noticed that with the default settings, the NuttX build generated too much output for the CDT Build Console, so if I wanted to look near the beginning of the build output for something that might cause an error, I couldn't because it had been lost. To fix this:

  1. In the menu, open Window → Preferences.
  2. In the dialog that appears, make sure that advanced settings are displayed. If there is a link at the bottom of the dialog labeled "Show advanced settings" click it. This will show additional settings in the left sidebar of the dialog box.
  3. In the sidebar, find and expand "C/C++" → "Build" → "Console"
  4. Find the item "Limit console output (number of lines)" and set it to something larger. Mine was initially set to 500. I increased it to 20000. This setting seemed to work for me.
  5. Apply and close the dialog.

Since we are using CCS slightly differently than TI expected, it seems necessary to show advanced settings in multiple places. So far I've done that in Project Properties (described last time) and in the Preferences dialog as I just explained above. Initially, I hadn't noticed that some preferences were hidden, so when I tried to find and enlarge the console scrollback I ended up doing it for the Run/Debug console, which is something else, and I saw no improvement. Showing advanced settings and updating the setting for the C/C++ Build Console made all the difference.

Showing source files in the Project Explorer

The other improvement I made is for the project itself.

Normally, if there is a build error, it should be possible to double-click the error either in the CDT Build Console or the Problems view and CCS should open the offending source file and place the cursor on the offending line. This wasn't happening. I thought that was a bit strange because source-level debugging worked (when I built with debug information and optimizations suppressed) but it didn't work for build errors. Nor was I able to use the indexer to navigate (e.g., by right-clicking an identifier and choosing "Open Declaration").

I fixed this by adding the "nuttx" and "apps" folders to the project as Linked Folders. The way to do this is not entirely intuitive because you might be tempted to right-click the project in the Project Explorer and choose "Add Files." But apparently that's not the right way.


  1. Right-click the project in the Project Explorer and choose "New" → "Folder."
  2. Make sure the project is selected in the list (in my case it's called NuttxCCS), not "RemoteSystemsTempFiles."
  3. Click "Advanced" (notice a theme for today?)
  4. Select the radio button for "Link to alternate location (Linked Folder)"
  5. In my case, I placed the NuttxCCS directory containing the CCS project adjacent to the nuttx and apps directories. Therefore the path to nuttx is "../nuttx" relative to the project. So in the text field below "Link to alternate location" I entered:
    as the path.
  6. Make sure "Choose file system" is set to "default"
  7. Click Finish to add the linked folder.
  8. It might ask a bunch of times (once for each .cfg file it finds) if you want to enable XDCtools. Select "No" each time and be careful because the order of the No and Yes buttons are reversed! (At least on my system!)
  9. Wait for it to build its index, or whatever it's doing.
  10. Repeat the above process to add the apps directory, using
    as the path.

Now, if all went well, build errors can be double-clicked to jump straight to the offending file and line.

That's all for today! See you soon.

August 1, 2019: Even more on Using TI's CCSv9 with NuttX

Stop lengthy "Searching for Binaries"

As mentioned before, CCS is based on Eclipse.

Each time I built the project, I noticed a lengthy Eclipse task called "Searching for Binaries" running for quite some time. I wanted to stop this from bogging down my system. After a quick search, I found the answer to this one here: According to Alex Mueller:

Eclipse searches for the binaries to fill the virtual folder "Binaries" in your project (see Project Explorer). These binaries are also used when you create a Launch Configuration.

If you are using an external Makefile Eclipse does not which binaries were created by the build step. Therefore, after every build it searches the complete project for changes.

Mueller writes that you can limit the search scope. That's exactly what I want, to limit the search scope to the one file I know matters, nuttx. So I followed Mueller's instructions to go to "Project Properties" → "C/C++ General" → "Paths and Symbols" → the "Output location" tab. There is a tree view titled "Output folders on build path" containing search locations. There was only one item in the list: "NuttxCCS/nuttx" with an arrow indicating the item can be expanded. Expanding this item reveals a filter, which was initially empty. I highlighted it, clicked "Edit Filter..." and added multiple items: Everything in the nuttx directory except the nuttx binary itself.

Having made this change, I built the project and there was no lengthy "Searching for Binaries"—in fact the search was pretty much instantaneous! When it comes to computers, I like speed!

Stay tuned for more!

September 3, 2019: Seeing how make invokes the compiler

It happened a few times that I needed to see exactly how make was invoking the compiler.

Normally, only something like this is printed to the console:

CC:  name_of_file.c

But I need to see how the compiler was actually invoked, as in what command line arguments it received.

Googling around, I found all sorts of advice, such as passing --debug=j to make, etc., but it didn't work in this case.

After some experimentation and more searching, I figured out that what I wanted could be achieved by passing a V=1 argument to make:

$ make V=1

Now it prints all kinds of details, like this:

CC:  name_of_file.c
arm-none-eabi-gcc -c -fno-builtin -funwind-tables -Wall -Wstrict-prototypes -Wshadow -Wundef -g -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard -I. -isystem /home/builder/NuttX/nuttx/include  -D__KERNEL__ -ffunction-sections -fdata-sections -pipe -fdebug-prefix-map=..= -I/home/builder/NuttX/nuttx/sched -I/home/builder/NuttX/nuttx/arch/arm/src/chip -I/home/builder/NuttX/nuttx/arch/arm/src/common -I/home/builder/NuttX/nuttx/arch/arm/src/armv7-m  name_of_file.c -o  name_of_file.o

December 10, 2019: NuttX to become an Apache Software Foundation (ASF) Project

This isn't so much a technical update as a bit of news. Until the present time, NuttX has been a project run almost exclusively by one person, Gregory Nutt. With support for myriad processor architecture and microcontroller variants, the codebase has grown so large that Mr. Nutt decided it would be best to continue its development as an Apache.org project.

The way Apache.org works is that projects that want to become part of ASF must first become a "podling" in the ASF Incubator. During "incubation" the project undergoes a transition period until all its processes are operating according to the "Apache Way" at which time the project can graduate to become an Apache "top-level project."

At the time of this writing, only the very first parts of this process have taken place, namely the proposal was made, a vote took place (which passed unanimously), and the project is now beginning its first step as an ASF podling.

Stay tuned while this story develops!

March 30, 2020: Updated various links on this page

Since NuttX joined the Apache Software Foundation by becoming an Apache.org Incubator Podling, the NuttX website and documentation have moved from their former web addresses to Apache.org servers. Also, some 3rd party NuttX sites, such as the former nuttx2019.org, have been moved to new locations, such as nuttx.events.

The ongoing changes will ultimately be good for the future of NuttX, but they resulted in various broken links in the sections above. So I went ahead and tracked down all their new locations and updated the links.

If you do find any more broken links, please let me know and I'll go hunting for their new locations.

Thanks for reading and come back soon!

August 15-16, 2020: The NuttX Online Workshop (N.O.W.)

This section last updated August 20th, 2020.

A NuttX 2020 event was planned to take place in Tokyo. However, because of the pandemic, the event was held online instead. The NuttX Online Workshop (N.O.W.) was held online August 15-16, 2020. The video footage and presentations can be seen on YouTube by following the links below:

Note: While the primary place to communicate with the NuttX developers and users is at the NuttX mailing lists, some questions and answers can be found in the forums that were set up for the event, also listed below. Links to other articles about some of these projects are included below as well.

March 31, 2021: An Update...

Many things have happened since my last significant update here, but I hope to get back into regularly documenting my adventures here.

Until now, I've described in (excruciating?!) detail how I've gotten NuttX to build and run on the TI TM4C129x microcontroller but at the outset I mentioned that my reason to dive headlong into NuttX is that I work with many different microcontroller architectures and the programming is very different when jumping from one family to another.

Oh, all the various microcontroller vendors support programming in C, but that's basically where the similarities end. From there, you have three options: you could write bare-metal firmware and operate the chip's basic peripherals by stuffing values into registers; or you could write bare-metal firmware and use a library of hardware abstraction function provided by the chip vendor to encapsulate some of the details of the peripherals; or you could go the RTOS route, and some chip vendors have one or more favorite RTOSes that you could choose from.

The biggest problem with all of those approaches is that, again, they're not portable. Even if you use a hardware abstraction library such as TI's TivaWare for the TM4C129x or STmicro's HAL for the STM32 families, your software is still stuck on that vendor's chips, and sometimes, on a particular model of chip. When your customer needs next-generation electronics with added new features that require a different microcontroller, you often end up having to rework much of the code to fit the new chip, starting back at square one for the most low-level details. At least that has been my experience.

So when I discovered NuttX, its long list of supported microcontroller architectures, its goal of sticking as much as possible to POSIX or POSIX-like standards, and its vibrant developer community, I found a viable and smarter way to write quality firmware with mobility between different microcontroller families.

I have several updates to this Adventure series in the works, which I hope to post soon, and in which I hop over to the STM32 family for the latest project I'm working on. Stay tuned for topics including:

As always, stay tuned for more Adventures with NuttX!

References and External Resources

This section last updated March 30th, 2020.

Back to main page

Send feedback to: the name of this blog at mail dot com.