Category: NuttX

NuttX Channel #016: Using the HC-SR04 to measure distance

I create a new video explaining how to use the ranging sensor HC-SR04 on NuttX:

Advertisements

Creating a HC-SR04 driver for NuttX

In this post I will explain how I did the HC-SR04 driver for NuttX.

I think this is the first time I try to explain how to create a driver for NuttX, oh wait! It is not! The first time was this post: NuttX driver to control a single LED

But this time it will be different, instead of just posting the code here, I will try to explain how I came with the driver. So, let to get started.

First I searched for the HC-SR04 datasheet, it was easy to find:
https://cdn.sparkfun.com/datasheets/Sensors/Proximity/HCSR04.pdf

Reading it I discovered that I need to send a pulse of 10uS in the pin Trig to start the conversion, pretty easy:

static int hcsr04_start_measuring(FAR struct hcsr04_dev_s *priv)
{
  /* Configure the interruption */

  priv->rising = true;
  priv->config->irq_setmode(priv->config, priv->rising);
  priv->config->irq_enable(priv->config, true);

  /* Send to 10uS trigger pulse */

  priv->config->set_trigger(priv->config, true);
  usleep(10);
  priv->config->set_trigger(priv->config, false);

  return 0;
}

After sending the Trigger pulse we will receive a pulse in the Echo pin with the width encoding the distance measured.

Because we need to measure width of a pulse the first idea that came to my mind was to use the Input Capture of STM32 Timer (I’m using the STM32F103-Minimum board), but I want this driver to be generic, then I decided to use an ordinary GPIO interrupt pin of STM32.

I can setup STM32 to detect level changing (rising edge and falling edge), but some microcontrollers don’t support it, you need to select rising edge or falling edge, not both at same time. We need to work around it because I need this driver to be generic enough to work on these “poor man” MCUs.

Then to get it working I need to implement a ping-pong approach: first setup the GPIO pin to detect rising edge of signal and inside the ISR (Interrupt Service Routine or just interrupt handler) it needs to change the pin configuration to detect interruption in the falling edge.

So at hcsr04_int_handler I did it:

if (priv->rising)
{
  /* Get the clock ticks from the free running timer */

  priv->time_start_pulse = priv->config->get_clock(priv->config);

  /* Now we need to wait for the falling edge interruption */

  priv->rising = false;
  priv->config->irq_setmode(priv->config, priv->rising);
  priv->config->irq_enable(priv->config, true);
}
else
{
  /* Get the clock ticks from the free running timer */

  priv->time_finish_pulse = priv->config->get_clock(priv->config);

  /* Disable interruptions */

  priv->config->irq_enable(priv->config, false);

  /* Convertion is done */

  sem_post(&priv->conv_donesem);
}

So now you got the idea how it works, we just need to understand the magic under the hood. These functions irq_enable(), irq_setmode(), get_clock(), etc, are in fact “function pointers” to board specific functions:

/* Interrupt configuration data structure */

struct hcsr04_config_s
{
  CODE int (*irq_attach)(FAR struct hcsr04_config_s * state, xcpt_t isr,
                         FAR void *arg);
  CODE void (*irq_enable)(FAR const struct hcsr04_config_s *state,
                          bool enable);
  CODE void (*irq_clear)(FAR const struct hcsr04_config_s *state);
  CODE void (*irq_setmode)(FAR struct hcsr04_config_s *state, bool risemode);
  CODE void (*set_trigger)(FAR const struct hcsr04_config_s *state, bool on);
  CODE int64_t (*get_clock)(FAR const struct hcsr04_config_s *state);
};

The real functions are at “nuttx/configs/stm32f103-minimum/src/stm32_hcsr04.c”

This way we can create a generic abstraction and let it work with any board/microcontroller.

As you probably already figured-out, it is the irq_setmode() function that defines if the GPIO pin (connected to Echo pin of HC-SR04 module) will detect rising edge signal or falling edge signal:

/* Setup the interruption mode: Rising or Falling */

static void hcsr04_irq_setmode(FAR struct hcsr04_config_s *state, bool rise_mode)
{
  FAR struct stm32_hcsr04config_s *priv =
  (FAR struct stm32_hcsr04config_s *)state;

  if (rise_mode)
    {
      priv->rising = true;
      priv->falling = false;
    }
  else
    {
      priv->rising = false;
      priv->falling = true;
    }
}

Ok, we just need the “rising” variable to store the current edge mode, because the “falling” variable always will be the inverse. But let us to use both for didactic reason. Now irq_enable() just call stm32_gpiosetevent() passing these edge parameters and enabling it (passing the driver’s interrupt handler) or disabling it (passing a NULL).

/* Enable or disable the GPIO interrupt */

static void hcsr04_irq_enable(FAR const struct hcsr04_config_s *state, bool enable)
{
  FAR struct stm32_hcsr04config_s *priv =
                                   (FAR struct stm32_hcsr04config_s *)state;

  sinfo("%d\n", enable);

  (void)stm32_gpiosetevent(GPIO_HCSR04_INT, priv->rising, priv->falling, true,
                           enable ? priv->isr : NULL, priv->arg);
}

Finally the get_clock() just returns the current clock tick of a free running timer configured to run at 1 microsecond resolution. I just need to convert the value of returned “timespec” variable “ts” to microseconds, multiplying tv_sec by 1 million (1 second has 1000000 us) and dividing tv_nsec by 1000 (1us = 1000 ns), see:

/* Return the current Free Running clock tick */

static int64_t hcsr04_get_clock(FAR const struct hcsr04_config_s *state)
{
  /* Get the time from free running timer */

  stm32_freerun_counter(&g_freerun, &ts);

  /* Return time in microseconds */

  return ((ts.tv_sec * 1000000) + (ts.tv_nsec / 1000));
}

So, I think you got the idea how this driver works. It is was easy to implement. You can read the complete code here: “nuttx/drivers/sensors/hc_sr04.c

Comparing NuttX with Zephyr

Today I decided to do a basic test comparing a small NuttX hello-world against the zephyr hello-world.

First let explain that I’m a NuttX contributor and maybe I’m a little bit biased, but I tried to keep me (as much as I could) neutral on this.

What motivated to do that was the nice Eric Styger article: https://mcuoneclipse.com/2017/01/22/zephyr-thoughts-and-first-steps-on-the-arm-cortex-m4f-with-gcc-gdb-and-eclipse/

I like the part that Eric said:

“I’m really not sure how Intel has convinced the Linux Foundation to promote Zephyr. If someone is looking for an operating system with Linux heritage, then it would something like NuttX or eCos in my view. On the other hand: more free and open source choices are good :-).”

(Hey Eric, we need you on NuttX!)

Let’s to start our test, first (of course) NuttX:

$ git clone https://www.bitbucket.org/nuttx/nuttx nuttx-project
$ git clone https://www.bitbucket.org/nuttx/apps
$ cd nuttx-project/
$ ./tools/configure.sh stm32f103-minimum/hello
  Copy files
  Refreshing...

