Home Assistent

This is the probably the fourth home automation project that cited here.

The project page:

https://home-assistant.io

It has integration with NEST products, Hue lamp and many other services.

Thanks Fred to this tip!

Advertisements

Programming Smoothieboard V2 Mini

I’m testing the Smoothieboard V2 Mini

The JP10 (BOOT2) is in the position 0 (tied to ground) because I will program it using SWD instead using the LPCScript DFU/bootloader.

First we need to clone the repositories:

$ git clone https://github.com/Smoothieware/smoothie-nuttx
$ git clone https://github.com/Smoothieware/smoothie-v2

Enter inside “smoothie-nuttx” and compile the nuttx for smoothie v2 mini alpha:

$ cd smoothie-nuttx
$ cd nuttx
$ cd tools
$ ./configure.sh smoothiev2-mini-alpha/smoothiedev
$ cd ..
$ make export
...
CC:  lpc43_ostest.c
CC:  lpc43_autoleds.c
CC:  lpc43_timer.c
AR:   lpc43_boot.o lpc43_appinit.o lpc43_mmcsd.o lpc43_highpri.o lpc43_ostest.o lpc43_autoleds.o lpc43_timer.o 
make[2]: Leaving directory '/smoothie-nuttx/nuttx/configs/smoothiev2-mini-alpha/src'
make[1]: Leaving directory '/smoothie-nuttx/nuttx/arch/arm/src'

Just confirm the the file “nuttx-export.zip” was created correctly:

$ ls -l nuttx-export.zip 
-rw-rw-r-- 1 alan alan 2932905 Set  3 20:00 nuttx-export.zip

We need to copy this file to smoothie-v2 directory to compile the final firmware:

$ cp nuttx-export.zip ../../smoothie-v2/Firmware/

Then go to there and decompress the nuttx-export:

$ cd ../../smoothie-v2/Firmware/
$ unzip nuttx-export.zip
...
  inflating: nuttx-export/include/machine/_types.h  
  inflating: nuttx-export/include/machine/ieeefp.h  
  inflating: nuttx-export/include/math.h

Case you are using a version of gcc crosscompiler different from 6.3.1:

$ arm-none-eabi-gcc -v
...
Thread model: single
gcc version 6.3.1 20170620 (release) [ARM/embedded-6-branch revision 249437] (GNU Tools for ARM Embedded Processors 6-2017-q2-update) 

Then you need to export the variable the “ARMVERSION” with your version, see the Rakefile for more info.

We can compile the Unit Tests just executing:

$ rake testing=1
...
Compiling /tmp/smoothie-v2/Firmware/TestUnits/TEST_timer1.cpp for Bambino
Compiling /tmp/smoothie-v2/Firmware/TestUnits/main.cpp for Bambino
Linking for Bambino
   text	   data	    bss	    dec	    hex	filename
 394553	   1128	  11800	 407481	  637b9	smoothiev2_Bambino/smoothiev2.elf

Finally enter inside “smoothiev2_Bambino” and flash the firmware.

I’m using a STLink-v2 clone (low cost: about U$ 2.00) with only three pins: SWDIO, SWCLK and GND connected to JTAG header of the board:

$ cd smoothiev2_Bambino
$ sudo openocd -f interface/stlink-v2.cfg -f target/lpc4330.cfg -c init -c "reset halt" -c "flash write_image erase smoothiev2.bin 0x14000000"
Open On-Chip Debugger 0.10.0+dev-00172-g7719e96 (2017-08-24-16:57)
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.270400
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)
target halted due to breakpoint, current mode: Thread 
xPSR: 0x61000000 pc: 0x10000154 msp: 0x10087ff0
target halted due to breakpoint, current mode: Thread 
xPSR: 0x61000000 pc: 0x10000198 msp: 0x10087ff0
wrote 458752 bytes from file smoothiev2.bin in 12.150717s (36.870 KiB/s)

Connect the serial console and you will get:


