cover photo


Blinky on STM32F407 Discovery with Rust

I've gotten blinky to work \o/  .

After a lot of messing about the right HAL for my board STM32F407 Discovery board:


extern crate cortex_m;
extern crate cortex_m_rt;
extern crate panic_halt;

extern crate stm32f407g_disc as board;

use cortex_m_rt::entry;

use board::hal::delay::Delay;
use board::hal::prelude::*;
use board::hal::stm32;

use cortex_m::peripheral::Peripherals;

fn main() -> ! {
    if let (Some(p), Some(cp)) = (stm32::Peripherals::take(), Peripherals::take()) {
        let gpiod = p.GPIOD.split();
        let mut led = gpiod.pd13.into_push_pull_output();

        let rcc = p.RCC.constrain();
        let clocks = rcc.cfgr.sysclk(168.mhz()).freeze();
        let mut delay = Delay::new(cp.SYST, clocks);
        loop {


    loop {

The program's name I'm testing with is called "enviromon". Replace that with your own.  The combination of openocd and gdb to debug works great. To flash to µC only openocd is needed with a commandline:
$ openocd -f /usr/share/openocd/scripts/board/stm32f4discovery.cfg -c 'program ./target/thumbv7em-none-eabihf/release/enviromon verify reset exit'

To see the size of the binary (release version, not debug):
$ cargo size --bin enviromon --release --verbose -- -A

Further information
$ cargo readobj --bin enviromon --release -- --file-headers

To see the The Assembly code with the rust lines that trigger the generation:
$ cargo objdump --bin enviromon --release -- -disassemble -no-show-raw-insn -print-imm-hex -source -line-numbers
 rust  STM32  µC
Rust on STM32

After reading and following along with i've got Rust program to run on STM32F4 Discovery board.
With the right configuration from I could make
$ cargo run
will do the build and push the code through via GDB. For this to work $ openocd needs to be running.
Next-up, interact with the different pieces of hardware on the board.
STM32F4Discovery board with atom and openocd

  last edited: Thu, 27 Dec 2018 22:43:21 +0100  
During's Electronics Friday, I was having trouble with getting to Binky with a STM32 board I had laying around. It was the first time working with this board, and ARM in general. The trouble was writing to the STM micro. I've tried stlink but not much luck there.

However, Openocd did work for me.
I wrote binky in Atom:

#include <Arduino.h>

const int MYPIN = PD14;

void setup() {
  // put your setup code here, to run once:
  pinMode(MYPIN, OUTPUT);

void loop() {
  // put your main code here, to run repeatedly:
  digitalWrite(MYPIN  , HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);                       // wait for a second
  digitalWrite(MYPIN, LOW);    // turn the LED off by making the voltage LOW

Compiling worked, but uploading to the STM board was the issue.  
Atom drops the elf file in .pioenvs/disco_f407vg/firmware.elf
And with
$ openocd -f /usr/share/openocd/scripts/board/stm32f4discovery.cfg -c "program .pioenvs/disco_f407vg/firmware.elf verify reset exit"
it got uploaded to the STM board.

Here's the STM documentation for the board i'm using:
Chotee is now connected with Early Grey

Working with the NC3791 MPPT tracker

A while back i got a small solar power MPPT (Maximum power point tracker) board from Aliexpress ( I got the version for 6v, but it turned out I needed more voltage to run my project, so I put two more panels I had laying around in series to make a (max) (6v + 2*4.5V= ) 15V series voltage. Of course, now I need to change the MPPT board now.

The datasheet for the main chip is here:

On the board I need to change the Resistors marked R1 and R2
The boards "R1" is between Solar+ and pin6 (MPPT) called R3 in the Application Circuit
And "R2" of the board is between Gnd and pin6 (MPPT) which is called R4 in the Application Circuit.

Looking at the board the SMD R1 as "25d" while R2 has a code of "4532".
Using for reference,
The "25d" of R1 indicates the EIA96 system and "25" actually stands for "178" and "d" for x1000. R1 is a 178KOhm
R2's 4532 means "453" * 10^2. R2 is 45.3KOhm.

The MPPT pin (pin6 on the NC3791) regulates so that there's 1.205V on that pin. So, for there to be 1.205v on MPPT pin, there needs to be ( (R1+R2)/R2*MPPT = (178+45.3)/45.3*1.205= ) 5.93V on Solar+ . So, yea. that makes sense for the 6V variant.

We want it to be at 1.205v when there's 15v and I'd rather only change one of the resistors. 15v to 1.205 is a ratio of 12.45 (6v has a 4.92 ratio). Lets day that ratio is X. So, taking our formula of (R1+R2)/R2=x we can transform it into R1=(x*R2)-R2. Or (12.45*45.3)-45.3=518.7. So We'll need to replace R1 with a 519KOhm resistor. Neat.

Unfortunately I don't have a 519KOhm resistor laying about. I only have the famous R12 series. But there's which helps find a good combination of common value resistors to make the value you need. Best values for 518.7K are:
two in parallel: 680000    ||    2200000    =    519444.444    (0.144 %) and
two in series: 470000    +    47000    =    517000        (-0.328 %)
Super capacitors

  last edited: Sat, 01 Sep 2018 13:17:34 +0200  
I've been looking a bit into supercaps (capacitors in the >1F range) and they are now readily available. While the Available Farads keep going up, prices are dropping as well. Since they have often have low voltage ratings (2.7v is common), you'll need to put a few in series for most applications.

Here's a nice selection:
A Circuit of 3 of them in series.
Using Gpsbabel with Linux and a Garmin etrex Vista HCx

...This is for my future self... I've dusted off my Garmin hand held GPS and realized I've forgotten how to upload tracks/routes to it. Something I did regularly before.

I use gpsbabel which has regular Debian packages. and the documentation is here;

Check that the garmin is talking to the computer:
$ sudo gpsbabel -i garmin -f usb:-1
0 3380402361 694 eTrex Vista HCx Software Version 2.40

Device "0" is successfully talking to the PC.

Upload new tracks+routes+waypoints of a .gpx file to the device.
$ sudo gpsbabel -t -r -w -i gpx -f my_file.gpx -o garmin -F usb:

Unfortunately,  when uploading the device reports "Track Truncated". THis means that the track contains more points then the device can handle. On my Vista can only read tracks that have up to 500 points, it can however, write 10k points to the sd-card, So I need to reduce the number of points. gpsbabel can do this as well by filtering the file

But I preferred to use the bikehike service where you can up and download gpx files and allows to reduce the number of points and check the result. To reduce the number of points, it is the "options" setting.  

Uploading new maps
Grab them from
If you want to make bike routes, select the "Routable Bicycle (Openfietsmap Lite)" type of map. Select the tiles or countries, download the .zip and drop the contained .img file into the "garmin" directory of the device.
 linux  garmin  gps
Using ESP32 and SHT11 for humidity and temperature

Using an old SHT11 part I had laying around. The SHT11 is an obsolete part, having been replaced by the Sensirion SHT3x line. But even that doesn't seem to be widely used in hobbyist market anymore, places like Sparkfun now use use other Chips. Probably because of this, I couldn't find an ESP32 library for this. I could find a Raspberry-PI python, one for Arduino and a version for ESP32 (also in C++).

I've decided to try to port the Python for the rPI as it seems to need the least changes.  

After a bit of messing about, writing a few shims was the quickest solution, and it works, even if it's not the cleanest.

The ESP now reports on temperature and humidity of the sensor.
ESP project code repository on github

As I'm exploring the ESP32, I'm also writing some larger code then just the loose snippits in these posts. You can find the repository on
 esp32  github  code
ESP being a TCP Client and pushing data


>>> import socket
addr_info = socket.getaddrinfo('', 2300)
addr = addr_info[0][-1]
s = socket.socket()

This will connect to port 2300 of machine '' (DNS names are also valid here) and write "foobar\n" to the socket before closing the connection. To test this, the nc/netcat application can help like so

$ nc -vl 2300
Listening on [] (family 0, port 2300)
Connection from [] port 2300 [tcp/*] accepted (family 2, sport 52864)
Using ESP32 with ADCs to track voltages

  last edited: Sat, 12 May 2018 15:10:15 +0200  
For the Solar powered ESP32 project, I want to keep track of solar and battery voltages. To track them, we use the ADC (Analog to Digital Converters) of the Micro Controller.  

The ESP32 has 18 (!) 12bit ADCs channels and their normal operation is between 0 to 1.1volt. You can set the input to attenuate the input to other ranges as well (up to  3.3 volt), but since a voltage divider is needed already, I can just as well attenuate to between 0 and 1.1 volt already.

At 1.1v and with 12bits resolution, (2^12 = 4095 steps) the each value of the ADC represents (1.1v / 2^12=) 0.269mV. Pretty awesome resolutions. But the expectations is that the least significant bits will be dancing all-over and the 1.1V voltage reference will not be that accurate, limiting the absolute accuracy.

Both battery and Solar inputs have voltages greater then 1v so we need to scale them. The simplest is to use a simple voltage divider where the middle pin goes to the ADCs pin.

The battery voltage goes up to 4.2V when charging. adding 100mV of margin should prevent ever "topping out" the scale. So we need to scale 0-4.3V to 0-1.1V. What values to use? The formula is R1/(R1+R2); where R1 is the value you will measure over and the R2 is the other value. An awesome combination is R1=1, R2=3.3, which is (1/(1+3.3)=) 1/4.3. So, if the input value is 4.3V, the output would be exactly 1V. a good match. Also because 3.3 is a value in the  standard resistor series \o/. Another reason is that even in the case of gross overloading, the absolute maximum 3.6V of the ESP32 is far far away, making it safer.

Okay, but power wise we'd have 4.3v going through 4.3Ohm, running 1A of current and burning 4.3W of power. Not at all ideal for a solar project. If we multiply both R1 and R2 by 100K, we get 100K and 330K resistors. Still standard values and only using 10µA. Much better.

The ESP32's ADC's pin will also draw some current. The spec doesn't specify how much, except that it's "high". Which generally means "A couple of Mega-ohms at least". We'll measure later how much it really is. But since I don't currently know how much, having 10µA is a safer choice then going for even higher  resistor values.

So, to test it, hooked up the divider from 3.3V pin to ground. Measuring the voltage with a multimeter, I get 3.298V from the 3V3 Pin and the divider midpoint gives 0.755V. Great. well within the 1V range. So lets hookup the midpoint to Pin36.
>>> import machine
>>> from machine import ADC
>>> from machine import Pin
>>> pin_bat = ADC(Pin(36))

Lets read some values ... and as you can see, it dances around a bit, as expected.


To turn this value into the actual voltage I did:

>>> ( / (2**12 / 1.1)) * 4.3

Okay, high by about 45mV.

The ESP32 reference isn't that good in absolute sense, but it is stable overtime.  Here's a discussion about this topic To get better accuracy some more work needs to be done to better approximate the ADCs value with the  observed value, but once achieved that should be stable. Here's the deepdive into the topic:
And a example curve to improve the stability:

For the solar panel voltage the maximum expected voltage is 8V. So a reasonable value for that voltage divider is R1=100K and R2=680K... at 8V this would give 1.027V on the ADC. Which fits works fine. To damage the ESP, the solar voltage would need to be in the 28V range, so that's quite safe even on the sunniest of days.
Uploading a program and executing at bootup

The tutorial describes how to upload files and how to connect the ESP to an existing WIFI network (station mode) and use it in AP mode.

$ pip install esptool --upgrade
$ pip install adafruit-ampy --upgrade
$ ampy --port /dev/ttyUSB0 run  # This runs the file once uploaded to the esp32
$ ampy --port /dev/ttyUSB0 put  # Uploads the file.

Because the file is called it will be executed at the start of the micro.

If a script it running, and you want to get to the REPL prompt, you can just connect and give a Ctrl-C. This stops the script, and gives you the REPL prompt.

Trick to see the files uploaded on the micro you can do:
>>> import os
>>> os.listdir()
['', '']

To put the ESP32 into AP mode use
import network
ap = network.WLAN(network.AP_IF)
ap.config(authmode=3, password='yourpassword')

This will set the authentication of the ESP32's AP to the the commonly used WPA2-PSK mode.
Sparkfun's ESP32 Thing's LED.

  last edited: Sun, 06 May 2018 13:23:08 +0200  
There is a Led on the sparkfun esp32 thing that the software can turn off and on. This is Pin 5. It's capable of both a GPIO and PWM.

To control it:
>>> import machine
>>> from machine import Pin
>>> p5 = Pin(5, Pin.OUT)
## The Led will now turn off
>>> p5.value(1)  # Turn it on
>>> p5.value(0) # and off.
>>> from machine import PWM
>>> pwm5 = PWM(Pin(5))
>>> pwm5.freq(1)  # The led blinks on and off in one second.
>>> pwm5.duty(10)  # The on part is much shorter now.
>>> pwm5.freq(30) # Around 30 cycles per second, Persistence of vision takes over.  
Micropython with ESP32 using the REPL interface

  last edited: Thu, 03 May 2018 01:23:16 +0200  
Reference for ESP8266, which is nearly identical for the ESP32 is here:

SImple bit-bangging in python goes at 27kHz
>>> from machine import Pin
>>> c = 1
>>> while True:
...     c+=1
...     p0.value(c%2)

PWMs work as well

>>> from machine import PWM
>>> pwm0 = PWM(Pin(0)
... )
>>> pwm0.freq(1000)  # 1kHz PWM
>>> pwm0.freq()

Experimentally the maximum PWM frequency is 78.125 kHz. The Multimeter agrees with this.
>>> pwm0.freq(78125)
>>> pwm0.freq()
>>> pwm0.duty(512)  # 50% duty cycle
>>> pwm0.duty(256)  # 25% duty
>>> pwm0.duty()

The ADC (there's 8 of them -- see for the Pin numbers)

>>> from machine import Pin, ADC
>>> a0 = ADC(Pin(36))
>>> a0
4095    # That's a 12bits ADC!
>>> a0.width(ADC.WIDTH_9BIT)  # Lower resulution

Since by default voltages are measured from 0 to 1 volt, a single ADC step is 0.24mV. Neat!
>>> 1.0/(2**12)*1000
Getting an inventory system going

  last edited: Tue, 01 May 2018 23:11:44 +0200  
After realizing that i'm more and more using Aliexpress' "ordered" list as the source for what parts I have available, I've decided to sink the time into getting Partkeepr available for myself and Techinc hackerspace. To keep the service maintainable the trick is to install the service from a vanilla Debian box.
I had tried that before, but got stuck on wanting to auto-config the partkeepr as well. @realitygaps gave the hint to just use the whole Partkeepr app and database as the data to backup and just run the standard update-setup process when a new version is released. So, that's what's prepared now. There are installation and backup Ansible playbooks.

So, I have a system I need, and even if nobody but me uses the installation, I can help others by exposing what parts I have available at cost.

Integrating the inventory in techInc would clearly be a more interesting project... but first, I need to master the tool by itself.
Chotee updated their profile photo

Micropython Connecting ESP32 to a Wifi

Use pycharm's micropython support

Upload the Micropython image for ESP32

How to connect to a Wifi (using the micropython REPL interface)

>>> import network
>>> sta_if = network.WLAN(network.STA_IF)
I (783788) wifi: mode : sta (24:0a:c4:05:b0:78)
I (783788) wifi: STA_START
>>> sta_if.connect('<ESSID>', '<password>')
>>> sta_if.ifconfig
>>> sta_if.ifconfig()