$ make
make[1]: Entering directory '/home/alan/nuttx-project/tools'
make[1]: Leaving directory '/home/alan/nuttx-project/tools'
No .version file found, creating one
make[1]: Entering directory '/home/alan/nuttx-project/tools'
make[1]: Leaving directory '/home/alan/nuttx-project/tools'
LN: include/arch to arch/arm/include
LN: include/arch/board to /home/alan/nuttx-project/configs/stm32f103-minimum/include
LN: include/arch/chip to arch/arm/include/stm32
LN: arch/arm/src/board to /home/alan/nuttx-project/configs/stm32f103-minimum/src
LN: arch/arm/src/chip to arch/arm/src/stm32
make[1]: Entering directory '/home/alan/nuttx-project/configs'
make[1]: Leaving directory '/home/alan/nuttx-project/configs'
make[1]: Entering directory '/home/alan/apps'
make[2]: Entering directory '/home/alan/apps/platform'
LN: platform/board to /home/alan/apps/platform/dummy
make[2]: Leaving directory '/home/alan/apps/platform'
make[1]: Leaving directory '/home/alan/apps'
make[1]: Entering directory '/home/alan/nuttx-project/configs'
make[2]: Entering directory '/home/alan/nuttx-project/configs/stm32f103-minimum/src'
make[2]: Nothing to be done for 'context'.
make[2]: Leaving directory '/home/alan/nuttx-project/configs/stm32f103-minimum/src'
make[1]: Leaving directory '/home/alan/nuttx-project/configs'
make[1]: Entering directory '/home/alan/apps'
make[2]: Entering directory '/home/alan/apps/builtin'
make[3]: Entering directory '/home/alan/apps/builtin/registry'
make[3]: Leaving directory '/home/alan/apps/builtin/registry'
make[2]: Leaving directory '/home/alan/apps/builtin'
make[2]: Entering directory '/home/alan/apps'
make[3]: Entering directory '/home/alan/apps/examples/hello'
make[3]: Nothing to be done for 'context'.
make[3]: Leaving directory '/home/alan/apps/examples/hello'
make[3]: Entering directory '/home/alan/apps/examples/nsh'
make[3]: Nothing to be done for 'context'.
make[3]: Leaving directory '/home/alan/apps/examples/nsh'
make[3]: Entering directory '/home/alan/apps/nshlib'
make[3]: Nothing to be done for 'context'.
make[3]: Leaving directory '/home/alan/apps/nshlib'
make[3]: Entering directory '/home/alan/apps/system/readline'
make[3]: Nothing to be done for 'context'.
make[3]: Leaving directory '/home/alan/apps/system/readline'
make[3]: Entering directory '/home/alan/apps/platform'
LN: platform/board to /home/alan/apps/platform/dummy
make[3]: Leaving directory '/home/alan/apps/platform'
make[2]: Leaving directory '/home/alan/apps'
make[1]: Leaving directory '/home/alan/apps'
make[1]: Entering directory '/home/alan/nuttx-project/tools'
make[1]: Leaving directory '/home/alan/nuttx-project/tools'
make[1]: Entering directory '/home/alan/nuttx-project/tools'
make[1]: Leaving directory '/home/alan/nuttx-project/tools'
make[1]: Entering directory '/home/alan/nuttx-project/sched'
make[1]: Leaving directory '/home/alan/nuttx-project/sched'
make[1]: Entering directory '/home/alan/nuttx-project/drivers'
make[1]: Leaving directory '/home/alan/nuttx-project/drivers'
make[1]: Entering directory '/home/alan/nuttx-project/configs'
make[1]: Leaving directory '/home/alan/nuttx-project/configs'
make[1]: Entering directory '/home/alan/nuttx-project/arch/arm/src'
make[2]: Entering directory '/home/alan/nuttx-project/configs/stm32f103-minimum/src'
make[2]: Leaving directory '/home/alan/nuttx-project/configs/stm32f103-minimum/src'
make[1]: Leaving directory '/home/alan/nuttx-project/arch/arm/src'
make[1]: Entering directory '/home/alan/apps'
make[2]: Entering directory '/home/alan/apps/builtin'
make[3]: Entering directory '/home/alan/apps/builtin/registry'
make[3]: Nothing to be done for 'context'.
make[3]: Leaving directory '/home/alan/apps/builtin/registry'
make[2]: Leaving directory '/home/alan/apps/builtin'
make[2]: Entering directory '/home/alan/apps'
make[3]: Entering directory '/home/alan/apps/examples/hello'
make[3]: Nothing to be done for 'context'.
make[3]: Leaving directory '/home/alan/apps/examples/hello'
make[3]: Entering directory '/home/alan/apps/examples/nsh'
make[3]: Nothing to be done for 'context'.
make[3]: Leaving directory '/home/alan/apps/examples/nsh'
make[3]: Entering directory '/home/alan/apps/nshlib'
make[3]: Nothing to be done for 'context'.
make[3]: Leaving directory '/home/alan/apps/nshlib'
make[3]: Entering directory '/home/alan/apps/system/readline'
make[3]: Nothing to be done for 'context'.
make[3]: Leaving directory '/home/alan/apps/system/readline'
make[3]: Entering directory '/home/alan/apps/platform'
LN: platform/board to /home/alan/apps/platform/dummy
make[3]: Leaving directory '/home/alan/apps/platform'
make[2]: Leaving directory '/home/alan/apps'
make[2]: Entering directory '/home/alan/apps/examples/hello'
make[2]: Leaving directory '/home/alan/apps/examples/hello'
make[2]: Entering directory '/home/alan/apps/examples/nsh'
make[2]: Leaving directory '/home/alan/apps/examples/nsh'
make[2]: Entering directory '/home/alan/apps/nshlib'
make[2]: Leaving directory '/home/alan/apps/nshlib'
make[2]: Entering directory '/home/alan/apps/system/readline'
make[2]: Leaving directory '/home/alan/apps/system/readline'
make[2]: Entering directory '/home/alan/apps/platform'
LN: platform/board to /home/alan/apps/platform/dummy
make[2]: Leaving directory '/home/alan/apps/platform'
make[1]: Leaving directory '/home/alan/apps'
make[1]: Entering directory '/home/alan/nuttx-project/libc'
make[1]: Leaving directory '/home/alan/nuttx-project/libc'
make[1]: Entering directory '/home/alan/nuttx-project/mm'
make[1]: Leaving directory '/home/alan/nuttx-project/mm'
make[1]: Entering directory '/home/alan/nuttx-project/fs'
make[1]: Leaving directory '/home/alan/nuttx-project/fs'
make[1]: Entering directory '/home/alan/nuttx-project/binfmt'
make[1]: Leaving directory '/home/alan/nuttx-project/binfmt'
make[1]: Entering directory '/home/alan/nuttx-project/sched'
CC:  clock/clock_initialize.c
CC:  clock/clock_settime.c
CC:  clock/clock_gettime.c
CC:  clock/clock_getres.c
CC:  clock/clock_time2ticks.c
CC:  clock/clock_abstime2ticks.c
CC:  clock/clock_ticks2time.c
CC:  clock/clock_systimer.c
CC:  clock/clock_systimespec.c
CC:  clock/clock_timespec_add.c
CC:  clock/clock_timespec_subtract.c
CC:  errno/errno_getptr.c
CC:  group/group_create.c
CC:  group/group_join.c
CC:  group/group_leave.c
CC:  group/group_find.c
CC:  group/group_setupstreams.c
CC:  group/group_setupidlefiles.c
CC:  group/group_setuptaskfiles.c
CC:  group/group_foreachchild.c
CC:  group/group_killchildren.c
CC:  init/os_start.c
CC:  init/os_bringup.c
CC:  irq/irq_initialize.c
CC:  irq/irq_attach.c
CC:  irq/irq_dispatch.c
CC:  irq/irq_unexpectedisr.c
CC:  paging/pg_miss.c
CC:  paging/pg_worker.c
CC:  sched/sched_garbage.c
CC:  sched/sched_getfiles.c
CC:  sched/sched_addreadytorun.c
CC:  sched/sched_removereadytorun.c
CC:  sched/sched_addprioritized.c
CC:  sched/sched_mergeprioritized.c
CC:  sched/sched_mergepending.c
CC:  sched/sched_addblocked.c
CC:  sched/sched_removeblocked.c
CC:  sched/sched_free.c
CC:  sched/sched_gettcb.c
CC:  sched/sched_verifytcb.c
CC:  sched/sched_releasetcb.c
CC:  sched/sched_getsockets.c
CC:  sched/sched_getstreams.c
CC:  sched/sched_setparam.c
CC:  sched/sched_setpriority.c
CC:  sched/sched_getparam.c
CC:  sched/sched_setscheduler.c
CC:  sched/sched_getscheduler.c
CC:  sched/sched_yield.c
CC:  sched/sched_rrgetinterval.c
CC:  sched/sched_foreach.c
CC:  sched/sched_lock.c
CC:  sched/sched_unlock.c
CC:  sched/sched_lockcount.c
CC:  sched/sched_idletask.c
CC:  sched/sched_self.c
CC:  sched/sched_roundrobin.c
CC:  sched/sched_resumescheduler.c
CC:  sched/sched_processtimer.c
CC:  semaphore/sem_destroy.c
CC:  semaphore/sem_wait.c
CC:  semaphore/sem_trywait.c
CC:  semaphore/sem_tickwait.c
CC:  semaphore/sem_timedwait.c
CC:  semaphore/sem_timeout.c
CC:  semaphore/sem_post.c
CC:  semaphore/sem_recover.c
CC:  semaphore/sem_reset.c
CC:  semaphore/sem_waitirq.c
CC:  task/task_create.c
CC:  task/task_init.c
CC:  task/task_setup.c
CC:  task/task_activate.c
CC:  task/task_start.c
CC:  task/task_delete.c
CC:  task/task_exit.c
CC:  task/task_exithook.c
CC:  task/task_getgroup.c
CC:  task/task_getpid.c
CC:  task/task_prctl.c
CC:  task/task_recover.c
CC:  task/task_restart.c
CC:  task/task_spawnparms.c
CC:  task/task_setcancelstate.c
CC:  task/task_terminate.c
CC:  task/exit.c
CC:  task/task_spawn.c
CC:  wdog/wd_initialize.c
CC:  wdog/wd_create.c
CC:  wdog/wd_start.c
CC:  wdog/wd_cancel.c
CC:  wdog/wd_delete.c
CC:  wdog/wd_gettime.c
CC:  wdog/wd_recover.c
AR:   clock_initialize.o clock_settime.o clock_gettime.o clock_getres.o clock_time2ticks.o clock_abstime2ticks.o clock_ticks2time.o clock_systimer.o clock_systimespec.o clock_timespec_add.o clock_timespec_subtract.o errno_getptr.o group_create.o group_join.o group_leave.o group_find.o group_setupstreams.o group_setupidlefiles.o group_setuptaskfiles.o group_foreachchild.o group_killchildren.o os_start.o os_bringup.o irq_initialize.o irq_attach.o irq_dispatch.o irq_unexpectedisr.o pg_miss.o pg_worker.o sched_garbage.o sched_getfiles.o sched_addreadytorun.o sched_removereadytorun.o sched_addprioritized.o sched_mergeprioritized.o sched_mergepending.o sched_addblocked.o sched_removeblocked.o sched_free.o sched_gettcb.o sched_verifytcb.o sched_releasetcb.o sched_getsockets.o sched_getstreams.o sched_setparam.o sched_setpriority.o sched_getparam.o sched_setscheduler.o sched_getscheduler.o sched_yield.o sched_rrgetinterval.o sched_foreach.o sched_lock.o sched_unlock.o sched_lockcount.o sched_idletask.o sched_self.o sched_roundrobin.o sched_resumescheduler.o sched_processtimer.o sem_destroy.o sem_wait.o sem_trywait.o sem_tickwait.o sem_timedwait.o sem_timeout.o sem_post.o sem_recover.o sem_reset.o sem_waitirq.o task_create.o task_init.o task_setup.o task_activate.o task_start.o task_delete.o task_exit.o task_exithook.o task_getgroup.o task_getpid.o task_prctl.o task_recover.o task_restart.o task_spawnparms.o task_setcancelstate.o task_terminate.o exit.o task_spawn.o wd_initialize.o wd_create.o wd_start.o wd_cancel.o wd_delete.o wd_gettime.o wd_recover.o
make[1]: Leaving directory '/home/alan/nuttx-project/sched'
make[1]: Entering directory '/home/alan/nuttx-project/drivers'
CC:  pipes/pipe.c
CC:  pipes/fifo.c
CC:  pipes/pipe_common.c
CC:  serial/serial.c
CC:  serial/serial_io.c
CC:  serial/lowconsole.c
CC:  syslog/vsyslog.c
CC:  syslog/syslog_stream.c
CC:  syslog/syslog_emergstream.c
CC:  syslog/syslog_channel.c
CC:  syslog/syslog_putc.c
CC:  syslog/syslog_write.c
CC:  syslog/syslog_force.c
CC:  syslog/syslog_flush.c
CC:  syslog/syslog_initialize.c
CC:  syslog/syslog_device.c
CC:  syslog/syslog_consolechannel.c
CC:  usbhost/hid_parser.c
CC:  dev_null.c
CC:  dev_zero.c
AR:   pipe.o fifo.o pipe_common.o serial.o serial_io.o lowconsole.o vsyslog.o syslog_stream.o syslog_emergstream.o syslog_channel.o syslog_putc.o syslog_write.o syslog_force.o syslog_flush.o syslog_initialize.o syslog_device.o syslog_consolechannel.o hid_parser.o dev_null.o dev_zero.o
make[1]: Leaving directory '/home/alan/nuttx-project/drivers'
make[1]: Entering directory '/home/alan/nuttx-project/configs'
AR:    
make[1]: Leaving directory '/home/alan/nuttx-project/configs'
make[1]: Entering directory '/home/alan/nuttx-project/libc'
CC:  dirent/lib_readdirr.c
CC:  dirent/lib_telldir.c
CC:  fixedmath/lib_fixedmath.c
CC:  fixedmath/lib_b16sin.c
CC:  fixedmath/lib_b16cos.c
CC:  fixedmath/lib_b16atan2.c
CC:  fixedmath/lib_ubsqrt.c
CC:  inttypes/lib_imaxabs.c
CC:  inttypes/lib_strtoimax.c
CC:  inttypes/lib_strtoumax.c
CC:  libgen/lib_basename.c
CC:  libgen/lib_dirname.c
CC:  misc/lib_stream.c
CC:  misc/lib_utsname.c
CC:  misc/lib_xorshift128.c
CC:  misc/lib_tea_encrypt.c
CC:  misc/lib_tea_decrypt.c
CC:  misc/lib_umul32.c
CC:  misc/lib_umul64.c
CC:  misc/lib_umul32x64.c
CC:  misc/lib_uadd32x64.c
CC:  misc/lib_uadd64.c
CC:  misc/lib_usub64x32.c
CC:  misc/lib_usub64.c
CC:  misc/lib_sendfile.c
CC:  misc/lib_streamsem.c
CC:  misc/lib_crc64.c
CC:  misc/lib_crc32.c
CC:  misc/lib_crc16.c
CC:  misc/lib_crc8.c
CC:  misc/lib_dumpbuffer.c
CC:  misc/lib_match.c
CC:  net/lib_addrconfig.c
CC:  net/lib_etherntoa.c
CC:  net/lib_htons.c
CC:  net/lib_htonl.c
CC:  net/lib_inetaddr.c
CC:  net/lib_inetntoa.c
CC:  net/lib_inetntop.c
CC:  net/lib_inetpton.c
CC:  queue/sq_addlast.c
CC:  queue/sq_addfirst.c
CC:  queue/sq_addafter.c
CC:  queue/sq_cat.c
CC:  queue/sq_rem.c
CC:  queue/sq_remlast.c
CC:  queue/sq_remfirst.c
CC:  queue/sq_remafter.c
CC:  queue/sq_count.c
CC:  queue/dq_addlast.c
CC:  queue/dq_addfirst.c
CC:  queue/dq_addafter.c
CC:  queue/dq_addbefore.c
CC:  queue/dq_cat.c
CC:  queue/dq_rem.c
CC:  queue/dq_remlast.c
CC:  queue/dq_remfirst.c
CC:  queue/dq_count.c
CC:  sched/sched_getprioritymax.c
CC:  sched/sched_getprioritymin.c
CC:  sched/task_setcanceltype.c
CC:  sched/task_testcancel.c
CC:  semaphore/sem_init.c
CC:  semaphore/sem_getprotocol.c
CC:  semaphore/sem_getvalue.c
CC:  semaphore/sem_setprotocol.c
CC:  spawn/lib_psfa_addaction.c
CC:  spawn/lib_psfa_addclose.c
CC:  spawn/lib_psfa_adddup2.c
CC:  spawn/lib_psfa_addopen.c
CC:  spawn/lib_psfa_destroy.c
CC:  spawn/lib_psfa_init.c
CC:  spawn/lib_psa_getflags.c
CC:  spawn/lib_psa_getschedparam.c
CC:  spawn/lib_psa_getschedpolicy.c
CC:  spawn/lib_psa_init.c
CC:  spawn/lib_psa_setflags.c
CC:  spawn/lib_psa_setschedparam.c
CC:  spawn/lib_psa_setschedpolicy.c
CC:  spawn/lib_psa_getstacksize.c
CC:  spawn/lib_psa_setstacksize.c
CC:  stdio/lib_fileno.c
CC:  stdio/lib_printf.c
CC:  stdio/lib_sprintf.c
CC:  stdio/lib_asprintf.c
CC:  stdio/lib_snprintf.c
CC:  stdio/lib_libsprintf.c
CC:  stdio/lib_vsprintf.c
CC:  stdio/lib_vasprintf.c
CC:  stdio/lib_vsnprintf.c
CC:  stdio/lib_libvsprintf.c
CC:  stdio/lib_dprintf.c
CC:  stdio/lib_vdprintf.c
CC:  stdio/lib_meminstream.c
CC:  stdio/lib_memoutstream.c
CC:  stdio/lib_memsistream.c
CC:  stdio/lib_memsostream.c
CC:  stdio/lib_lowoutstream.c
CC:  stdio/lib_zeroinstream.c
CC:  stdio/lib_nullinstream.c
CC:  stdio/lib_nulloutstream.c
CC:  stdio/lib_sscanf.c
CC:  stdio/lib_rawinstream.c
CC:  stdio/lib_rawoutstream.c
CC:  stdio/lib_rawsistream.c
CC:  stdio/lib_rawsostream.c
CC:  stdio/lib_libnoflush.c
CC:  stdio/lib_libsnoflush.c
CC:  stdio/lib_remove.c
CC:  stdio/lib_fopen.c
CC:  stdio/lib_freopen.c
CC:  stdio/lib_fclose.c
CC:  stdio/lib_fread.c
CC:  stdio/lib_libfread.c
CC:  stdio/lib_fseek.c
CC:  stdio/lib_ftell.c
CC:  stdio/lib_fsetpos.c
CC:  stdio/lib_fgetpos.c
CC:  stdio/lib_fgetc.c
CC:  stdio/lib_fgets.c
CC:  stdio/lib_gets_s.c
CC:  stdio/lib_gets.c
CC:  stdio/lib_libfgets.c
CC:  stdio/lib_fwrite.c
CC:  stdio/lib_libfwrite.c
CC:  stdio/lib_fflush.c
CC:  stdio/lib_libflushall.c
CC:  stdio/lib_libfflush.c
CC:  stdio/lib_rdflush.c
CC:  stdio/lib_wrflush.c
CC:  stdio/lib_fputc.c
CC:  stdio/lib_puts.c
CC:  stdio/lib_fputs.c
CC:  stdio/lib_ungetc.c
CC:  stdio/lib_vprintf.c
CC:  stdio/lib_fprintf.c
CC:  stdio/lib_vfprintf.c
CC:  stdio/lib_stdinstream.c
CC:  stdio/lib_stdoutstream.c
CC:  stdio/lib_stdsistream.c
CC:  stdio/lib_stdsostream.c
CC:  stdio/lib_perror.c
CC:  stdio/lib_feof.c
CC:  stdio/lib_ferror.c
CC:  stdio/lib_clearerr.c
CC:  stdlib/lib_abs.c
CC:  stdlib/lib_abort.c
CC:  stdlib/lib_div.c
CC:  stdlib/lib_ldiv.c
CC:  stdlib/lib_lldiv.c
CC:  stdlib/lib_itoa.c
CC:  stdlib/lib_labs.c
CC:  stdlib/lib_llabs.c
CC:  stdlib/lib_bsearch.c
CC:  stdlib/lib_rand.c
CC:  stdlib/lib_qsort.c
CC:  stdlib/lib_srand.c
CC:  stdlib/lib_strtol.c
CC:  stdlib/lib_strtoll.c
CC:  stdlib/lib_strtoul.c
CC:  stdlib/lib_strtoull.c
CC:  stdlib/lib_strtod.c
CC:  stdlib/lib_strtof.c
CC:  stdlib/lib_strtold.c
CC:  stdlib/lib_checkbase.c
CC:  string/lib_ffs.c
CC:  string/lib_ffsl.c
CC:  string/lib_ffsll.c
CC:  string/lib_fls.c
CC:  string/lib_flsl.c
CC:  string/lib_flsll.c
CC:  string/lib_isbasedigit.c
CC:  string/lib_memset.c
CC:  string/lib_memchr.c
CC:  string/lib_memccpy.c
CC:  string/lib_memcmp.c
CC:  string/lib_memmove.c
CC:  string/lib_skipspace.c
CC:  string/lib_stpcpy.c
CC:  string/lib_strcasecmp.c
CC:  string/lib_strcat.c
CC:  string/lib_strchr.c
CC:  string/lib_strcpy.c
CC:  string/lib_strcmp.c
CC:  string/lib_strcspn.c
CC:  string/lib_strdup.c
CC:  string/lib_strerror.c
CC:  string/lib_strlen.c
CC:  string/lib_strnlen.c
CC:  string/lib_strncasecmp.c
CC:  string/lib_strncat.c
CC:  string/lib_strncmp.c
CC:  string/lib_strncpy.c
CC:  string/lib_strndup.c
CC:  string/lib_strcasestr.c
CC:  string/lib_strpbrk.c
CC:  string/lib_strrchr.c
CC:  string/lib_strspn.c
CC:  string/lib_strstr.c
CC:  string/lib_strtok.c
CC:  string/lib_strtokr.c
CC:  string/lib_strerrorr.c
CC:  string/lib_explicit_bzero.c
CC:  string/lib_memcpy.c
CC:  symtab/symtab_findbyname.c
CC:  symtab/symtab_findbyvalue.c
CC:  symtab/symtab_findorderedbyname.c
CC:  symtab/symtab_findorderedbyvalue.c
CC:  syslog/lib_syslog.c
CC:  syslog/lib_setlogmask.c
CC:  termios/lib_cfgetspeed.c
CC:  termios/lib_cfsetspeed.c
CC:  termios/lib_isatty.c
CC:  termios/lib_tcflush.c
CC:  termios/lib_tcgetattr.c
CC:  termios/lib_tcsetattr.c
CC:  time/lib_strftime.c
CC:  time/lib_calendar2utc.c
CC:  time/lib_daysbeforemonth.c
CC:  time/lib_gettimeofday.c
CC:  time/lib_isleapyear.c
CC:  time/lib_settimeofday.c
CC:  time/lib_time.c
CC:  time/lib_difftime.c
CC:  time/lib_mktime.c
CC:  time/lib_gmtime.c
CC:  time/lib_gmtimer.c
CC:  unistd/lib_access.c
CC:  unistd/lib_swab.c
CC:  unistd/lib_getopt.c
CC:  unistd/lib_getoptargp.c
CC:  unistd/lib_getoptindp.c
CC:  unistd/lib_getoptoptp.c
AR:    bin/lib_readdirr.o  bin/lib_telldir.o  bin/lib_fixedmath.o  bin/lib_b16sin.o  bin/lib_b16cos.o  bin/lib_b16atan2.o  bin/lib_ubsqrt.o  bin/lib_imaxabs.o  bin/lib_strtoimax.o  bin/lib_strtoumax.o  bin/lib_basename.o  bin/lib_dirname.o  bin/lib_stream.o  bin/lib_utsname.o  bin/lib_xorshift128.o  bin/lib_tea_encrypt.o  bin/lib_tea_decrypt.o  bin/lib_umul32.o  bin/lib_umul64.o  bin/lib_umul32x64.o  bin/lib_uadd32x64.o  bin/lib_uadd64.o  bin/lib_usub64x32.o  bin/lib_usub64.o  bin/lib_sendfile.o  bin/lib_streamsem.o  bin/lib_crc64.o  bin/lib_crc32.o  bin/lib_crc16.o  bin/lib_crc8.o  bin/lib_dumpbuffer.o  bin/lib_match.o  bin/lib_addrconfig.o  bin/lib_etherntoa.o  bin/lib_htons.o  bin/lib_htonl.o  bin/lib_inetaddr.o  bin/lib_inetntoa.o  bin/lib_inetntop.o  bin/lib_inetpton.o  bin/sq_addlast.o  bin/sq_addfirst.o  bin/sq_addafter.o  bin/sq_cat.o  bin/sq_rem.o  bin/sq_remlast.o  bin/sq_remfirst.o  bin/sq_remafter.o  bin/sq_count.o  bin/dq_addlast.o  bin/dq_addfirst.o  bin/dq_addafter.o  bin/dq_addbefore.o  bin/dq_cat.o  bin/dq_rem.o  bin/dq_remlast.o  bin/dq_remfirst.o  bin/dq_count.o  bin/sched_getprioritymax.o  bin/sched_getprioritymin.o  bin/task_setcanceltype.o  bin/task_testcancel.o  bin/sem_init.o  bin/sem_getprotocol.o  bin/sem_getvalue.o  bin/sem_setprotocol.o  bin/lib_psfa_addaction.o  bin/lib_psfa_addclose.o  bin/lib_psfa_adddup2.o  bin/lib_psfa_addopen.o  bin/lib_psfa_destroy.o  bin/lib_psfa_init.o  bin/lib_psa_getflags.o  bin/lib_psa_getschedparam.o  bin/lib_psa_getschedpolicy.o  bin/lib_psa_init.o  bin/lib_psa_setflags.o  bin/lib_psa_setschedparam.o  bin/lib_psa_setschedpolicy.o  bin/lib_psa_getstacksize.o  bin/lib_psa_setstacksize.o  bin/lib_fileno.o  bin/lib_printf.o  bin/lib_sprintf.o  bin/lib_asprintf.o  bin/lib_snprintf.o  bin/lib_libsprintf.o  bin/lib_vsprintf.o  bin/lib_vasprintf.o  bin/lib_vsnprintf.o  bin/lib_libvsprintf.o  bin/lib_dprintf.o  bin/lib_vdprintf.o  bin/lib_meminstream.o  bin/lib_memoutstream.o  bin/lib_memsistream.o  bin/lib_memsostream.o  bin/lib_lowoutstream.o  bin/lib_zeroinstream.o  bin/lib_nullinstream.o  bin/lib_nulloutstream.o  bin/lib_sscanf.o  bin/lib_rawinstream.o  bin/lib_rawoutstream.o  bin/lib_rawsistream.o  bin/lib_rawsostream.o  bin/lib_libnoflush.o  bin/lib_libsnoflush.o  bin/lib_remove.o  bin/lib_fopen.o  bin/lib_freopen.o  bin/lib_fclose.o  bin/lib_fread.o  bin/lib_libfread.o  bin/lib_fseek.o  bin/lib_ftell.o  bin/lib_fsetpos.o  bin/lib_fgetpos.o  bin/lib_fgetc.o  bin/lib_fgets.o  bin/lib_gets_s.o  bin/lib_gets.o  bin/lib_libfgets.o  bin/lib_fwrite.o  bin/lib_libfwrite.o  bin/lib_fflush.o  bin/lib_libflushall.o  bin/lib_libfflush.o  bin/lib_rdflush.o  bin/lib_wrflush.o  bin/lib_fputc.o  bin/lib_puts.o  bin/lib_fputs.o  bin/lib_ungetc.o  bin/lib_vprintf.o  bin/lib_fprintf.o  bin/lib_vfprintf.o  bin/lib_stdinstream.o  bin/lib_stdoutstream.o  bin/lib_stdsistream.o  bin/lib_stdsostream.o  bin/lib_perror.o  bin/lib_feof.o  bin/lib_ferror.o  bin/lib_clearerr.o  bin/lib_abs.o  bin/lib_abort.o  bin/lib_div.o  bin/lib_ldiv.o  bin/lib_lldiv.o  bin/lib_itoa.o  bin/lib_labs.o  bin/lib_llabs.o  bin/lib_bsearch.o  bin/lib_rand.o  bin/lib_qsort.o  bin/lib_srand.o  bin/lib_strtol.o  bin/lib_strtoll.o  bin/lib_strtoul.o  bin/lib_strtoull.o  bin/lib_strtod.o  bin/lib_strtof.o  bin/lib_strtold.o  bin/lib_checkbase.o  bin/lib_ffs.o  bin/lib_ffsl.o  bin/lib_ffsll.o  bin/lib_fls.o  bin/lib_flsl.o  bin/lib_flsll.o  bin/lib_isbasedigit.o  bin/lib_memset.o  bin/lib_memchr.o  bin/lib_memccpy.o  bin/lib_memcmp.o  bin/lib_memmove.o  bin/lib_skipspace.o  bin/lib_stpcpy.o  bin/lib_strcasecmp.o  bin/lib_strcat.o  bin/lib_strchr.o  bin/lib_strcpy.o  bin/lib_strcmp.o  bin/lib_strcspn.o  bin/lib_strdup.o  bin/lib_strerror.o  bin/lib_strlen.o  bin/lib_strnlen.o  bin/lib_strncasecmp.o  bin/lib_strncat.o  bin/lib_strncmp.o  bin/lib_strncpy.o  bin/lib_strndup.o  bin/lib_strcasestr.o  bin/lib_strpbrk.o  bin/lib_strrchr.o  bin/lib_strspn.o  bin/lib_strstr.o  bin/lib_strtok.o  bin/lib_strtokr.o  bin/lib_strerrorr.o  bin/lib_explicit_bzero.o  bin/lib_memcpy.o  bin/symtab_findbyname.o  bin/symtab_findbyvalue.o  bin/symtab_findorderedbyname.o  bin/symtab_findorderedbyvalue.o  bin/lib_syslog.o  bin/lib_setlogmask.o  bin/lib_cfgetspeed.o  bin/lib_cfsetspeed.o  bin/lib_isatty.o  bin/lib_tcflush.o  bin/lib_tcgetattr.o  bin/lib_tcsetattr.o  bin/lib_strftime.o  bin/lib_calendar2utc.o  bin/lib_daysbeforemonth.o  bin/lib_gettimeofday.o  bin/lib_isleapyear.o  bin/lib_settimeofday.o  bin/lib_time.o  bin/lib_difftime.o  bin/lib_mktime.o  bin/lib_gmtime.o  bin/lib_gmtimer.o  bin/lib_access.o  bin/lib_swab.o  bin/lib_getopt.o  bin/lib_getoptargp.o  bin/lib_getoptindp.o  bin/lib_getoptoptp.o
make[1]: Leaving directory '/home/alan/nuttx-project/libc'
make[1]: Entering directory '/home/alan/nuttx-project/mm'
CC:  mm_heap/mm_initialize.c
CC:  mm_heap/mm_sem.c
CC:  mm_heap/mm_addfreechunk.c
CC:  mm_heap/mm_size2ndx.c
CC:  mm_heap/mm_shrinkchunk.c
CC:  mm_heap/mm_brkaddr.c
CC:  mm_heap/mm_calloc.c
CC:  mm_heap/mm_extend.c
CC:  mm_heap/mm_free.c
CC:  mm_heap/mm_mallinfo.c
CC:  mm_heap/mm_malloc.c
CC:  mm_heap/mm_memalign.c
CC:  mm_heap/mm_realloc.c
CC:  mm_heap/mm_zalloc.c
CC:  umm_heap/umm_initialize.c
CC:  umm_heap/umm_addregion.c
CC:  umm_heap/umm_sem.c
CC:  umm_heap/umm_brkaddr.c
CC:  umm_heap/umm_calloc.c
CC:  umm_heap/umm_extend.c
CC:  umm_heap/umm_free.c
CC:  umm_heap/umm_mallinfo.c
CC:  umm_heap/umm_malloc.c
CC:  umm_heap/umm_memalign.c
CC:  umm_heap/umm_realloc.c
CC:  umm_heap/umm_zalloc.c
CC:  umm_heap/umm_globals.c
AR:    bin/mm_initialize.o  bin/mm_sem.o  bin/mm_addfreechunk.o  bin/mm_size2ndx.o  bin/mm_shrinkchunk.o  bin/mm_brkaddr.o  bin/mm_calloc.o  bin/mm_extend.o  bin/mm_free.o  bin/mm_mallinfo.o  bin/mm_malloc.o  bin/mm_memalign.o  bin/mm_realloc.o  bin/mm_zalloc.o  bin/umm_initialize.o  bin/umm_addregion.o  bin/umm_sem.o  bin/umm_brkaddr.o  bin/umm_calloc.o  bin/umm_extend.o  bin/umm_free.o  bin/umm_mallinfo.o  bin/umm_malloc.o  bin/umm_memalign.o  bin/umm_realloc.o  bin/umm_zalloc.o  bin/umm_globals.o
make[1]: Leaving directory '/home/alan/nuttx-project/mm'
make[1]: Entering directory '/home/alan/nuttx-project/arch/arm/src'
AS:  chip/gnu/stm32_vectors.S
AS:  armv7-m/gnu/up_saveusercontext.S
AS:  armv7-m/gnu/up_fullcontextrestore.S
AS:  armv7-m/gnu/up_switchcontext.S
AS:  armv7-m/gnu/up_testset.S
AS:  armv7-m/gnu/vfork.S
AS:  armv7-m/gnu/up_exception.S
CC:  chip/stm32_allocateheap.c
CC:  chip/stm32_start.c
CC:  chip/stm32_rcc.c
CC:  chip/stm32_lse.c
CC:  chip/stm32_lsi.c
CC:  chip/stm32_gpio.c
CC:  chip/stm32_exti_gpio.c
CC:  chip/stm32_flash.c
CC:  chip/stm32_irq.c
CC:  chip/stm32_dma.c
CC:  chip/stm32_lowputc.c
CC:  chip/stm32_serial.c
CC:  chip/stm32_spi.c
CC:  chip/stm32_i2s.c
CC:  chip/stm32_sdio.c
CC:  chip/stm32_tim.c
CC:  chip/stm32_waste.c
CC:  chip/stm32_ccm.c
CC:  chip/stm32_uid.c
CC:  chip/stm32_capture.c
CC:  chip/stm32_timerisr.c
CC:  chip/stm32_i2c.c
CC:  chip/stm32_idle.c
CC:  chip/stm32_pmstop.c
CC:  chip/stm32_pmstandby.c
CC:  chip/stm32_pmsleep.c
CC:  chip/stm32_pminitialize.c
CC:  armv7-m/up_assert.c
CC:  armv7-m/up_blocktask.c
CC:  armv7-m/up_copyfullstate.c
CC:  common/up_createstack.c
CC:  common/up_mdelay.c
CC:  common/up_udelay.c
CC:  common/up_exit.c
CC:  common/up_initialize.c
CC:  armv7-m/up_initialstate.c
CC:  common/up_interruptcontext.c
CC:  armv7-m/up_memfault.c
CC:  common/up_modifyreg8.c
CC:  common/up_modifyreg16.c
CC:  common/up_modifyreg32.c
CC:  armv7-m/up_releasepending.c
CC:  common/up_releasestack.c
CC:  armv7-m/up_reprioritizertr.c
CC:  armv7-m/up_schedulesigaction.c
CC:  armv7-m/up_sigdeliver.c
CC:  common/up_stackframe.c
CC:  armv7-m/up_systemreset.c
CC:  armv7-m/up_unblocktask.c
CC:  common/up_usestack.c
CC:  armv7-m/up_doirq.c
CC:  armv7-m/up_hardfault.c
CC:  armv7-m/up_svcall.c
CC:  common/up_vfork.c
CC:  armv7-m/up_vectors.c
AR:  stm32_vectors.o up_saveusercontext.o up_fullcontextrestore.o up_switchcontext.o up_testset.o vfork.o up_exception.o stm32_allocateheap.o stm32_start.o stm32_rcc.o stm32_lse.o stm32_lsi.o stm32_gpio.o stm32_exti_gpio.o stm32_flash.o stm32_irq.o stm32_dma.o stm32_lowputc.o stm32_serial.o stm32_spi.o stm32_i2s.o stm32_sdio.o stm32_tim.o stm32_waste.o stm32_ccm.o stm32_uid.o stm32_capture.o stm32_timerisr.o stm32_i2c.o stm32_idle.o stm32_pmstop.o stm32_pmstandby.o stm32_pmsleep.o stm32_pminitialize.o up_assert.o up_blocktask.o up_copyfullstate.o up_createstack.o up_mdelay.o up_udelay.o up_exit.o up_initialize.o up_initialstate.o up_interruptcontext.o up_memfault.o up_modifyreg8.o up_modifyreg16.o up_modifyreg32.o up_releasepending.o up_releasestack.o up_reprioritizertr.o up_schedulesigaction.o up_sigdeliver.o up_stackframe.o up_systemreset.o up_unblocktask.o up_usestack.o up_doirq.o up_hardfault.o up_svcall.o up_vfork.o up_vectors.o
make[1]: Leaving directory '/home/alan/nuttx-project/arch/arm/src'
make[1]: Entering directory '/home/alan/apps'
make[2]: Entering directory '/home/alan/apps/examples/hello'
CC:  hello_main.c
AR:     hello_main.o
make[2]: Leaving directory '/home/alan/apps/examples/hello'
make[2]: Entering directory '/home/alan/apps/examples/nsh'
CC:  nsh_main.c
AR:     nsh_main.o
make[2]: Leaving directory '/home/alan/apps/examples/nsh'
make[2]: Entering directory '/home/alan/apps/nshlib'
CC:  nsh_init.c
CC:  nsh_parse.c
CC:  nsh_console.c
CC:  nsh_script.c
CC:  nsh_system.c
CC:  nsh_command.c
CC:  nsh_fscmds.c
CC:  nsh_ddcmd.c
CC:  nsh_proccmds.c
CC:  nsh_mmcmds.c
CC:  nsh_timcmds.c
CC:  nsh_envcmds.c
CC:  nsh_syscmds.c
CC:  nsh_dbgcmds.c
CC:  nsh_session.c
CC:  nsh_fsutils.c
CC:  nsh_consolemain.c
AR:   nsh_init.o nsh_parse.o nsh_console.o nsh_script.o nsh_system.o nsh_command.o nsh_fscmds.o nsh_ddcmd.o nsh_proccmds.o nsh_mmcmds.o nsh_timcmds.o nsh_envcmds.o nsh_syscmds.o nsh_dbgcmds.o nsh_session.o nsh_fsutils.o nsh_consolemain.o
make[2]: Leaving directory '/home/alan/apps/nshlib'
make[2]: Entering directory '/home/alan/apps/system/readline'
CC:  readline.c
CC:  readline_common.c
AR:   readline.o readline_common.o
make[2]: Leaving directory '/home/alan/apps/system/readline'
make[2]: Entering directory '/home/alan/apps/platform'
AR:   
make[2]: Leaving directory '/home/alan/apps/platform'
make[1]: Leaving directory '/home/alan/apps'
make[1]: Entering directory '/home/alan/nuttx-project/fs'
CC:  fs_initialize.c
CC:  inode/fs_files.c
CC:  inode/fs_foreachinode.c
CC:  inode/fs_inode.c
CC:  inode/fs_inodeaddref.c
CC:  inode/fs_inodebasename.c
CC:  inode/fs_inodefind.c
CC:  inode/fs_inodefree.c
CC:  inode/fs_inoderelease.c
CC:  inode/fs_inoderemove.c
CC:  inode/fs_inodereserve.c
CC:  inode/fs_inodesearch.c
CC:  inode/fs_filedetach.c
CC:  vfs/fs_close.c
CC:  vfs/fs_dup.c
CC:  vfs/fs_dup2.c
CC:  vfs/fs_fcntl.c
CC:  vfs/fs_dupfd.c
CC:  vfs/fs_dupfd2.c
CC:  vfs/fs_epoll.c
CC:  vfs/fs_fstat.c
CC:  vfs/fs_fstatfs.c
CC:  vfs/fs_getfilep.c
CC:  vfs/fs_ioctl.c
CC:  vfs/fs_lseek.c
CC:  vfs/fs_mkdir.c
CC:  vfs/fs_open.c
CC:  vfs/fs_poll.c
CC:  vfs/fs_read.c
CC:  vfs/fs_rename.c
CC:  vfs/fs_rmdir.c
CC:  vfs/fs_statfs.c
CC:  vfs/fs_stat.c
CC:  vfs/fs_select.c
CC:  vfs/fs_unlink.c
CC:  vfs/fs_write.c
CC:  vfs/fs_pread.c
CC:  vfs/fs_pwrite.c
CC:  vfs/fs_link.c
CC:  vfs/fs_readlink.c
CC:  vfs/fs_fdopen.c
CC:  driver/fs_registerdriver.c
CC:  driver/fs_unregisterdriver.c
CC:  dirent/fs_closedir.c
CC:  dirent/fs_opendir.c
CC:  dirent/fs_readdir.c
CC:  dirent/fs_rewinddir.c
CC:  dirent/fs_seekdir.c
CC:  mmap/fs_mmap.c
AR:   fs_initialize.o fs_files.o fs_foreachinode.o fs_inode.o fs_inodeaddref.o fs_inodebasename.o fs_inodefind.o fs_inodefree.o fs_inoderelease.o fs_inoderemove.o fs_inodereserve.o fs_inodesearch.o fs_filedetach.o fs_close.o fs_dup.o fs_dup2.o fs_fcntl.o fs_dupfd.o fs_dupfd2.o fs_epoll.o fs_fstat.o fs_fstatfs.o fs_getfilep.o fs_ioctl.o fs_lseek.o fs_mkdir.o fs_open.o fs_poll.o fs_read.o fs_rename.o fs_rmdir.o fs_statfs.o fs_stat.o fs_select.o fs_unlink.o fs_write.o fs_pread.o fs_pwrite.o fs_link.o fs_readlink.o fs_fdopen.o fs_registerdriver.o fs_unregisterdriver.o fs_closedir.o fs_opendir.o fs_readdir.o fs_rewinddir.o fs_seekdir.o fs_mmap.o
make[1]: Leaving directory '/home/alan/nuttx-project/fs'
make[1]: Entering directory '/home/alan/nuttx-project/binfmt'
CC:  binfmt_globals.c
CC:  binfmt_register.c
CC:  binfmt_unregister.c
CC:  binfmt_loadmodule.c
CC:  binfmt_unloadmodule.c
CC:  binfmt_execmodule.c
CC:  binfmt_exec.c
CC:  binfmt_copyargv.c
CC:  binfmt_dumpmodule.c
AR:   binfmt_globals.o binfmt_register.o binfmt_unregister.o binfmt_loadmodule.o binfmt_unloadmodule.o binfmt_execmodule.o binfmt_exec.o binfmt_copyargv.o binfmt_dumpmodule.o
make[1]: Leaving directory '/home/alan/nuttx-project/binfmt'
make[1]: Entering directory '/home/alan/nuttx-project/arch/arm/src'
make[2]: Entering directory '/home/alan/nuttx-project/configs/stm32f103-minimum/src'
CC:  stm32_boot.c
CC:  stm32_bringup.c
CC:  stm32_spi.c
CC:  stm32_userleds.c
AR:   stm32_boot.o stm32_bringup.o stm32_spi.o stm32_userleds.o 
make[2]: Leaving directory '/home/alan/nuttx-project/configs/stm32f103-minimum/src'
LD: nuttx
make[1]: Leaving directory '/home/alan/nuttx-project/arch/arm/src'
CP: nuttx.bin

