Hacking the DPS5005

Some time ago I found the DPS5005 while browsing AliExpress for programmable power supplies. To be honest, I dismissed the ‘5005 since it was not a complete product. Then HAD wrote about it in december last year and after watching YouTube user @iforce2d’s video I just had to get one. The overall impression was quite good but the software was a bit cluttered and the DPS5005 could not be instrumented via a serial port (or wifi). Looking closely at the sandwich PCB design I noticed the DPS is powered by an STM32, which is pretty much what I expected. And so begun the OpenDPS project, a free firmware replacement for the DPS5005 and friends.

OpenDPS, wifi connected
OpenDPS, wifi connected

This write up of the OpenDPS project is divided into three parts. Part one (this one) covers reverse engineering the stock firmware and could be of interest for those looking at reverse engineering STM32 devices in general. Part two covers the design of OpenDPS, the name given to the open DPS5005 firmware. Part three covers the upgrade process of stock DPS:es and connecting these to the world. If you only want to upgrade your DPS you may skip directly to part three.

Reverse engineering the DPS5005

The reverse engineering of the DPS5005 can be summarised as “bring up of the STM32 based DPS5005 hardware and writing an application for it”. This is pretty much my day job but I always have the hardware schematics and the hardware design engineer at hand. This time, obviously, I had neither which was a bit more challenging. So where does one start? Looking at the PCB, I quickly found the serial port. That was a dud, completely silent. Fake port! I later realised the DPS5005 stock firmware does not even initialise the serial port. The STM32 is covered by the TFT display, which in turn is soldered using eight pins. As I did not have the time to play with iron and solder wick I resorted to a metal saw and promptly sawed the TFT display off (please note this is not the unit in the pictures below).

SWO pinout
Top: SWO pinout, UART below

Warranty voided, oh there actually was none to begin with. Having the STM32 in the open quickly allowed me to identify the five test points at the top of the PCB, the expected SWO trace port. But had the producers locked the SWO port when flashing the firmware? Luckily, no.

Debugger connected
Debugger connected

After some soldering, connecting an STLink clone and selecting an appropriate OpenOCD configuration for the STM32F100, I had a go at it:

% openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg
GNU ARM Eclipse 64-bits Open On-Chip Debugger 0.10.0-dev-00498-gbbfb673 (2016-10-28-19:13)
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 <transport>'.
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
adapter speed: 1000 kHz
adapter_nsrst_delay: 100
none separate
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : clock speed 950 kHz
Info : STLINK v2 JTAG v17 API v2 SWIM v4 VID 0x0483 PID 0x3748
Info : using stlink api v2
Info : Target voltage: 3.245093
Info : stm32f1x.cpu: hardware has 6 breakpoints, 4 watchpoints

Yay! Next I connected to OpenOCD to examine the target:

% telnet localhost 4444

> halt
> stm32f1x options_read 0
Option Byte: 0x3fffffe
Readout Protection On
Software Watchdog
Stop: No reset generated
Standby: No reset generated
User Option0: 0xff
User Option1: 0xff