Starting tests...
There are 35 registered tests...
  PlannerQueue-basic
  PlannerQueue-iteration
  ConfigTest-get_sections
  ConfigTest-load_section
  ConfigTest-load_sub_sections
  Dispatcher-check_callbacks
  Dispatcher-Remove_second_G1_handler
  Dispatcher-one_off_dispatch
  GCodeTest-basic
  GCodeTest-subcode
  GCodeTest-copy
  GCodeTest-Multiple_commands_on_line_no_spaces
  GCodeTest-Modal_G1_and_comments
  GCodeTest-Line_numbers_and_checksums
  MemoryTest-stats
  MemoryTest-AHBn
  Module-single_module
  Module-single_module_destructed
  Module-multi_module
  SDCardTest-mount
  SDCardTest-directory
  SDCardTest-write_read
  SDCardTest-read_config_init
  SDCardTest-unmount
  SlowTicker-test_20_hz
  SlowTicker-test_10_hz
  StreamsTest-stringstream
  StreamsTest-cout
  StreamsTest-OutputStream_null
  StreamsTest-OutputStream_sstream
  StreamsTest-OutputStream_fdstream
  StreamsTest-OutputStream_prependok
  StreamsTest-OutputStream_long_line
  TimeTest-delta_ik
  TimerTest-test_20_hz
/home/alan/nuttxspace/SmoothieProject/smoothie-v2/Firmware/TestUnits/TEST_PlannerQueue.cpp:7:PlannerQueue-basic:PAS
/home/alan/nuttxspace/SmoothieProject/smoothie-v2/Firmware/TestUnits/TEST_PlannerQueue.cpp:53:PlannerQueue-iteratiS
/home/alan/nuttxspace/SmoothieProject/smoothie-v2/Firmware/TestUnits/TEST_config.cpp:15:ConfigTest-get_sections:PAS
[(enable, false)]
/home/alan/nuttxspace/SmoothieProject/smoothie-v2/Firmware/TestUnits/TEST_config.cpp:31:ConfigTest-load_section:PAS
elapsed time 20000 us
/home/alan/nuttxspace/SmoothieProject/smoothie-v2/Firmware/TestUnits/TEST_config.cpp:51:ConfigTest-load_sub_sectioS
/home/alan/nuttxspace/SmoothieProject/smoothie-v2/Firmware/TestUnits/TEST_dispatch.cpp:51:Dispatcher-check_callbacS
/home/alan/nuttxspace/SmoothieProject/smoothie-v2/Firmware/TestUnits/TEST_dispatch.cpp:78:Dispatcher-Remove_secondS
/home/alan/nuttxspace/SmoothieProject/smoothie-v2/Firmware/TestUnits/TEST_dispatch.cpp:91:Dispatcher-one_off_dispaS
/home/alan/nuttxspace/SmoothieProject/smoothie-v2/Firmware/TestUnits/TEST_gcode.cpp:7:GCodeTest-basic:PASS
/home/alan/nuttxspace/SmoothieProject/smoothie-v2/Firmware/TestUnits/TEST_gcode.cpp:31:GCodeTest-subcode:PASS
/home/alan/nuttxspace/SmoothieProject/smoothie-v2/Firmware/TestUnits/TEST_gcode.cpp:52:GCodeTest-copy:PASS
/home/alan/nuttxspace/SmoothieProject/smoothie-v2/Firmware/TestUnits/TEST_gcode.cpp:80:GCodeTest-Multiple_commandsS
/home/alan/nuttxspace/SmoothieProject/smoothie-v2/Firmware/TestUnits/TEST_gcode.cpp:100:GCodeTest-Modal_G1_and_comS
/home/alan/nuttxspace/SmoothieProject/smoothie-v2/Firmware/TestUnits/TEST_gcode.cpp:118:GCodeTest-Line_numbers_andS
             total       used       free    largest
Mem:        191152      41840     149312     115232
/home/alan/nuttxspace/SmoothieProject/smoothie-v2/Firmware/TestUnits/TEST_mem.cpp:7:MemoryTest-stats:PASS
/home/alan/nuttxspace/SmoothieProject/smoothie-v2/Firmware/TestUnits/TEST_mem.cpp:16:MemoryTest-AHBn:PASS
/home/alan/nuttxspace/SmoothieProject/smoothie-v2/Firmware/TestUnits/TEST_module.cpp:18:Module-single_module:PASS
/home/alan/nuttxspace/SmoothieProject/smoothie-v2/Firmware/TestUnits/TEST_module.cpp:40:Module-single_module_destrS
/home/alan/nuttxspace/SmoothieProject/smoothie-v2/Firmware/TestUnits/TEST_module.cpp:62:Module-multi_module:PASS
/home/alan/nuttxspace/SmoothieProject/smoothie-v2/Firmware/TestUnits/TEST_sdcard.cpp:26:SDCardTest-mount:FAIL: Exp1

-----------------------
20 Tests 1 Failures 0 Ignored 
FAIL
Done

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.

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