Now let see the NuttX’s “hello world” size:

$ arm-none-eabi-size nuttx
   text	   data	    bss	    dec	    hex	filename
  15068	     84	   1676	  16828	   41bc	nuttx

So, the NuttX’s helloworld is about 15KB.

Time to compile and compare Zephyr:

$ git clone https://gerrit.zephyrproject.org/r/zephyr zephyr-project
$ cd zephyr-project/
$ git checkout tags/v1.6.0
$ export ZEPHYR_BASE=/home/alan/zephyr-project
$ export ZEPHYR_GCC_VARIANT=gccarmemb
$ export GCCARMEMB_TOOLCHAIN_PATH=/usr
$ cd samples/hello_world/
$ make BOARD=frdm_k64f
make[1]: Entering directory '/home/alan/zephyr/zephyr-project'
make[2]: Entering directory '/home/alan/zephyr/zephyr-project/samples/hello_world/outdir/frdm_k64f'
  GEN     ./Makefile
scripts/kconfig/conf --silentoldconfig Kconfig
  Using /home/alan/zephyr/zephyr-project as source for kernel
  GEN     ./Makefile
  CHK     include/generated/version.h
  UPD     include/generated/version.h
  CHK     misc/generated/configs.c
  UPD     misc/generated/configs.c
  CHK     include/generated/offsets.h
  UPD     include/generated/offsets.h
  CHK     misc/generated/sysgen/prj.mdef
  UPD     misc/generated/sysgen/prj.mdef
  LD      lib/iot/built-in.o
  LD      lib/libc/minimal/source/stdlib/built-in.o
  CC      lib/libc/minimal/source/stdout/fprintf.o
  CC      lib/libc/minimal/source/stdout/prf.o
  CC      lib/libc/minimal/source/stdout/sprintf.o
  CC      lib/libc/minimal/source/stdout/stdout_console.o
  LD      lib/libc/minimal/source/stdout/built-in.o
  CC      lib/libc/minimal/source/string/string.o
  LD      lib/libc/minimal/source/string/built-in.o
  LD      lib/libc/minimal/source/built-in.o
  LD      lib/libc/minimal/built-in.o
  LD      lib/libc/built-in.o
  LD      lib/built-in.o
  CC      misc/printk.o
  LD      misc/debug/built-in.o
  CC      misc/generated/configs.o
  CC      misc/generated/sysgen/kernel_main.o
  LD      misc/generated/sysgen/built-in.o
  LD      misc/generated/built-in.o
  LD      misc/built-in.o
  LD      net/built-in.o
  LD      boards/arm/frdm_k64f/built-in.o
  LD      boards/built-in.o
  LD      ext/fs/built-in.o
  CC      ext/hal/ksdk/devices/MK64F12/fsl_clock.o
  LD      ext/hal/ksdk/components/built-in.o
  LD      ext/hal/ksdk/drivers/built-in.o
  LD      ext/hal/ksdk/built-in.o
  LD      ext/hal/built-in.o
  LD      ext/lib/crypto/built-in.o
  LD      ext/lib/built-in.o
  LD      ext/built-in.o
  LD      subsys/built-in.o
  LD      tests/built-in.o
  AS      arch/arm/core/exc_exit.o
  CC      arch/arm/core/irq_init.o
  AS      arch/arm/core/swap.o
  CC      arch/arm/core/fault.o
  CC      arch/arm/core/irq_manage.o
  CC      arch/arm/core/thread.o
  AS      arch/arm/core/cpu_idle.o
  AS      arch/arm/core/fault_s.o
  AS      arch/arm/core/isr_wrapper.o
  CC      arch/arm/core/fatal.o
  CC      arch/arm/core/sys_fatal_error_handler.o
  CC      arch/arm/core/thread_abort.o
  AS      arch/arm/core/cortex_m/vector_table.o
  AS      arch/arm/core/cortex_m/reset.o
  AS      arch/arm/core/cortex_m/nmi_on_reset.o
  CC      arch/arm/core/cortex_m/prep_c.o
  CC      arch/arm/core/cortex_m/scs.o
  CC      arch/arm/core/cortex_m/scb.o
  CC      arch/arm/core/cortex_m/nmi.o
  CC      arch/arm/core/cortex_m/exc_manage.o
  CC      arch/arm/core/cortex_m/irq_vector_table.o
  AS      arch/arm/core/cortex_m/sw_isr_table.o
  LD      arch/arm/core/cortex_m/built-in.o
  LD      arch/arm/core/built-in.o
  CC      arch/arm/soc/nxp_kinetis/k6x/soc_config.o
  CC      arch/arm/soc/nxp_kinetis/k6x/soc.o
  AS      arch/arm/soc/nxp_kinetis/k6x/wdog.o
  LD      arch/arm/soc/nxp_kinetis/k6x/built-in.o
  LD      arch/arm/soc/nxp_kinetis/built-in.o
  LD      arch/arm/built-in.o
  LD      arch/built-in.o
  CC      drivers/console/uart_console.o
  LD      drivers/console/built-in.o
  CC      drivers/gpio/gpio_k64.o
  LD      drivers/gpio/built-in.o
  LD      drivers/interrupt_controller/built-in.o
  CC      drivers/pinmux/k64/pinmux.o
  CC      drivers/pinmux/k64/pinmux_board_frdm_k64f.o
  LD      drivers/pinmux/built-in.o
  LD      drivers/random/built-in.o
  CC      drivers/serial/uart_k20.o
  LD      drivers/serial/built-in.o
  CC      drivers/timer/cortex_m_systick.o
  CC      drivers/timer/sys_clock_init.o
  LD      drivers/timer/built-in.o
  LD      drivers/built-in.o
  CC      kernel/unified/version.o
  LD      kernel/unified/built-in.o
  CC      kernel/unified/alert.o
  CC      kernel/unified/device.o
  CC      kernel/unified/errno.o
  CC      kernel/unified/fifo.o
  CC      kernel/unified/idle.o
  CC      kernel/unified/init.o
  CC      kernel/unified/legacy_offload.o
  CC      kernel/unified/legacy_timer.o
  CC      kernel/unified/lifo.o
  CC      kernel/unified/mailbox.o
  CC      kernel/unified/mem_pool.o
  CC      kernel/unified/mem_slab.o
  CC      kernel/unified/msg_q.o
  CC      kernel/unified/mutex.o
  CC      kernel/unified/pipes.o
  CC      kernel/unified/sched.o
  CC      kernel/unified/sem.o
  CC      kernel/unified/stack.o
  CC      kernel/unified/sys_clock.o
  CC      kernel/unified/system_work_q.o
  CC      kernel/unified/thread.o
  CC      kernel/unified/thread_abort.o
  CC      kernel/unified/timer.o
  CC      kernel/unified/work_q.o
  AR      kernel/unified/lib.a
  CC      src/main.o
  LD      src/built-in.o
  AR      libzephyr.a
  LINK    zephyr.lnk
  BIN     zephyr.bin