So “readout protection” is enabled which mean you cannot read the firmware from flash. Not a biggie as I was not interested in the stock firmware in itself, only what it controlled. So what would be needed to create the OpenDPS firmware?

  • Learn how buttons and other IOs are connected.
  • What STM32 peripheral drives what function?
  • Controlling the output voltage (controlled by the DAC?)
  • Current limiter (maybe ADC?)
  • Measuring input and output voltage (definitely ADC)
  • Dimmable TFT (not needed 🙂
  • Write a TFT driver

To assist, I created a Python script (ocd-client.py) connecting to OpenOCD for dumping various STM32 device registers. Eg, by dumping the entire DAC register area I could determine the DAC was in use. The buttons I could identify by dumping the GPIO input registers, pressing the button and dumping the registers again. The entire GPIO setup can be recreated by this script and I learned the output voltage really is driven by the DAC. The TFT backlight is driven by timer 4 and the output current, input voltage and output voltage are measured using ADC1 on channels 7, 8 and 9. The 1.44″ TFT is an ILI9163C and I used @SumoToy’s driver for this. The SPI select pin for the display is grounded which is a clever way of saving one pin for designs where there is only one device connected on the SPI bus. Additionally, the display does not use the MISO pin. The most important thing now was how to control the DAC to set a desired output voltage, how to interpret the ADC1 values measuring the output voltage, current draw and input voltage. Normally, one would look at the schematics to figure out what an ADC reading means but in this case I had to reverse engineer that. I simply connected a multimeter, tried a few settings on the stock firmware, observed the ADC1 reading and plotted the result. Next, I created a simple application using the lovely libopencm3 and tested in on a “Bluepill” before wiping the DPS5005. Telnetting to port 4444 again I tried:

> reset halt
> flash erase_address unlock 0x08000000 0x10000
Device Security Bit Set
stm32f1x.cpu: target state: halted
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000003a msp: 0x20000800
stm32x device protected
failed erasing sectors 0 to 63

Failed! Hmmm, let’s do a power cycle, restart OpenOCD and try that again.

> flash erase_address unlock 0x08000000 0x10000
device id = 0x10016420
flash size = 64kbytes
erased address 0x08000000 (length 65536) in 0.094533s (677.012 KiB/s)

Now that’s better! I am not sure why it fails the first time, it did so on both my units but succeeded on the second attempt. A simple ‘make flash’ and the display showed my test pattern and the power output was at the expected 5V. Mission, partly, accomplished! I could reflash the DPS5005 and control the voltage setting. Time to write a proper application. More in part two.

OpenDPS Design

This is the second part about hacking the DPS5005. Part one covers the reverse engineering of the DPS5005 and part three covers the process of upgrading stock DPS5005:s to OpenDPS.

 

The goal of OpenDPS is to reflash the stock DPS5005 (and friends) with a firmware that has the same functionality, has a less cluttered user interface and is remote controllable via wifi or a serial port. The application needs to respond to user input both via buttons and the serial port and also via ADC readings telling us if the current draw is larger than what we allowed. Buttons and UART RX are handled using interrupts and obviously the ADC needs to be interrupt based too for fast response (and less smoke). Responding to user input and TFT drawing can be left to the application context.

System Overview

The following modules are used in OpenDPS:

  • event – uses a ring buffer for storing events from the interrupt context to be handled in the application context. Events are button presses, received bytes on the UART and over current protection triggers
  • hw – the hardware abstraction (ADC, GPIO, …)
  • ili9631c – the TFT driver
  • opendps – main application
  • past – for storing persistent parameters in flash
  • protocol – helper for the serial protocol to instrument the OpenDPS device
  • pwrctl – power control, the DAC and calculations to convert ADC readings to eg. current draw
  • ringbuf – a ringbuffer implementation
  • spi_driver – just that
  • tft – TFT utility functions
  • tick systick handler with 1ms resolution
  • uframe – framing of serial protocol spoken
  • ui – handle the user interface

Control Flow

The application in opendps.c sits in a busy loop waiting for events to arrive in the circular buffer. Button presses, serial RX and over current protection events are placed in this buffer. The application calls the UI module that updates the UI with fresh measurements every 250ms. User input is also handled in the UI module. Events are 16 bit integers encoding the event type and optional event data. For the UART RX event the data obviously is the received byte. For button presses we also include information telling us if the press was a long press.

ADC and DAC Management

As I did not have the schematics at hand I had to reverse engineer the formula to calculate voltage/current based on ADC readings. I did some measurements and plotted in a Google Docs spreadsheet to find out

  • V_in(ADC1_IN8) – given a reading on channel 8, what is the input voltage?
  • V_out(ADC1_IN9) – given a reading on channel 9, what is the output voltage?
  • V_out(DAC) – what is the output voltage given a DAC setting? (and the inverse)
  • I_out(ADC1_IN7) – given a reading on channel 7, what is the current draw? (and the inverse)

To reduce complexity in the ADC IRQ handler, I pre calculate the ADC value that corresponds to the dialled current limit to quickly determine if we went over the limit. Here I ran into some issues as the ADC reading of the current draw differed between the two ‘5005s I had at hand. One of the units reported the wrong current draw which was tracked down to a different value when no current was drawn at all. The remedy is to take the first 1000 samples at system startup to calculate the ADC value for 0.00mA current draw and compensate in the calculations (see adc_i_offset & friends in hw.c)

Additionally, I currently collect a number of “over current samples” before triggering the OCP. This scheme needs some investigation.

Persistent Storage

User settings need to be persisted and this is taken care of by the past (parameter storage) module. This module uses two blocks for storing data. One is the “current block” and when it gets full a garbage collection is performed and the data is copied to the other block. Counters tell which block is the most recent one. In theory, power loss should not lead to corruption and/or data loss.

Graphics

An anti aliased rendering of Ubuntu Condensed is used in two different sizes for the UI. The font is found in gfx/fonts and consists of two files. The glyphs itself (eg. ubuntu_condensed_48.png) and one image describing the widths of each character (eg. ubuntu_condensed_48_width.png).

Ubuntu Condensed, 48
Ubuntu Condensed, 48

The widths are indicated by a white pixel in the first row:

Width markings
Width markings

The fonts are converted by ‘make fonts’ which invokes font-convert.py. The glyph PNG is converted to BGR565 (used by the TFT) and written to font-X.[h|c]. Each glyph is converted to a separate blob which speeds up blitting to the TFT. See tft_putch(…) in tft.c for usage. Blocking DMA is used to transfer the glyph data. One enhancement would be to have a list of DMA descriptors and fire the next DMA job in ISR context at the completion of the previous one. The icons displayed are handled in a similar manner (see eg. wifi.h) and are converted by ‘make graphics’. You should be able to change the font with little difficulty, in theory 🙂

Remote Control

The OpenDPS device can be controlled via the UART port and you can either connect an FTDI adapter or an ESP8266. The latter is the most fun. A simple serial protocol is used (see protocol.h and uframe.h). Either way you go, there is a Python script to talk to the OpenDPS device, dpsctl.py:

% dpsctl.py -h
usage: dpsctl.py [-h] [-d DEVICE] [-s] [-u VOLTAGE] [-i CURRENT] [-p POWER]
 [-P] [-L] [-l] [-S] [-j] [-v]

Instrument an OpenDPS device

optional arguments:
 -h, --help show this help message and exit
 -d DEVICE, --device DEVICE
 OpenDPS device to connect to. Can be a /dev/tty device
 or an IP number. If omitted, dpsctl.py will try the
 environment variable DPSIF
 -s, --scan Scan for OpenDPS wifi devices
 -u VOLTAGE, --voltage VOLTAGE
 Set voltage (millivolt)
 -i CURRENT, --current CURRENT
 Set maximum current (milliampere)
 -p POWER, --power POWER
 Power 'on' or 'off'
 -P, --ping Ping device
 -L, --lock Lock device keys
 -l, --unlock Unlock device keys
 -S, --status Read voltage/current settings and measurements
 -j, --json Output status as JSON
 -v, --verbose Verbose communications

The utility is agnostic as to how the OpenDPS device is connected. Provide an ip address and it will attempt to talk to that. Provide a TTY device and it will attempt to talk to that. For wifi connected DPS:es, you can provide the option –scan to find all OpenDPS devices on your network.

Any good old ESP8266 board with the UART exposed will work. Connect GND, RX and TX, build and flash esp8266-proxy (don’t forget to set your wifi credentials) and you should be good to go.

git clone https://github.com/kanflo/esp-open-rtos.git
cd esp-open-rtos
git submodule init
git submodule update
git checkout -b netif remotes/origin/sdk_system_get_netif
export EOR_ROOT=`pwd`
echo '#define WIFI_SSID "my ssid"' > include/private_ssid_config.h
echo '#define WIFI_PASS "my secret password"' >> include/private_ssid_config.h
cd /path/to/esp8266-proxy
make && make flash

Note that you currently cannot use the master branch on the main ESP Open RTOS repository as my PR for a function needed for multicast has not been merged yet.

The design of esp8266-proxy is quite minimalistic. It receives UDP packets on port 5005, sends the content on the serial port and returns the answer to the UDP source address and port.

When OpenDPS starts the wifi icon is flashing at 1Hz. When it goes steady your ESP8266 has connected to your wifi and told the OpenDPS that it is connected. Try scanning for it:

% dpsctl.py --scan
172.16.3.203
1 OpenDPS device found

Next try pinging it:

% dpsctl.py -d 172.16.3.203 --ping

The TFT should flash once as a visual indication. If you get ‘Error: timeout talking to device 172.16.3.203’, check if you swapped RX and TX. You can always connect an FTDI adapter on either RX pin on the ESP8266 and OpenDPS to debug the communication.

That concludes part two, please see part three for a description of how to upgrade your DPS5005 to an OpenDPS 5005.

Upgrading your DPS5005

This is the third article about hacking the DPS5005. Part one covers the reverse engineering of the DPS5005 and part two covers the design of OpenDPS.

 

April 14th 2017 update: is has been verified that OpenDPS can push 5A. Thanks @johannes!

June 9th 2017 update: added a note on saving the STM32 peripheral settings before wiping the internal flash.

August 31st 2017 update: updated article with the new boot loader and a note to test your device prior to unlocking.

 

Although this guide is written for the ‘5005 it should work for the entire DPS family but I only have 5005s to test with. Before we begin I should mention that the stock firmware will be gone permanently. As readout protection is enabled on the STM32, the FW cannot be extracted and I have no source for it. Additionally, I take no responsibility if you destroy your DPS. That said, let the fun begin. You will need a DPS5005 (or similar), an STLink clone and some wire. Either you solder the wire onto the DPS or you can use female-male dupont wires for flashing.

Teardown

First you need to remove the PCB from the (semi) housing. Use a small flat screwdriver to prey the PCB loose from the retaining flaps.

Teardown
Teardown

Be careful not to break the retaining flaps (not that they’re fragile, but still). They are very much needed for holding the front panel in place when you press the buttons.

If you have an older version (below left) you can solder some AWG26 wire onto the SWO and UART ports. It is advisable not to solder pin headers as there is limited room inside the housing. I added dupont jumper housings at the end of the cables to aid in connecting them to the STLink clone and FTDI ditto. Hint: make the cables “stretch” backwards, from the display. For newer versions (below right) the 1.25mm JST-GH there is little room for the SWD wires. As a bonus, you need not solder the UART cables in case you bought one of the “communications versions”.

If you do not want to solder (and do not want any remote control) (and have steady hands) you could connect three female-male dupont cables to the STLink clone and hold them pressed against the DPS while flashing.

Debugger connected, UART cable at the top
Debugger connected, UART cable at the top

Building OpenDPS

With that in place you should install OpenOCD and an ARM GCC toolchain. For GCC, Launchpad is a good place to start. For OpenOCD, YMMW. If you are on macOS you can find OpenOCD here (it installs as /Applications/GNU ARM Eclipse/OpenOCD/0.10.0-201610281609-dev/bin/openocd). With the tools in place you’re ready for the next step.

git clone --recursive https://github.com/kanflo/opendps.git
cd opendps
make -C libopencm3
make -C opendps
make -C dpsboot

Flashing

Next you need to unlock the internal flash of the STM32 before flashing (which causes a complete erase). Start OpenOCD:

cd openocd/scripts
openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg

You will receive a few lines of output ending with “Info : stm32f1x.cpu: hardware has 6 breakpoints, 4 watchpoints” if the connection was successful.

Please note! Before you unlock and erase the STM32 flash, you should make a dump of the STM32 peripheral settings of your stock DPS firmware. The DPS hardware might change at any time and if you flash OpenDPS and it does not work because eg. the GPIO pin enabling output power was changed, things get difficult. The ocd-client.py script will assist you now that OpenOCD is running. Please note that OpenOCD might interfere with the stock firmware. When you connect, the stock FW might lock up. First, power on the DPS and make sure the power output is disabled but set to e.g. 5V, start OpenOCD and type:

./ocd-client,py all > 5V-off.txt

If needed, restart the unit (and OpenOCD), enable power output @ 5V and type:

./ocd-client,py all > 5V-on.txt

Rinse and repeat for one or two more voltage levels. Check the log files, there should be no lines saying “Parsing error”. If your OpenDPS does not work, these files will enable me (or someone else, remember this is open source you 😀 ) to pinpoint the problem. Additionally, you should test the device before unlocking it. Enable power, connect something and verify that your unit actually works.

Now let’s wipe that flash. In another terminal:

telnet localhost 4444

and type:

reset halt
flash erase_address unlock 0x08000000 0x10000

You will probably get the following, ending with an error:

Device Security Bit Set
stm32f1x.cpu: target state: halted
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000003a msp: 0x20000800
stm32x device protected
failed erasing sectors 0 to 63

Keep calm. Restart OpenOCD, toggle power on the DPS and try again. This time you should see:

erased address 0x08000000 (length 65536) in 0.094533s (677.012 KiB/s)

Time to flash (flash the app first, then the boot loader):

make -C opendps flash
make -C dpsboot flash

The last two lines should read:

** Verified OK **
** Resetting Target **

and your DPS5005 is now an OpenDPS 5005.

OpenDPS
OpenDPS, now with wifi

Congratulations! If things went south somwhere, feel free to ask for help in the comments below.

From here you can use the OpenDPS as a stand alone device, control it via a serial port or control it via wifi by connecting an ESP8266.

Short User Manual

When you power on your OpenDPS, the current voltage and current limit settings are displayed and the power output is always disabled. Pressing ON/OFF will enable power output and the display will now show the measured output voltage and the measured current draw. If the screen flashes once and goes back to displaying the voltage/current settings, the over current protection kicked in. Press ON/OFF again to disable the power output.

Press the SET button to go into editing mode. Press the V and A buttons to move between the voltage and current settings. Press the rotary knob to step sideways and turn the knob to change the values. Press SET again to exit editing mode.

Press and hold the knob for two seconds to lock the keys, long press again to unlock. A long press of the SET key will invert the display.

When your OpenDPS starts it will wait for a wifi connection from a connected ESP8266 and the wifi icon will flash at 1Hz. If it does not get a wifi connection, the wifi icon will be turned off after 10 seconds. If there was an error connecting to your wifi network, the wifi icon will flash at 4Hz.

Remote Serial Control

If you soldered wires to the UART port, connect an FTDI adapter and try the dpsctl.py tool:

dpsctl.py -d /dev/tty.usb.yourdevice --ping

The TFT should flash once as a visual indication. If you get ‘Error: timeout talking to device’, check if you swapped RX and TX and/or forgot to connect GND.

The port setting can be set in an environment variable

export DPSIF=/dev/tty.usb.yourdevice

After setting the DPSIF variable, you can try setting the output voltage to 3.3V:

dpsctl.py --voltage 3300

enable the output:

dpsctl.py --power on

check the measurements:

% dpsctl.py --status
V_in : 7.71 V
V_set : 3.30 V
V_out : 3.32 V (on)
I_lim : 0.100 A
I_out : 0.040 A
Run a firmware upgrade over the serial port (extra usable for newer versions where adding SWD is a hassle):
% make -C opendps bin
% dpsctl.py -d /dev/ttyUSB0 -U opendps/opendps.bin
 If serial control is what you aimed for, you can get rid of the annoying flashing wifi icon by adding WIFI=0 when building OpenDPS
make clean ; make WIFI=0 flash

Remote Wifi Control

For wifi control, any good old ESP8266 board with the UART exposed will work. Connect GND, RX and TX, build and flash esp8266-proxy (don’t forget to set your wifi credentials) and you should be good to go.

git clone --recursive https://github.com/superhouse/esp-open-rtos.git
export EOR_ROOT=`pwd`/esp-open-rtos
echo '#define WIFI_SSID "my ssid"' > esp-open-rtos/include/private_ssid_config.h
echo '#define WIFI_PASS "my secret password"' >> esp-open-rtos/include/private_ssid_config.h
cd /path/to/esp8266-proxy
make && make flash

Note that you currently cannot use the master branch on the main ESP Open RTOS repository as my PR for a function needed for multicast has not been merged yet.

When your OpenDPS has connected to your wifi network, try the ‘scan’ command to find out its IP number:

% dpsctl.py --scan
172.16.3.203
1 OpenDPS device found

Next try pinging it:

% dpsctl.py -d 172.16.3.203 --ping

The TFT should flash once as a visual indication. If you get ‘Error: timeout talking to device 172.16.3.203’, check if you swapped RX and TX. The dpsctl.py tool has the same functionality over wifi as well as the serial port.

Sadly, you cannot power your ESP8266 from your OpenDPS. The VDD pin next to the SWO port is connected to U4 (under the TFT), an MD7133H 3.3V regulator which only provides a measly 30mA (yes, thirty). Additionally, this regulator is powered by U3 (on the backside, next to the screw terminal) which is an XL7005A supplying 400mA @ 5V which could be a bit over the edge for a power hungry, cold booting ESP8266.

 

Todos

There are a few todos in the code but overall OpenDPS should be stable for everyday use.


That’s it, have fun hacking your DPS5005!

 

The Commadorable 64

Update Aug 28th: The BOM for all variants is now on Github. Please see the notes at the end if you want to build a Commadorable 64 yourself.

The ILI9341 based QVGA displays found on eBay for €4 are well suited for making small screenlets telling the current temperature, weather forecasts, traffic situation to work and spreading them over the house. As PCB design is both fun, cheap and rewarding I did a custom PCB for these tiny displays. Actually, I made three, one for each of the 2.2″, 2.4″ and 2.8″ screens. The 2.8″ version has not been produced but the smaller variant have and work well. From 2.4″ and onwards there is (untested) touch support on the screen modules.

The “Hello World” application for this project also named the PCBs. I call them Commadorable 64. Here is why:

LEGO Stormtrooper added for size reference
LEGO Stormtrooper added for size reference

The cursor blinks but I resisted the urge to create an animated GIF. “Commadorable 64” is a play with “Commodore 64” and “adorable”. It has been scientifically proven that those for whom the Commodore 64 played a significant part of their childhood will look at the 2.2″ version of the C64 start screen and react the same way as cat people looking at kittens. Heads will be tilted slightly sideways, smiles appear and sounds like “naaaaaaaw” will be heard. I have one of these at work and depending on childhood experiences people will either go “what?” or “naaaaaaw”.

ESP side
ESP side

The PCB is soldered directly to the pins of the ILI9341 module. Some of these screens will probably end up in other applications in the future. The other day I read about openframe.io and adding support for these would be fun.

The PCBs can be ordered from DirtyPCBs.com, 2.2″ with a bonus AAduino and 2.4″ version with touch. The BOM consists of the usual components for my ESP8266 designs. We have 0603 resistors and capacitors, a 3x6x2.5mm momentary push button [eBay] for displaying the IP address, a SOT23-3 P-mosfet to control the backlight, an LM1117 voltage regulator and a SOD-123FL schottky diode for reverse power protection and optional mini USB connectors. The PCB can be powered in three different ways depending on personal preference (well, four including the esprog interface). There are footprints for normal [eBay] and vertical [eBay] mini USB connectors, depending on if the module is to stand on a table or hang from a wall (Eagle parts available on Github). In addition there is a 0.1″ header for power. All power paths are protected by the diode.

Further update Aug 28th. I see some 20+ orders on DirtyPCBs for both Commadorable 64 variants which is great fun and I would really love to hear what you will build. I have some recommendations you might find useful. I have received a few broken ESP-12e/f modules on eBay over time and one broken ILI9341 module. Because of that I always try the modules before soldering them using my Esparducam board with the ESP Pinlet add on board. When a module passes testing I flash it with the ESP Open RTOS OTA basic demo meaning I can OTA any device directly after soldering. Also, you will note there is no FTDI connector on these boards, the reason is described here. As UART output is still useful, I have one “development” variant with leads from an FTDI connector soldered to the GND/RXI/TXO esprog pads. Oh, and I also have one Commadorable 64 board with a female header for testing the ILI9341 modules before soldering them. If you have any questions about building the boards, sound off in the comments below.

Code and schematics on Github, as always.

Bridging ISM radio and wifi for lunch money

The ESP8266 has taken the maker community by storm and the hype is well deserved. Before the ESP we had the HopeRF ISM radio RFM12 and its successor RFM69. So is the ESP8266 an RFM69 killer? I would say no. Hell no even 🙂 The RFM69 is still very well suited for certain applications and the ESP8266 will not run for 2+ years on a set of AA batteries. The two can however play nicely together as a low cost ISM/wifi bridge. I did a custom PCB for this in the shape of a somewhat large USB stick, dubbed “Espism”.

 

Currently it works as an ISM sniffer posting the received packets on the MQTT topic espism-<macaddr>. Packets are posted in hex followed by the RSSI value:

espism-5ccf7f147cd Hello from 172.16.3.120
espism-5ccf7f147cd 016340630001000000c375b642[-27]
espism-5ccf7f147cd 630180[-57]

A set of four LEDs indicate received packets. Well three LEDs as I made a mistake on the ground plane. The MQTT server IP and RFM69 network information is hard coded into the binary.

I ported Andreas Heßling’s STM32 RFM driver to the lovely ESP Open RTOS, my swiss army knife for ESP8266 development. The type-A right angle 90 degreee USB connector and 3x6x2.5mm push button can be found for little money on eBay. The push button currently serves no purpose but the plan is to perform a “master reset” of the device using this button. The rest of the BOM consists of 0603 resistors and capacitors, an LM1117 3.3V regulator and a SOT23 P-mosfet for driving the 0603 LEDs. Oh, and the ESP12F talking to an RFM69CW. The BOM should add up to about the price of lunch.

Code and schematics on Github as always.

Factory programming ESP8266 gadgets

The FTDI connector can be found on just about any ESP8266 design. If you are building a gadget to be deployed somewhere and not a full blown development board, the FTDI connector is somewhat overkill. And it is quite large. A few pins could be shaved off but we still have a through hole connector invading the other side of the PCB.

I ended up designing my own connector and it has been used sucessfully in all of my recent projects. The connector consists of five test points providing power, GND, TXO, RXI and GPIO0 for boot control. It takes very little single sided PCB space and is inspired by the TagConnect I use at work. Note that the power provided through the connector is unregulated.

I also designed a pogo pin connector to mate the test points and a small board with a DC barrel connector and the FTDI connector. This board has two switches for power and boot mode selection.

If you look carefully on the pogo pin adapter you see that the power pin is somewhat retracted. As the adapter will be hand held, the four other pins can be aligned to the device and with a gentle push power will be applied.

The pins used are P75-B1 1.02 mm (40 mil) [eBay] and the 9x4x8.5mm 3 way switches are also on eBay.

Schematics and my Eagle library with the device connector (“ESPROG-DEVICE”) as always on Github.

Building the Esparducam

I have had some questions about the possibility to purchase Esparducam boards and also about the bill of material. While I am looking into selling spare boards, here are some instructions about building the boards. Here is the link to order the PCBs [dirtypcbs.com].

Bare PCBs

If you have never tried building surface mounted boards yourself I highly recommend you try it! I started here [nathan.chantrell.net] and googled my way from there.

Here is the BOM with some eBay links:

C1 1uF capacitor 0603
C2 0.1uF capacitor  0603
C3 1uF capacitor  0603
C4 10uF capacitor  0603
C6 0.1uF capacitor  0603
J1 6 pin 2.54mm male header (angle) [eBay]
JP1 8 pin 2.54mm female header (for the Arducam Mini) [eBay]
JP9 Power jack 5.5×2.1mm [eBay]
R1 4k7 0603
R2 4k7 0603
R3 4k7 0603
R4 4k7 0603
S1,S2 Momentary switch [eBay]
U1 NCP1117 (or LM1117) 3.3V regulator [eBay]
X1 ESP-12f

The following parts are optional depending on what you want to do with your board:

Reverse current protection

D1 SOD-123FL, schottky diode for reverse current protection [eBay],
If you feel brave you can bypass the diode by placing a blob of solder across SJ2 on the back of the board.

Adding motion detection

If you want to attach a PIR [eBay] you need:
J2 JST ZH connector, 3 pin [eBay]
R6 220k 0603
R7 100k 0603
R6 and R7 was going to be a voltage divider that I messed up leaving R7 optional. Please note that the PIR does not work at 3.3V. To bypass this without adding a 5V regulator I simply feed the PIR with the raw board voltage which in my case is 5V.

Controlling power to the Arducam Mini

If you want to be able to control the power to the Arducam Mini board you need Q2 and R5. If you feel ok to have power constantly enabled simple place a blob of solder across SJ1 at the back of the board.
Q2 P mosfet, SOT-23 [eBay]
R5 4k7 0605

External flash

The external SPI flash is also optional. Please note that the footprint is somewhat too narrow, some flashes might not fit.
U2 SPI flash SOIC-8
C5 0.1uF 0603

Adding header pins

These optional headers are for attaching add-on boards or pins for taking measurements
JP3, JP6 8 pin 2.54mm male header
JP4,JP5 8 pin 2.54mm female header

That’s it, good luck!

Building a low cost wifi camera

Update! Here is a post with the BOM for the project.

Sometime ago I came across the Arducam Mini which is quite a nice camera module from UCTronics. It is a small PCB with a two megapixel OmniVision OV2640 sensor, an interchangeable lens and an FPGA to do the heavy lifting of image processing and JPEG encoding. Priced at around 24 Euros (lens included) you can easily buy a few without hurting your wallet and combined with an ESP8266 you can build quite a low cost wifi camera. Or several. Because designing and building PCBs is both fun and inexpensive I designed a board to go with the ESP8266/Arducam Mini combo, aptly named the Esparducam. And uniquely named too, try googeling for “esparducam“. Heck, even the domain name is available at the time of writing 🙂

The Espaducam board
The Espaducam board

Anyhow. The Esparducam board is a development board for the Arducam Mini module and is quite well suited for ESP8266 development in general.

Espaducam with Arducam Mini module
Espaducam with Arducam Mini module

The board is powered through a barrel connector at a minimum of 5V (upper limit untested) and all the IO pins on the ESP8266 are available on pin headers. The double rows are intended for the design of small breakout boards that sit on the inner 0.1″ aligned headers while the outer headers allow for connecting logic analyzers/oscilloscopes and so on. The Arducam Mini module plugs right into the front header and the standard FTDI connector is at the back of the board.

Image quality is, imho, quite decent at this price point, here are a few samples.

An optional SPI flash can be mounted for image storage and you can connect a standard eBay PIR module to the white JST header next to the FTDI connector if you want to build a motion triggered camera.

I am no hardware engineer but if you are and you find any silly design mistakes please let me know.

Schematics
Schematics

You can order the Esparducam board form DirtyPBCs and I would love to know if you build one. I plan to build a few for house monitoring, kite photography, reading my water meter and whatever else I can come up with.

The demo application listens to port 80 for HTTP GETs and will capture and return an image. It also has a command line interface on the serial port and the command ‘upload:<ip number>’ will capture an image and upload it via HTTP. A Python script is included that will receive and display the image using your system’s default image viewer. Note that the demo application is just that, a demo application. It does not handle simultaneous clients, errors or anything else that occurs in the real world.

IMG_3761Lastly a note about the lens. It uses a mount called M12xP0.5 and there are plenty of lenses to choose between. The one included with the Arducam Mini module has about the same field of view as a normal 50mm lens on a full frame DSLR. I would recommend getting a 3.2mm lens or shorter for some more wide angle if you plan to use the module for surveillance applications. The 3.2mm lens (called LS-40136) can focus at a very short distance making it a candidate for water meter reading applications.

I have yet to try the even shorter ones like the LS-20150 at 2.8mm or the LS-40166 at 2.6mm.

The Esparducam turned out so nice it became my preferred ESP8266 development board, why is a different post.

Code and hardware schematics as always on Github.

 

 

A versatile ESP8266 development board

This is followup to my post about building a low cost wifi camera. I mentioned that the Esparducam board is well suited for ESP8266 development in general and here is why. In addition to the Esparducam board I also designed a number of addon boards. The boards are very small (21×26 mm) meaning you can fit two of them into a standard 50×50 mm PCB you can get produced for very little money. If you want to try a new component or connector and perhaps a newly designed footprint, make a “boardlet” and try it on the Esparducam.

The RFM69C breakout
The RFM69C breakout board

The “ISM boardlet” mounts an RFM96C for building a low cost ISM to Wifi gateway. The board has an optional LED (driven by a mosfet) for link indication. I ported André Heßling’s RFM69-STM32 driver for this board and even though I have not had the time to test that much, basic transmission works.

The ESP Pinlet
The ESP Pinlet

The next board, the esp-pinlet, serves as a test bench for ESP12 family modules. After soldering an ESP12e module to an Esparducam board I noticed it would not connect to my Wifi network. For the price of ESP8266 modules, I cannot complain about broken modules but I want to make sure the modules I mount on my boards actually work before soldering. So how do we test ESP12 modules without soldering? Pogo pins! The pinlet board has 1.02mm (40 mil) holes for pogo pins that allows for an ESP12 module to be firmly pressed against the pins while flashed and tested. You can find these on eBay.

Look ma, no solder!
Look ma, no solder!

Schematics on Github.

Update on April 27th

Th pogo pins I used initially where not that good as the needle like shape made them get stuck in some of the ESP12 modules. A much better alternative is the P75-E2 [eBay] type of pin (still 1.02mm / 40mil):

P75-E2 pins
P75-E2 pins

If you plan on building a pinlet board, make use of the fact that you get ~10 in each order to help with alignment.

Pin alignment
Pin alignment

The stack here (top to bottom) is the board having the pins mounted, a spacer board (the red one), five pinlet boards for alignment and at the bottom one board flipped upside down to keep the pins from sliding downwards. The package is fixed with tape and ready for solder.

Commercial pilots control my moodlight

Having spent some time building the Wifi Ghost I wanted it to be something that was actually used. Few people in the house found the interest to change color on a daily basis (myself included). Then it occured to me, why not let the pilots of the aircrafts buzzing around the airspace of southern Sweden control it? They will probably never know that by passing within a few kilometers of my ADS-B receiver they will light up my study.

This will be a small project as most parts are already in place. The ADS-B tracker from my Skygrazer project will feed a script that sets the ghost color via its MQTT topic. What color though? Well, the most prominent color in the airlines’s logo of course! Make a Bing image search for the name of the airline with the word “logo” appended, pick an image, download and analyze. The color will be dimmed according to the distance to the aircraft. I use a maximum distance of 2 kilometers making the light fade up and down whenever an aircraft passes near my house.

The result? A wifi ghost light put to good use. And art 🙂

Code available on Github.