Keeping your bitbucket repo in sync with upstream

I imported the NuttX repository to my bitbucket account with name nuttx_nyx (for NyX board). Then I want to keep it in sync with mainline/upstream without accessing the bitbucket page to click on “Sync” button.

So you just need to add the upstream remote:

$ git remote add upstream https://bitbucket.org/nuttx/nuttx

Then we have two remotes now:

$ git remote -v

origin	https://bitbucket.org/acassis/nuttx_nyx (fetch)
origin	https://bitbucket.org/acassis/nuttx_nyx (push)

upstream	https://bitbucket.org/nuttx/nuttx (fetch)
upstream	https://bitbucket.org/nuttx/nuttx (push)

Then when you fetch from upstream it will be putted on you origin/master:

$ git fetch upstream
From https://bitbucket.org/nuttx/nuttx
   afe137f..fe7d8c9  master     -> origin/master

Fine, now just do the default way:

$ git push origin master

You can create your local commit and rebase it with be on top of upstream and saved to your repository.

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

Compiling sigrok and pulseview

Install the dependencies:

$ sudo apt-get install automake libudev-dev checkinstall libglib2.0-dev libftdi-dev sdcc python3-dev qt-sdk libboost-system-dev libboost-thread-dev libboost-filesystem-dev libqt5svg5-dev libglibmm-2.4-dev libboost1.58-all-dev

Clone the repositories:

$ git clone git://sigrok.org/libsigrok
$ git clone git://sigrok.org/libsigrokdecode
$ git clone git://sigrok.org/sigrok-cli
$ git clone git://sigrok.org/pulseview

Compile them all:

$ cd libsigrok
$ ./autogen.sh
$ ./configure
$ make
$ sudo checkinstall

$ cd libsigrokdecode
$ ./autogen.sh
$ ./configure
$ make
$ sudo checkinstall

$ cd sigrok-cli
$ ./autogen.sh
$ ./configure
$ make
$ sudo checkinstall

$ cd pulseview
$ cmake .
$ make
$ sudo checkinstall

Reduzing Memory consumption: Smaller Vector Tables

I want to reduce the memory consumption to NuttX in the stm32f103-minimum board to get external SPI NOR Flash with SmartFS and USB Serial Console at same time.

After mount the SmartFS partition I will have only 808 bytes of RAM:

nsh> free
 total used free largest
Mem: 17536 15352 2184 2184
nsh> mksmartfs /dev/smart0p1
nsh> free
 total used free largest
Mem: 17536 15352 2184 2184
nsh> mount -t smartfs /dev/smart0p1 /mnt
nsh> free
 total used free largest
Mem: 17536 16728 808 808
nsh>

Analyzing which features are consumpting more RAM I notice the interruption vector table is the using more than 600 bytes:

$ arm-none-eabi-nm --print-size --size-sort --radix dec -C nuttx | grep ' [DdBb] ' | tail -20
536873088 00000008 B g_sigpendingirqaction
536873096 00000008 B g_sigpendingirqsignal
536873104 00000008 B g_sigpendingsignal
536872252 00000008 B g_waitingforsemaphore
536872280 00000008 B g_waitingforsignal
536873124 00000008 B g_wdactivelist
536873112 00000008 B g_wdfreelist
536872436 00000016 B g_hpwork
536873296 00000028 B g_spawn_parms
536871024 00000028 d g_spi1dev
536871860 00000028 b g_syslog_dev
536870912 00000092 d g_usart1priv
536871764 00000096 b g_wdpool
536872288 00000128 B g_pidhash
536873132 00000164 B g_mmheap
536871564 00000188 b g_idletcb
536871308 00000256 b g_usart1rxbuffer
536871052 00000256 b g_usart1txbuffer
536871888 00000328 b g_usbdev
536872452 00000608 B g_irqvector

Fortunately there is an option to reduce it:

http://www.nuttx.org/doku.php?id=wiki:howtos:smallvectors

Keep tuned!

Issues compiling OSD Lyrics

I love the OSD Lyrics, it is very good the see music lyrics in the Linux computer.

After cloning it from https://github.com/osdlyrics/osdlyrics and executing:

$ ./autogen.sh
...
checking for GTK2... yes
checking for X11... yes
checking for DBUS_GLIB... yes
checking for NOTIFY... yes
./configure: line 8541: syntax error near unexpected token `0.35.0'
./configure: line 8541: `IT_PROG_INTLTOOL(0.35.0)'

I installed the packet:

$ sudo apt-get install intltool

Finally:

$ make
$ sudo make install

Source: https://github.com/pastcompute/mtools/issues/2