make[2]: Leaving directory '/home/alan/zephyr/zephyr-project/samples/hello_world/outdir/frdm_k64f'
make[1]: Leaving directory '/home/alan/zephyr/zephyr-project'

And the size is:

$ arm-none-eabi-size outdir/frdm_k64f/zephyr.elf 
   text	   data	    bss	    dec	    hex	filename
  10226	    400	   7808	  18434	   4802	outdir/frdm_k64f/zephyr.elf

Then Zephyr’s size is about 10KB!

Maybe you could think: “Oh, NuttX is 50% bigger!”, but you are wrong here.

First: NuttX is a real POSIX RTOS, the helloworld example use the POSIX printf() function. Zephyr is not POSIX and it uses a limited/trimmed-down printk() function.

Second: as you saw NuttX compiled many more files and this simple helloworld includes File System support and the structure to support Device Drivers.

Third: this 15KB is only the initial overhead, probably NuttX increases more slowly than Zephyr because NuttX is very modular and its features are separated in many files.

Testing LLVM LIBC++ on NuttX

Clone NuttX:

$ git clone https://bitbucket.org/nuttx/nuttx

Clone NuttX’s Apps:

$ git clone https://bitbucket.org/nuttx/apps

Clone libc++ for NuttX:

$ git clone https://bitbucket.org/acassis/libcxx

Install the libc++ on NuttX:

cd libcxx
$ ./install.sh ../nuttx/
Installing LLVM/libcxx in the NuttX source tree
Installation suceeded

Modify the HelloXX example to use sstream:

$ cd ..
$ cd apps

Download 0001-Modify-helloxx-to-test-sstream.patch: https://gist.github.com/acassis/504e86d992a2fc459784c6284aa90e53

Apply it:

$ git am 0001-Modify-helloxx-to-test-sstream.patch

Add (l)gamma to NuttX and add helloxx example:

$ cd ..
$ cd nuttx

Download 0001-Add-gamma-and-lgamma.patch: https://gist.github.com/acassis/4fc95d3ecba3c4829eac303d5704dc76

Apply it:

$ git am 0001-Add-gamma-and-lgamma.patch

Download 0001-Add-helloxx-C-example-to-STM32F4Discovery.patch: https://gist.github.com/acassis/b17e90835eeffb58a35651a4e0d0503d

Apply it:

$ git am 0001-Add-helloxx-C-example-to-STM32F4Discovery.patch

Configure NuttX to use the helloxx example:

$ cd tools
$ ./configure.sh stm32f4discovery/helloxx

Compile it:

$ cd ..
$ make

Flash it:

$ sudo openocd -f interface/stlink-v2.cfg -f target/stm32f4x.cfg -c init -c "reset halt" -c "flash write_image erase nuttx.bin 0x08000000"

Restart NuttX, you should see:

Hello World! 42                                                              
helloxx_main: Saying hello from the dynamically constructed instance         
CHelloWorld::HelloWorld: Hello, World!!                                      
Hello World! 42                                                              
helloxx_main: Saying hello from the instance constructed on the stack        
CHelloWorld::HelloWorld: Hello, World!! 
helloxx_main: Saying hello from the statically constructed instance
CHelloWorld::HelloWorld: Hello, World!! 

Using NuttX as a library

It is possible to use NuttX as library, then you don’t need to compile the source code all the time, just modify your application and link it against the NuttX library.

Here I will explain step-by-step how to do that.

I will consider that you just entered on nuttx/tools and executed the ./configure.sh to select your board and your application profile (here my application is called “hello” and CONFIG_USER_ENTRYPOINT=”hello_main”). Then now instead of executing “make” to compile the source code you should to execute:

make export

If everything worked as expected you will get the file “nuttx-export.zip”. Extract this file and create your application inside it. Here I create a hello.c file with it:

#include 

int hello_main(void)
{
        printf("Hello World!\n");
        return 0;
}

Now I compiled it this way:

$ arm-none-eabi-gcc -c -fno-builtin -Wall -Wstrict-prototypes -Wshadow -Wundef -g -mcpu=cortex-m4 -mthumb -mfloat-abi=soft -I. -isystem ./include   -pipe -I "./include"  hello.c -o  hello.o

We just need to link again libnuttx.a to generate our nuttx ELF:

$ arm-none-eabi-ld --entry=__start -nostartfiles -nodefaultlibs -T./build/spificonfig.ld -L./libs hello.o -o nuttx.elf --start-group -lnuttx "/usr/lib/gcc/arm-none-eabi/6.2.1/thumb/v7e-m/libgcc.a" --end-group

And to generate the finaly binary from the ELF:

$ arm-none-eabi-objcopy -S -O binary nuttx.elf nuttx.bin

It is also a good idea to generate the map of symbols with the physical address of each function:

$ arm-none-eabi-nm nuttx.elf | \
grep -v '\(compiled\)\|\(\.o$\)\|\( [aUw] \)\|\(\.\.ng$\)\|\(LASH[RL]DI\)' | \
sort > System.map

Well done, now just flash it using OpenOCD and STLink-V2 :

$ sudo openocd -f interface/stlink-v2.cfg -f target/lpc4330.cfg -c init -c "reset halt" -c "flash write_image erase nuttx.bin 0x14000000"
Open On-Chip Debugger 0.10.0 (2017-02-12-09:48)
Licensed under GNU GPL v2
For bug reports, read
	http://openocd.org/doc/doxygen/bugs.html
Info : auto-selecting first available session transport "hla_swd". To override use 'transport select '.
adapter speed: 500 kHz
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
Info : Unable to match requested speed 500 kHz, using 480 kHz
Info : Unable to match requested speed 500 kHz, using 480 kHz
Info : clock speed 480 kHz
Info : STLINK v2 JTAG v17 API v2 SWIM v4 VID 0x0483 PID 0x3748
Info : using stlink api v2
Info : Target voltage: 3.273164
Info : lpc4350.m4: hardware has 6 breakpoints, 4 watchpoints
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x10402c40 msp: 0x10087ff0
auto erase enabled
Info : Found flash device 'win w25q64cv' (ID 0x001740ef)
Warn : no flash bank found for address 28000000
Warn : no flash bank found for address 280074c4
wrote 0 bytes from file nuttx.bin in 0.087209s (0.000 KiB/s)

Using LPCScrypt to flash firmware on Bambino board

I decided to use LPCScrypt from NXP to flash the Bambino-200E board. This way other people could to flash NuttX inside the board without a JTAG/SWD programmer, because LPCScrypt uses DFU to do that.

Initially I downloaded the LPCScrypt 1.8 for Linux from NXP site: http://www.nxp.com/products/microcontrollers-and-processors/arm-processors/lpc-cortex-m-mcus/software-tools/lpc-microcontroller-utilities/lpcscrypt-v1.8.0:LPCSCRYPT

I read the documentation and installed the dependencies and support to run 32-bits application. But LPCScrypt installer was not starting:

$ ./lpcscrypt_1.8.0_723_Linux-x86 
invalid command name "bind"
    while executing
"::unknown bind Text "
    ("uplevel" body line 1)
    invoked from within
"uplevel 1 $next $args"
    (procedure "::obj::Unknown" line 3)
    invoked from within
"bind Text "
    (procedure "::InstallJammer::InitializeGui" line 19)
    invoked from within
"::InstallJammer::InitializeGui "
    (procedure "::InstallJammer::InitInstall" line 68)
    invoked from within
"::InstallJammer::InitInstall"
    (file "/installkitvfs/main.tcl" line 22457)

Fortunately Jim Wolfman from Smoothie project had the LPCScrypt as a tar ball, then I don’t need to install:

$ wget blog.wolfman.com/files/lpcscrypt.tgz
$ tar xvf lpcscrypt.tgz

I need to create a udev rule to avoid the USB CDC/ACM port be used as modem:

$ sudo vi /etc/udev/rules.d/99-lpcscrypt.rules
SUBSYSTEM=="usb", ATTRS{idVendor}=="1fc9", ATTRS{idProduct}=="000c", MODE="0666"
SUBSYSTEM=="tty", ATTRS{idVendor}=="1fc9", ATTRS{idProduct}=="0083", MODE="0666"
ATTRS{idVendor}=="1fc9", ATTRS{idProduct}=="0083", ENV{ID_MM_DEVICE_IGNORE}="1"

Also you need to install the dfu-util program before using the lpcscrypt.

So, now jump/connect the two pins of BOOT (JP1) and reset the board. The board will enter on DFU mode, then you can execute the boot_lpcscrypt:

$ sudo ./lpcscrypt/scripts/boot_lpcscrypt

If the above command fails, you can try to run it manually:

$ sudo dfu-util -d 0x1fc9:0x000c -c 0 -i 0 -t 2048 -R  -D ./lpcscrypt/bin/LPCScrypt_140.bin.hdr

You can run dmesg to see if ttyACM0 was detected after running the LPCScrypt binary.

Finally you can run this command to flash nuttx.bin inside the external flash of Bambino board:

$ ./lpcscrypt/bin/lpcscrypt program -d /dev/ttyACM0 +c nuttx.bin SPIFI

That is it. I hope it works for you too.