Docker container web interface – Portainer and Riot-OS Development

This post is a follow up of starting up with RIOT-OS. To be able to develop with RIOT-OS an easy (and easier) way to do so is just to install docker and web UI docker interface Portainer to control docker.

So we will install Docker, Portainer, and finally the RIOT-OS building environment.

Installing Docker and Portainer, is an initial stepping stone for using the dockerized development environment for RIOT-OS, since I don’t want to install all the development environments in my machine.

Installing Docker:
On Arch-Linux is as simple as installing the Docker package using pacman, enabling the services and rebooting.
Basically we need to run, as root the following commands:

pacman -S docker
systemctl enable docker.service
reboot

After rebooting the following command should return some information

docker info

A sample output is:

Containers: 2
 Running: 0
 Paused: 0
 Stopped: 2
Images: 9
Server Version: 18.09.0-ce
Storage Driver: overlay2
 Backing Filesystem: extfs
 Supports d_type: true
 Native Overlay Diff: false
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
 Volume: local
 Network: bridge host macvlan null overlay
 Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
...
...
...

Installing Portainer
Installing the Docker Portainer Web UI is as simple as:

docker pull portainer/portainer

To run Portainer a set of complete instructions on this page, but basically on the simplest way is:

$ docker volume create portainer_data
$ docker run -d -p 9000:9000 --name portainer --restart always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer

We can now check if the docker image is up:

$ docker ps
CONTAINER ID        IMAGE                 COMMAND             CREATED             STATUS              PORTS                    NAMES
7a38ae7fc922        portainer/portainer   "/portainer"        4 seconds ago       Up 3 seconds        0.0.0.0:9000->9000/tcp   portainer

Since I have already ran the Portainer container, the initial setting up steps when accessing the URL HTTP://localhost:9000 do not appear, but we need to choose:

  1. A set of credentials to use as de administrator for portainer
  2. The local machine registry to connect to the local docker containers.

1- At initial access we define an user and password:

Portainer Credentials

2- Then we connect to our local docker instance:
Portainer Local Docker

Press Connect and then we can now access our Docker instance from Portainer:
Portainer Main Screen

Pressing the Local Docker Connection we can now manage our docker resources.

Installing the build environment for RIOT-OS
We can do it by two ways:

From the command line:

docker pull riot/riotbuild

or use Portainer:

This container is very big, so we need to wait some time for the container image download. The command line shows in greater detail the download process.

After the image is downloaded, we can follow these instructions for building our apps using the docker container as the build environment.

After the image is installed:

To use is is as simple as going the the examples directory and do:

make BUILD_IN_DOCKER=1

From this we are now able to build based RIOT-OS applications for several targets, including the ESP8266/ESP32.

As we can see we even don’t need to have a running container, just the image.

Advertisements

Arch Linux with full encrypted disk

So, I’ve bought a new light weight laptop, an HP Envy 13.3 1.2Kg I7, where I wiped out Windows 10 and installed Arch Linux.

Just for security reasons I’ve decided to do a full disk encryption install, including boot.

There are several instructions on the Web, including videos on youtube in how to do it, and so on this gist I have my instructions for the installation, based off course in other gists and instructions.

In this post is the configuration instructions that worked for me and also to allow better find from google/bing/ddg.

# WARNING: WORK IN PROGRESS, USE THESE STEPS WITH CAUTION. IT WILL CLEAR ALL DISK DATA!!
I REALLY recommend first to use a Virtual Box machine with EFI support enabled to test everything before doing it on a real machine.

# Arch installation on a HP ENVY 13 inch laptop (ah0006np part number: 16GB Ram, 512GB SSD)

OBJECTIVE:
Install Arch Linux with encrypted boot, root and swap filesystems and boot from UEFI, completly dumping Windows on the process.
No dual boot.
Windows, if necessary will be run on a Virtual Machine and re-use the Windows key that came with the laptop.

The configuration will be LVM on LUKS. Also a major difference from other tutorials is that the boot partition is also encrypted, and not a standard partition.

# Results do far:

– Disk encryption ok. GRUB boots slow (20s). Otherwise works fine.
– Wireless works ootb, but errors on dmesg output from time to time when high traffic.
– Sound and microfone works ok
– Webcam does work but needs configuration: See below at the end.
– Keyboard special keys work fine (brightness, Sound, Mute), including keyboard background lights, but F6 sound Mute Led does not work.
– Some screen corruption with the Intel Driver either SNA or UXA. Nouveau crashes, nvidia driver didn’t work. To be checked -> Issue with QT 5 and Konsole/Kate applications, not a Intel Driver issue.
– KDE SDDM doesn’t recover well if screen DPMS is activated. I’ve disable it so far to solve it.
– Suspend/resume works fine.
– Battery time so far, around 4/5 hours.


# Desired disk layout:

+---------------+----------------+----------------+----------------+
|ESP partition: |Boot partition: |Volume 1:       |Volume 2:       |
|               |                |                |                |
|/boot/efi       |/boot           |root            |swap            |
|               |                |                |                |
|               |                |/dev/vg0/root   |/dev/vg0/swap   |
|/dev/sda1      |/dev/sda2       +----------------+----------------+
|unencrypted    |LUKS encrypted  |/dev/sda3 encrypted LVM on LUKS  |
+---------------+----------------+---------------------------------+

The final result is to have an Arch Linux Installation with full disk encryption and with a basic set of applications such as the KDE Plasma Desktop.

These instructions have several sources, namely:
https://grez911.github.io/cryptoarch.html
and this WordPress post.

The installation process on this guide is for the Arch Linux installation onto an HP Envy 13, 16GB RAM with 512MB ssd laptop. This laptop comes with Windows 10 Home installed, and as far as my model goes, it comes with an Intel WiFi board and a WD Sandisk SN520 512GB NVME SSD.

The official Arch installation guide contains more details that you should refer to during this installation process.
That guide resides at: https://wiki.archlinux.org/index.php/Installation_Guide

## Boot from image

Download the archlinux-\*.iso image from https://www.archlinux.org/download/ and its GnuPG signature.
Use gpg –verify to ensure your archlinux-\*.iso is exactly what the Arch developers intended. For example
at the time of installation:

$ gpg --verify archlinux-2017.10.01-x86_64.iso.sig
gpg: Signature made Sun 01 Oct 2017 07:29:43 AM CEST using RSA key ID 9741E8AC
gpg: Good signature from "Pierre Schmitz "
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 4AA4 767B BC9C 4B1D 18AE  28B7 7F2D 434B 9741 E8AC

Currently the Arch ISO is archlinux-2018.11.01-x86_64.iso.

Burn the archlinux-\*.iso to a 1+ Gb USB stick. You can use the dd command, unetbootin or Etcher.

Connect the USB stick to the usb port and power on/cycle the machine to boot.
If your USB stick fails to boot, ensure that Secure Boot is disabled in your UEFI configuration.

Note: To access the BIOS on the Envy Laptop, turn on the laptop and press several times the ESC key or the F10 key to access the BIOS while the screen is black.
First I moved the boot order to have the USB boot at the top.
Then we need to disable the secure boot option and press F10 to save. Confirm saving it.

Attention now: There is a confirmation screen to really commit the secure boot option change. Enter the requested code and save.

After booting up:

Set your keymap only if not you are not using the default English keyboard.

$ loadkeys pt-latin1

We can now, if required backup the HP recovery partition, that I suppose is the Windows Install Media.

# Connect to the Internet.

Execute the wifi-menu command and select a Wifi network. On this HP Envy, the wireless card (Intel) was detected with no issues.

Check with the “ip a” command if there is network connection.

## Prepare your hard disk

In the next steps we will create necessary partitions and encrypt the main partition.

Find the correct block device

$ lsblk

In my case the correct block device (the NVME SSD of my laptop) is ‘nvme0n1’. (Depends on the machine)

Create and size partitions appropriate to your goals using gdisk.

$ gdisk /dev/nvme0n1

Press p to show the partitions.

In my case I have a 260Mb EFI partition, a 16MB Reserved Microsoft Partition, a 460GB partition and a 980MB and another 15GB partition.

From this point on, everything that is to be done, will destroy the disk data.

# Delete all partitions on disk

Use the d command to delete all partitions. Use d, then partition number. Repeat for all partitions

Press o to create the GPT.

Create three partitions: One for the EFI, one for boot and the other will be used to have the Arch Linux installation. To create a partition, press n:

1. Partition 1 = 512 MB EFI partition (Hex code EF00). Initial Sector: ; End: 512M; Type: EF00
2. Partition 2 = 1GB Boot partition (Hex code 8300)
3. Partition 3 = Size it to the last sector of your drive. (default) (Hex code 8E00 – Linux LVM Partition)

Review your partitions with the ‘p’ command.
Write your gdisk changes with ‘w’.

Check again the names with the blkid command to know the partitions name:

1. EFI: /dev/nvme0n1p1
2. BOOT: /dev/nvme0n1p2
3. Arch: /dev/nvme0n1p3

# Create filesystems
The EFI filesystem must be FAT32:

$ mkfs.vfat -F 32 /dev/nvme0n1p1

The other filesystems are to be encrypted.

(optional) Before creating the partitions we can use the command

cryptsetup benchmark 

to see how fast the different encryption algoritms are.

# Encrypted /boot partition

$ cryptsetup -c aes-xts-plain64 -h sha512 -s 512 --use-random luksFormat /dev/nvme0n1p2
$ cryptsetup open /dev/nvme0n1p2 cryptboot
$ mkfs.ext4 /dev/mapper/cryptboot

The first command will ask for the disk passphrase. Do not forget it!.

ATTENTION:
The first crypsetup command will set the LUKS with default iter-time parameters, which may or may not make grub to boot slow (around 20s). If this is not fine add the following parameter: –iter-time=5000 (This will affect security, so use a large key phrase)

The last command will create a /dev/mapper/cryptboot device.
We can check that it was created with the command ls /dev/mapper

# Create encrypted LUKS device for the LVM

cryptsetup -c aes-xts-plain64 -h sha512 -s 512 --use-random luksFormat /dev/nvme0n1p3
cryptsetup open /dev/nvme0n1p3 cryptlvm


## Create encrypted LVM partitions

These steps will create the required root partition and an optional partition for swap.
Modify this structure only if you need additional, separate partitions. The sizes used below are only suggestions.
The VG and LV labels ‘ArchVG, root and swap’ can be changed to anything memorable to you. Use your labels consistently, below!

$ pvcreate /dev/mapper/cryptlvm
$ vgcreate ArchVG /dev/mapper/cryptlvm
$ lvcreate -L +16G ArchVG -n swap
$ lvcreate -l +100%FREE ArchVG -n root

Again, we can see on /dev/mapper if the logical volumes where created.

## Create filesystems on your encrypted partitions

$ mkswap /dev/mapper/ArchVG-swap
$ mkfs.ext4 /dev/mapper/cryptboot
$ mkfs.ext4 /dev/mapper/ArchVG-root

Mount the new system

mount /dev/mapper/ArchVG-root /mnt
swapon /dev/mapper/ArchVG-swap
mkdir /mnt/boot
mount /dev/mapper/cryptboot /mnt/boot
mkdir /mnt/boot/efi
mount /dev/nvme0n1p1 /mnt/boot/efi

# Install the Arch system

This installation command provides a decent set of basic system programs which will also support WiFi when initally booting into your Arch system.

At this point we need to have a network connection. Since the HP only has Wifi connection, we need to setup the WiFi connection. Other alternative is to use an Ethernet USB dongle that is recognized by the Arch boot iso.
Also, if you are behind a proxy, you can set the http_proxy and https_proxy variables to access the internet.

(Optional) Use reflector to speedup download (credit goes to u/momasf)

Change COUNTRY to (surprise) your country name.

pacman -Sy reflector
reflector --country 'COUNTRY' --age 12 --protocol https --sort rate --save /etc/pacman.d/mirrorlist

I won’t install base-dev here to save time at the installation.

$ pacstrap /mnt base grub-efi-x86_64 efibootmgr dialog wpa_supplicant vim

# Create and review FSTAB
The -U option pulls in all the correct UUIDs for your mounted filesystems.

 $ genfstab -U /mnt >> /mnt/etc/fstab
 $ nano /mnt/etc/fstab  # Check your fstab carefully, and modify it, if required.
 

Enter the newly installed system

$ arch-chroot /mnt /bin/bash

Set the system clock, you can replace UTC with your actual timezone

$ ln -fs /usr/share/zoneinfo/Europe/Lisbon /etc/localtime
$ hwclock --systohc --utc

Assign your hostname

$ echo mylaptop > /etc/hostname

My requirements for the locale are:
– Metric system
– 24h time format
– dd/mm/yyyy date format
– Portuguese language
– A4 paper size
– But all help, error messages are in English

The *pt_PT.UTF-8* plus *en_US.UTF-8* locale meets those requirements. To set up this locale:

– In /etc/locale.gen

en_US.UTF-8 UTF-8
pt_PT.UTF-8 UTF-8

– In /etc/locale.conf, you should **only** have this line:

LANG=en_US.UTF-8

We will change other settings on Bash profile.

Now run:

$ locale-gen

Create a new file vconsole.conf so that the console keymap is correctly set at boot. Create the file and add the following line:

KEYMAP=pt-latin1

Set your root password

$ passwd

Create a User, assign appropriate Group membership, and set a User password.

$ useradd -m -G audio,games,log,lp,optical,power,scanner,storage,video,wheel -s /bin/bash memyselfandi
$ passwd memyselfandi

Configure mkinitcpio with the correct HOOKS required for your initrd image

$ nano /etc/mkinitcpio.conf

Use this HOOKS statement: (I’ve moved keyboard before keymap, encrypt and so on…)

HOOKS="base udev autodetect modconf block keyboard keymap encrypt lvm2 resume filesystems fsck"

Generate your initrd image

mkinitcpio -p linux

## Install and configure Grub-EFI
Since we have the boot partition INSIDE the encrypted disk, we need to add the following option to the Grub options:

Edit the file /etc/default/grub and uncomment the following line:

GRUB_ENABLE_CRYPTODISK=y

And then we can install Grub, which will create an EFI entry named ArchLinux

grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=ArchLinux

Edit /etc/default/grub so it includes a statement like this:

GRUB_CMDLINE_LINUX="cryptdevice=/dev/nvme0n1p3:cryptlvm resume=/dev/mapper/ArchVG-swap i915.enable_guc=3"

I’ve also added the i915 configuration line.

Other way of doing it is to use UUID:

blkid /dev/nvme0n1p3 -s UUID -o value

And use the UUID outputed on this command line:

GRUB_CMDLINE_LINUX="cryptdevice=UUID=55994-XXXX-xXXXX-XXXXX:cryptlvm resume=/dev/mapper/ArchVG-swap"

Generate Your Final Grub Configuration:

$ grub-mkconfig -o /boot/grub/grub.cfg

At this point there are some errors regarding failing to connect to lvmetad, which are normal and can be ignored.

# Mounting /boot without password request
Grub will ask for passwords to access the encrypted volumes. We can do this automatically:

dd bs=512 count=8 if=/dev/urandom of=/etc/key
chmod 400 /etc/key
cryptsetup luksAddKey /dev/nvme0n1p2 /etc/key
echo "cryptboot /dev/nvme0n1p2 /etc/key luks" >> /etc/crypttab

# Mounting root LVM without password prompt

dd bs=512 count=8 if=/dev/urandom of=/crypto_keyfile.bin
chmod 000 /crypto_keyfile.bin
cryptsetup luksAddKey /dev/nvme0n1p3 /crypto_keyfile.bin
sed -i 's\^FILES=.*\FILES="/crypto_keyfile.bin"\g' /etc/mkinitcpio.conf
mkinitcpio -p linux
chmod 600 /boot/initramfs-linux*

The mkinitcpio.conf FILES line will look like:

FILES="/crypto_keyfile.bin"

# Enable Intel microcode CPU updates (if you use Intel processor, of course)

pacman -S intel-ucode
grub-mkconfig -o /boot/grub/grub.cfg

# Check EFI Boot Manager
Check that the EFI Boot manager has the ArchLinux entry:

$ efibootmgr

For example if ArchLinux entry is Boot0003, check if on the boot order, 0003 is on the head of the list.
If not change the order with:

$ efibootmg -o 0003,0002,0001,0000

Exit Your New Arch System

$ exit

Unmount all partitions

$ umount -R /mnt
$ swapoff -a

Reboot and Enjoy Your Encrypted Arch Linux System!

reboot

___

# Setup system

We need again to connect to the internet, so run again the *wifi-menu*.

Install bash completion for reduced typing effort and other packages if necessary:

$ pacman -S sudo bash-completion base-devel git

To be able to use sudo from your normal user add wheel to sudoers.

$ EDITOR=nano visudo

Uncomment the line

%wheel      ALL=(ALL) ALL

From this point on, it really depends of what need there is for the machine.

# Making the webcam to work.
The webcam id appears at the lsusb output:

Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 003: ID 8087:0a2a Intel Corp. 
Bus 001 Device 002: ID 04ca:7090 Lite-On Technology Corp. 
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

The webcam is the Bus 001:002 device: ID 04ca:7090.
Add the following rule at /etc/udev/rules.d

KERNEL=="video[0-9]*", SUBSYSTEM=="video4linux", SUBSYSTEMS=="usb", ATTRS{idVendor}=="04ca", ATTRS{idProduct}=="7090", SYMLINK+="video-cam"

Load the module to activate the webcam:

modprobe uvcvideo

The /dev/video0 and 1 devices should appear.

MakeBlock STEM mbot Robot – Using nodeJS to control mbot through BLE

A few weeks ago I’ve bought a mbot robot out of curiosity (also as a gift), since they became available at a nearby major electronic retailer and cheaper than buying them online.

The mbot is a robot chassis with two wheels, some external and onboard sensors, including an external ultrasonic sensor, and all this supported on a custom version of Arduino 328 board whish incorporates a motor driver, battery charger and so on. The version that I’ve bought also came with a LED Matrix display where it is possible to draw faces, text and numbers (mbot Face version).

The mbot robot can be controlled or used by either some Android (and IOS) mobile applications, or by using the Scratch programming environment. MakeBlock has a specific mbot version for Scratch called mblock that supports a set of new programming blocks to control the robot. The use of Scratch and mbot makes it ideal combination for teaching kids about programming and robotics.

We caan communicate/interface with mbot either by using an USB cable, or either by Low Power Bluetooth (the mbot BLE version) or through a 2.4GHz radio (the mbot 2.4GHz version). The 2.4Ghz version is more adequate for a classroom environment, since each robot is automatically bounded by radio to the 2.4GHz USB computer stick radio controller, which basically makes it plug and go and no need to fiddle with BLE discovery and bounding.

Anyway, the version that I have is the BLE one, and this post is about how to use NodeJS with the BLE Noble Library to communicate with mbot when using the factory firmware.

Requisites:

To make this work we need to have some requisites first:

Since mbot uses BLE, the computer must support also BLE. In my case I’m using the CSR 4 BLE dongle available on eBay, Ali and so on, to have BLE support on my computer.

The mbot must be loaded with the factory firmware so the this code can work. This is off course just for testing this code.
The factory firmware can be loaded either by using the mblock program when connected by USB cable, or by using the Arduino IDE.

The mbot BLE module is connected to the serial pins of the onboard arduino, so while the factory firmware has a specific interface, nothing stops us from replacing it with our own code and interface. For now we just keep the factory interface that is based on messages that start with 0xFF 0x55 ….

The code was tested on Linux, and it works fine. No idea if it works on windows…

As far it goes today, the NodeJS Bleno library doesn’t work with the latest node version 10, so we need to use this with a previous version of NodeJS. I’m using NodeJS V8, and also use the NodeJS Version Manager to have several versions of NodeJS active and available.

The BLE interface:
Using the Nordic Connect mobile application, we turn on the mbot, and on the application we start the BLE scan:

A device named Makeblock_LE should appear. We can connect to it and see the published services and characteristics:

There are two known services, and two unknown services. After some testing writing data to those services the service ffe1 is the service that connects to the mbot arduino serial port, and the service ffe4 I have no idea what it is for. Probably for controlling something on the BLE module itself.

The characteristics that the service ffe1 service exposes are:

As we can see, on is for reading data: ffe2 and it supports notification. This means we are warned when data is available so we can read it. The other characteristic is ffe3 that is for writing.

Basically if we connect to the Makeblock_LE BLE device, use the ffe1 service and write on the ffe3 characteristic we can control the robot. Data from the robot is automatically sent to us if we have notifications enabled on the ffe2 characteristic.

The mbot protocol:

There is one post that explains the protocol structure to communicate with the mbot.

Basically every command begins with 0xff 0x55 and then a set of bytes to control something.

The responses follow the same principle of starting with 0xff 0x55 and can return several values types.

An easier way to see what to send is to use mblock, program a scratch example in Arduino mode, and on the mblock serial monitor see what is sent to the robot.

My GitHub code source has some command examples for sending to mbot, namely to control the WS2812 RGB leds, the buzzer, the Led Matrix and to read data from the ultrasonic sensor.

How to use it:

Download the code from here MBot_BLE.

git clone https://github.com/fcgdam/mbot_ble

Make sure that you are using NodeJS version 8:

node -v
v8.11.3

If using Node V10, you can try to install the modules since in a future date from this post, the issues with Noble and NodeJS V10 might be solved.

Install the modules dependencies:

npm install

The code to access the BLE device needs root access, or check how to use Noble without root access:

sudo node mbotble.js

If the Ultrasonic distance sensor is connected to port 3, distance data is shown on the terminal.

That’s it!

Sample output:

The sample output for the mbotble.js when running as root on the RPI 3:

root@firefly:/home/pi/BLEMbot# node blembot.js 
- Bluetooth state change
  - Start scanning...
! Found device with local name: Makeblock_LE
! Mbot robot found! 
  - Stopped scanning...
- Connecting to Makeblock_LE [001010F13480]
! Connected to 001010F13480
! mbot BLE service found!
! mbot READ BLE characteristic found.
! mbot WRITE BLE characteristic found.
- End scanning BLE characteristics.
! Subscribed for mbot read notifications
Reading the ultrasound sensor data...
> mbot data received: "ff550002cb3db9410d0a"
Distance: 23.15517234802246
Reading the ultrasound sensor data...
> mbot data received: "ff5500020000bc410d0a"
Distance: 23.5
Reading the ultrasound sensor data...
> mbot data received: "ff5500027c1ab9410d0a"
Distance: 23.13793182373047
Reading the ultrasound sensor data...
> mbot data received: "ff5500028db0c0410d0a"
Distance: 24.086206436157227
Reading the ultrasound sensor data...
> mbot data received: "ff550002ddd398400d0a"
Distance: 4.775862216949463
Reading the ultrasound sensor data...
> mbot data received: "ff5500024f23d8410d0a"
Distance: 27.017240524291992
...
...
...

Using the BSFrance Lora32U4 board to connect to the Things Network Lorawan

The BSFrance Lora32u4 II (Lora32U4II for helping Google out) board is an Atmega32U4 processor with a HDP13 Lora transceiver on the same board. As far as I’m aware, the HDP13 is similar to the RFM95W (including pinout), and in my case it seems it has an original Semtech SX1276 (868Mhz radio transceiver) chip installed on the HDP13 module.
This board is similar to the Adafruit 32U4 Lora feather, if not equal… (possible schematics for the Lora32u4 board)

The board hardware includes beside the Lora HDP13 module a LiPo connector with an 2 pin JST PH 2.0mm pin spacing connector and the power supporting electronics.
There are two leds: one orange LED for LiPo and charger status, that blinks very fast when no LiPo is connected, and a very bright white led that fades in and out when the bootloader is in the programming mode or programming is ongoing. After the bootloader exits and starts the main program, the led shuts off.
This led, as usual in Arduino boards, is connected to I/O pin 13, so it is software controllable.

Also the only way to power up the board is either trough the USB port, LiPo battery or 5V to an input pin. No other voltages, like RAW voltages above 5V are supported.

As a final note, the board that I’ve bought also came with an uFL adapter cable for SMA, an antenna and a link for accessing documentation, so, excluding the LiPo battery, the complete kit.

Starting up using the board:

I’m testing the board to send data to the Things Network and doing so by using PlatformioIO as the developing IDE. Platformio IDE is much better than the Arduino IDE, since each project has it’s own depending libraries directory .piolibdeps which we can modify and edit the library code without breaking other projects.

The platformio.ini board definition for the Lora32u4II board is just a clone of Adafruit feather 32u4:

[env:feather32u4]
platform = atmelavr
board = feather32u4
framework = arduino

As the code to send data to the TTN network, I’ve just used ABP lorawan device connection that I’ve used on my previous hand build node.

I’m testing the node with both the IBM LMIC Library (ID: 852) and the Arduino LMIC Library (ID: 1729).

After setting the correct keys and device ID, all we need is to change the LMIC pins configuration for this board: LoRa32u4II pinout diagram

According to documentation the pins are:

  1. nss (SS – Chip Select): Pin 8
  2. rst (Reset): Pin 4
  3. DIO (Lora TX/RX indicator): Pin 7

So the LMIC Pins configuration is:

const lmic_pinmap lmic_pins = {
    .nss = 8,
    .rxtx = LMIC_UNUSED_PIN,
    .rst = 4,
    .dio = {7, 6 , LMIC_UNUSED_PIN}
};

Regarding Pin 6, is the chosen pin to connect to the DIO1 pin. This pin signals receive timeouts generated by the radio module.

The connection of this pin is required for LMIC and for the onEvent() function signaling of EV_TXCOMPLETE to be triggered/fired, otherwise the onEvent() funciton is never called.

Since this is a LoraWan Class A node, after the transmission, two receive windows are opened for any downlink data that might be sent to the node.

The DIO1 pin signals the receive timeout, and at the end of the receive windows, triggers the EV_TXCOMPLETE event.

I’ve tried to use other pins, for example, pin 3, but then the EV_TXCOMPLETE event was never fired… Strange.

Anyway, with the above configuration and with DIO1 connected through a wire bridge to pin 6 works fine.

If we do not connect DIO1 by removing the DIO1 pin configuration:

 .dio = {7, LMIC_UNUSED_PIN , LMIC_UNUSED_PIN}

with the platformio IBM Lmic library (Id: 852), or with the Arduino LMIC Library the LMIC fails. An example:

pio device monitor --port /dev/ttyACM0 --baud 115200
[cortex@brightlight:TTN32u4ABP]$ pio device monitor --port /dev/ttyACM0 --baud 115200
--- Miniterm on /dev/ttyACM0  115200,8,N,1 ---
--- Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
Starting...
FAILURE
.piolibdeps/IBM LMIC framework_ID852/src/hal/hal.cpp:24

The line hal.cpp:24 point to an ASSERT that doesn’t allow a LMIC_UNUSED_PIN for DIO1.

Putting pin 6 and making sure that it is connected to DIO1 is required. Otherwise if the pin is defined but not connected we have the following behaviour:

--- Miniterm on /dev/ttyACM0  115200,8,N,1 ---
--- Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
Starting...
Sending uplink packet...

As we can see the EV_TXCOMPLETE event is never fired, and the associated reschedule of another transmission never happens, since the code that triggers the next transmission is inside the code for the EV_TXCOMPLETE event. The only way, in this case, to exit this situation is to reset the board so another transmission can happen.

So if using the above LMIC pins configuration and connecting DIO1 to pin 6, sending data to the The Things Network works just fine:

Data received at the TTN side

Some final notes, tips and tricks:

The ATMega 32U4 USB Serial port:
The ATMega 32U4 USB serial port is a bit fiddly when using it from the Arduino framework. At reset or connection first the USB port is used by the bootloader (white led fading in and out). After a while the board starts to execute the flash program (white led off), but it resets the USB port. The host computer might have an issue with this and fails to assign an USB address.

The solution is just to add at the start of the setup function a delay:

void setup() {
  delay(2500);   // Give time to the ATMega32u4 port to wake up and be recognized by the OS.
  
  Serial.begin(115200);
...
...

Using minicom instead of PlatformIO serial monitor:
This one is quite simple to explain, since minicom survives to the USB port resets since they appear and disappear through the board reset.
Against it, is that we need to explicitly exit minicom to be able to program the board.

# minicom -D /dev/ttyACM0 -b 115200

The PlatformIO Arduino LMIC library is outdated:
This is solved now. Lib 852 is now updated.
The Arduino LMIC version (1729) on the PlatformIO is outdated, since, for example doesn’t have neither the LMIC_UNUSED_PIN definition and the LMIC_setClockError function needed for a successful OTAA TTN network join.

The solution is just clone the Arduino LMIC library and copy the src folder to .piolibdeps/IBM LMIC framework_ID852/ removing the original src folder version.

Comparing Library sizes:

Using the IBM LMIC Library (ID:852) with PINGS and BEACONS disabled on the config.h file, otherwise it doesn’t fit on the 32u4 32K flash space, our sketch uses the following space:

AVR Memory Usage
----------------
Device: atmega32u4

Program:   26040 bytes (79.5% Full)
(.text + .data + .bootloader)

Data:       1014 bytes (39.6% Full)
(.data + .bss + .noinit)

Using the Arduino LMIC library (ID: 1729) with PINGS and BEACONS enabled, but a more efficient AES implementation, we get:

AVR Memory Usage
----------------
Device: atmega32u4

Program:   22776 bytes (69.5% Full)
(.text + .data + .bootloader)

Data:        954 bytes (37.3% Full)
(.data + .bss + .noinit)

With PINGS and BEACONS disabled we get:

AVR Memory Usage
----------------
Device: atmega32u4

Program:   19032 bytes (58.1% Full)
(.text + .data + .bootloader)

Data:        903 bytes (35.3% Full)
(.data + .bss + .noinit)

So we get, with this last change, and while keeping support for OTTA, at least 8K/9K for program space not related to the Lorawan/TTN code support.

Building a Blackmagic Debug Probe

The Black Magic debug probe is in-application debugger, which allows IDE’s like NetBeans, Eclipse or others to connect directly to the hardware without using bridges like for example Openocd. The Blackmagic Probe software is open source and available on this Github link.

There are several posts/instructions on the internet regarding how to load the Black Magic firmware either on ST-Link hardware debuggers, ST-Link clones or using the “blue pill” STM32F103C8T6 based board.

There are several possible issues with this board:

  1. First they are quite cheap – not an issue
  2. It seems on some versions there is a problem with the USB connector regarding a resistor and bad contacts. In my version I had no issues. It just worked fine.
  3. The on board chip is the STM32F103C8T6 which has 64Kb of flash, but some claim that it can have 128Kb. In my case all the boards that I have, the flash size is 64Kb.

This last issue is a show stopper at the current release of the Black Magic firmware since it won’t fit on the 64Kb flash of the ST32F103C8T6. We must cut things from the firmware to be able to flash it on the STM32F103C8T6 board. But we will see how to do that.

Downloading and compiling the firmware:
This step is just straight forward, just clone the Blacmagic repository and compile. Since we are compiling to ST32F103 board we will assume it is a ST-Link clone.

[pcortex@pcortex:opt]$ git clone https://github.com/blacksphere/blackmagic
Cloning into 'blackmagic'...
remote: Counting objects: 5029, done.
remote: Compressing objects: 100% (9/9), done.
remote: Total 5029 (delta 1), reused 2 (delta 0), pack-reused 5020
Receiving objects: 100% (5029/5029), 2.01 MiB | 1.38 MiB/s, done.
Resolving deltas: 100% (3558/3558), done.
[pcortex@pcortex:opt]$ cd blackmagic/
README.md  Makefile  libopencm3/  HACKING  driver/  COPYING  scripts/  src/  upgrade/
[pcortex@pcortex:blackmagic|master]$ make
Initialising git submodules...
Submodule 'libopencm3' (https://github.com/libopencm3/libopencm3.git) registered for path 'libopencm3'
Cloning into '/opt/lixo/blackmagic/libopencm3'...
Submodule path 'libopencm3': checked out '67242de60dec0227739cd549e8a78e1a3c15dbf5'
  GENHDR  include/libopencm3/efm32/efm32gg/irq.json
  GENHDR  include/libopencm3/efm32/efm32g/irq.json
  GENHDR  include/libopencm3/efm32/efm32lg/irq.json
  GENHDR  include/libopencm3/efm32/efm32tg/irq.json
  GENHDR  include/libopencm3/stm32/f2/irq.json
...
...
...

Now we must target the firmware to our blue pill board, and so compiling the firmware as it was for a ST-Link clone:

[pcortex@pcortex:blackmagic|master]$ cd src
[pcortex@pcortex:src|master]$ make clean
 CLEAN
[pcortex@pcortex:src|master]$ make PROBE_HOST=stlink
GIT     include/version.h
  CC      target/adiv5.c
  CC      target/adiv5_jtagdp.c
  CC      target/adiv5_swdp.c
  CC      command.c
  CC      target/cortexa.c
  CC      target/cortexm.c
...
...
...
  CC      platforms/stlink/dfu_upgrade.c
  LD      dfu_upgrade
  OBJCOPY dfu_upgrade.bin
  OBJCOPY dfu_upgrade.hex

Done! On the src there is now at least two files:

  1. blackmagic_dfu.bin – The Device Firmware Upgrade loader.
  2. blackmagic.bin – The Blackmagic firmware.

Checking the file sizes we can see that the blackmagic.bin file (as of today) 57K, and the bootloader is 6.8K.

Flashing the firmware:
Flashing the firmware can be done by several forms:

  1. Using the STM32 embedded loader through a serial port
  2. Using the SWD connection, ST-Link probe and Openocd
  3. Using the SWD connection, ST-Link probe and Texane/st-link/st-util
  4. Using the DFU protocol, but it depends if the board already has a DFU firmware loaded.

Most of the posts on the internet regarding this step use the first aproach, namely using the STM32 boot loader and serial port. This needs a serial to USB converter to be connected and the STM32 boot pins to be modified.

Anyway, I’m flashing the firmware using Openocd and/or st-link utils through a ST-Link debug probe:

The blue pill pinout is as follows where the SWD connector is oposite the USB port:

From the ST-Link probe we need to connect the following pins:

  • Probe SWCLK Blue Pill DCLK
  • Probe SWDIO Blue Pill DIO
  • Probe GND Blue Pill GND

Regarding the power, I advise not to connect it and power up the blue pill board through the USB connector. This will allow to have access to both boards through USB without any possible power clashes.

We can now flash the firmware either with Texane St-Link programs or the AUR Arch Linux package stlink-git or using Openocd.

For using Openocd, create the following file and name it for example bluepill.cfg:

set CHIPNAME STM32F103C8T6

source [find interface/stlink-v2.cfg]
transport select hla_swd
source [find target/stm32f1x.cfg]
set WORKAREASIZE 0x2000

Also make sure that the ST-Link probe is detected so both st-link utils and openocd can work:

[pcortex@pcortex:src|master]$ lsusb
Bus 002 Device 003: ID 05e3:0608 Genesys Logic, Inc. Hub
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 008 Device 003: ID 046d:c52f Logitech, Inc. Unifying Receiver
Bus 008 Device 002: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)
...
Bus 003 Device 008: ID 0483:3748 STMicroelectronics ST-LINK/V2

We can now flash our board with the following command using Openocd:

openocd -f ../bluepill.cfg -c ‘init_reset halt; program blackmagic_dfu.bin 0x8000000 verify; reset;exit’

[pcortex@pcortex:src|master]$ openocd -f ../bluepill.cfg -c 'init_reset halt; program blackmagic_dfu.bin 0x8000000 verify; reset;exit'
Open On-Chip Debugger 0.10.0
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
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
0x2000
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 v24 API v2 SWIM v4 VID 0x0483 PID 0x3748
Info : using stlink api v2
Info : Target voltage: 3.208372
Info : STM32F103C8T6.cpu: hardware has 6 breakpoints, 4 watchpoints
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x080017b4 msp: 0x20005000
** Programming Started **
auto erase enabled
Info : device id = 0x20036410
Info : flash size = 64kbytes
target halted due to breakpoint, current mode: Thread 
xPSR: 0x61000000 pc: 0x2000003a msp: 0x20005000
wrote 7168 bytes from file blackmagic_dfu.bin in 0.656939s (10.655 KiB/s)
** Programming Finished **
** Verify Started **
target halted due to breakpoint, current mode: Thread 
xPSR: 0x61000000 pc: 0x2000002e msp: 0x20005000
verified 6900 bytes in 0.187018s (36.030 KiB/s)
** Verified OK **
[pcortex@pcortex:src|master]$

Using the st-flash command as documented on STM as BMP

[pcortex@pcortex:src|master]$ st-flash write blackmagic_dfu.bin 0x8000000
st-flash 1.3.1
2017-06-13T20:26:01 INFO src/common.c: Loading device parameters....
2017-06-13T20:26:01 INFO src/common.c: Device connected is: F1 Medium-density device, id 0x20036410
2017-06-13T20:26:01 INFO src/common.c: SRAM size: 0x5000 bytes (20 KiB), Flash: 0x10000 bytes (64 KiB) in pages of 1024 bytes
2017-06-13T20:26:01 INFO src/common.c: Attempting to write 6888 (0x1ae8) bytes to stm32 address: 134217728 (0x8000000)
Flash page at addr: 0x08001800 erased
2017-06-13T20:26:01 INFO src/common.c: Finished erasing 7 pages of 1024 (0x400) bytes
2017-06-13T20:26:01 INFO src/common.c: Starting Flash write for VL/F0/F3 core id
2017-06-13T20:26:01 INFO src/flash_loader.c: Successfully loaded flash loader in sram
  6/6 pages written
2017-06-13T20:26:02 INFO src/common.c: Starting verification of write complete
2017-06-13T20:26:02 INFO src/common.c: Flash written and verified! jolly good!
[pcortex@pcortex:src|master]$

So far so good, but the above is just DFU firmware that allows to use DFU utils later to upgrade the firmware through the USB port without using any other tools.

If unplug and plug our blue pill board and check for the USB ports we have now:

[pcortex@pcortex:src|master]$ lsusb
Bus 002 Device 003: ID 05e3:0608 Genesys Logic, Inc. Hub
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 008 Device 003: ID 046d:c52f Logitech, Inc. Unifying Receiver
Bus 008 Device 002: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)
...
Bus 003 Device 012: ID 1d50:6017 OpenMoko, Inc. Black Magic Debug Probe (DFU)
Bus 003 Device 008: ID 0483:3748 STMicroelectronics ST-LINK/V2
...

And we can now also use the dfu-util command to upload the firmware.

To upload the firmware we will see that it fails due to the firmware size and the 64Kb flash size. It might not happen to you if your board has more than 64Kb of flash available.

With Openocd command:

openocd -f ../bluepill.cfg -c 'init_reset halt; program blackmagic.bin verify; reset;exit'    
Open On-Chip Debugger 0.10.0
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
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
0x2000
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 v24 API v2 SWIM v4 VID 0x0483 PID 0x3748
Info : using stlink api v2
Info : Target voltage: 3.208372
Info : STM32F103C8T6.cpu: hardware has 6 breakpoints, 4 watchpoints
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x080017b4 msp: 0x20005000
** Programming Started **
auto erase enabled
Info : device id = 0x20036410
Info : flash size = 64kbytes
Warn : no flash bank found for address 0
wrote 0 bytes from file blackmagic.bin in 0.016043s (0.000 KiB/s)
** Programming Finished **
** Verify Started **
target halted due to breakpoint, current mode: Thread 
xPSR: 0x61000000 pc: 0x2000002e msp: 0x20005000
Error: checksum mismatch - attempting binary compare
diff 0 address 0x08010000. Was 0xff instead of 0x00
diff 1 address 0x08010001. Was 0xff instead of 0x00
diff 2 address 0x08010002. Was 0xff instead of 0x00
diff 3 address 0x08010003. Was 0xff instead of 0x00
diff 4 address 0x08010004. Was 0xff instead of 0x00
diff 5 address 0x08010005. Was 0xff instead of 0x00
diff 6 address 0x08010006. Was 0xff instead of 0x00

....
diff 123 address 0x0801007b. Was 0xff instead of 0x00
diff 124 address 0x0801007c. Was 0xff instead of 0x00
diff 125 address 0x0801007d. Was 0xff instead of 0x00
diff 126 address 0x0801007e. Was 0xff instead of 0x00
diff 127 address 0x0801007f. Was 0xff instead of 0x00
More than 128 errors, the rest are not printed.
embedded:startup.tcl:476: Error: ** Verify Failed **
in procedure 'program' 
in procedure 'program_error' called at file "embedded:startup.tcl", line 520
at file "embedded:startup.tcl", line 476

With the st-flash command:

[pcortex@pcortex:src|master]$ st-flash --reset write blackmagic.bin 0x8002000
st-flash 1.3.1
2017-06-13T20:37:27 INFO src/common.c: Loading device parameters....
2017-06-13T20:37:27 INFO src/common.c: Device connected is: F1 Medium-density device, id 0x20036410
2017-06-13T20:37:27 INFO src/common.c: SRAM size: 0x5000 bytes (20 KiB), Flash: 0x10000 bytes (64 KiB) in pages of 1024 bytes
2017-06-13T20:37:27 INFO src/common.c: Attempting to write 58084 (0xe2e4) bytes to stm32 address: 134225920 (0x8002000)
2017-06-13T20:37:27 ERROR src/common.c: addr too high
stlink_fwrite_flash() == -1
[pcortex@pcortex:src|master]$ 

And with the dfu util forcing the write above 64Kb:

[pcortex@pcortex:src|master]$ sudo dfu-util -a 0 -s 0x08002000:leave:force -D blackmagic.bin
dfu-util 0.9

Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2016 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/

dfu-util: Invalid DFU suffix signature
dfu-util: A valid DFU suffix will be required in a future dfu-util release!!!
Opening DFU capable USB device...
ID 1d50:6017
Run-time device DFU version 011a
Claiming USB DFU Interface...
Setting Alternate Setting #0 ...
Determining device status: state = dfuIDLE, status = 0
dfuIDLE, continuing
DFU mode device DFU version 011a
Device returned transfer size 1024
DfuSe interface name: "Internal Flash   "
Downloading to address = 0x08002000, size = 58084
dfu-util: Last page at 0x080102e3 is not writeable
[pcortex@pcortex:src|master]$ 

So no luck with my board version, and as a solution we need to strip down the firmware.

Striping down the firmware:
To make the BMP firmware able to fit the 64Kb flash we have to cut things. In my case I’ve removed some processors support since my work is with the STM32 and nRF families:

Edit the file named cortexm.c located at target subdirectory, and delete the following lines around line 254 (or search by PROBE) to remove the unneeded support:

#define PROBE(x) \
        do { if ((x)(t)) return true; else target_check_error(t); } while (0)

        PROBE(stm32f1_probe);
        PROBE(stm32f4_probe);
        PROBE(stm32l0_probe);   /* STM32L0xx & STM32L1xx */
        PROBE(stm32l4_probe);
        PROBE(lpc11xx_probe);
        PROBE(lpc15xx_probe);
        PROBE(lpc43xx_probe);
        PROBE(sam3x_probe);
        PROBE(sam4l_probe);
        PROBE(nrf51_probe);
        PROBE(samd_probe);
        PROBE(lmi_probe);
        PROBE(kinetis_probe);
        PROBE(efm32_probe);

Still at the source directory we build again the firmware:

[pcortex@pcortex:src|master]$ make clean
[pcortex@pcortex:src|master]$ make PROBE_HOST=stlink
[pcortex@pcortex:src|master]$ ls -l blackmagic*
-rwxr-xr-x 1 pcortex users 753K jun 13 20:53 blackmagic*
-rwxr-xr-x 1 pcortex users  55K jun 13 20:53 blackmagic.bin*
-rwxr-xr-x 1 pcortex users 325K jun 13 20:53 blackmagic_dfu*
-rwxr-xr-x 1 pcortex users 6,8K jun 13 20:53 blackmagic_dfu.bin*
-rw-r--r-- 1 pcortex users  20K jun 13 20:53 blackmagic_dfu.hex
[pcortex@pcortex:src|master]$

We can seen now that the firmware was “slim down” around 2K, which is enough now to fit the 64Kb flash:

Using Openocd:

[pcortex@pcortex:src|master]$ openocd -f ../bluepill.cfg -c 'init_reset halt; program blackmagic.bin 0x8002000 verify; reset;exit'
Open On-Chip Debugger 0.10.0
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
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
0x2000
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 v24 API v2 SWIM v4 VID 0x0483 PID 0x3748
Info : using stlink api v2
Info : Target voltage: 3.208372
Info : STM32F103C8T6.cpu: hardware has 6 breakpoints, 4 watchpoints
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x080017b4 msp: 0x20005000
** Programming Started **
auto erase enabled
Info : device id = 0x20036410
Info : flash size = 64kbytes
target halted due to breakpoint, current mode: Thread 
xPSR: 0x61000000 pc: 0x2000003a msp: 0x20005000
wrote 54272 bytes from file blackmagic.bin in 3.792976s (13.973 KiB/s)
** Programming Finished **
** Verify Started **
target halted due to breakpoint, current mode: Thread 
xPSR: 0x61000000 pc: 0x2000002e msp: 0x20005000
verified 53744 bytes in 0.854957s (61.388 KiB/s)
** Verified OK **

Using st-flash:

[pcortex@pcortex:src|master]$ st-flash --reset write blackmagic.bin 0x8002000
st-flash 1.3.1
2017-06-13T20:58:02 INFO src/common.c: Loading device parameters....
2017-06-13T20:58:02 INFO src/common.c: Device connected is: F1 Medium-density device, id 0x20036410
2017-06-13T20:58:02 INFO src/common.c: SRAM size: 0x5000 bytes (20 KiB), Flash: 0x10000 bytes (64 KiB) in pages of 1024 bytes
2017-06-13T20:58:02 INFO src/common.c: Attempting to write 55720 (0xd9a8) bytes to stm32 address: 134225920 (0x8002000)
Flash page at addr: 0x0800f800 erased
2017-06-13T20:58:05 INFO src/common.c: Finished erasing 55 pages of 1024 (0x400) bytes
2017-06-13T20:58:05 INFO src/common.c: Starting Flash write for VL/F0/F3 core id
2017-06-13T20:58:05 INFO src/flash_loader.c: Successfully loaded flash loader in sram
 54/54 pages written
2017-06-13T20:58:09 INFO src/common.c: Starting verification of write complete
2017-06-13T20:58:09 INFO src/common.c: Flash written and verified! jolly good!

Using the DFU firmware upload:

[pcortex@pcortex:src|master]$ sudo dfu-util -a 0 -s 0x08002000:leave:force -D blackmagic.bin
dfu-util 0.9

Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2016 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/

dfu-util: Invalid DFU suffix signature
dfu-util: A valid DFU suffix will be required in a future dfu-util release!!!
Opening DFU capable USB device...
ID 1d50:6017
Run-time device DFU version 011a
Claiming USB DFU Interface...
Setting Alternate Setting #0 ...
Determining device status: state = dfuIDLE, status = 0
dfuIDLE, continuing
DFU mode device DFU version 011a
Device returned transfer size 1024
DfuSe interface name: "Internal Flash   "
Downloading to address = 0x08002000, size = 55720
Download        [=========================] 100%        55720 bytes
Download done.
File downloaded successfully
Transitioning to dfuMANIFEST state

And now if we unplug the blue pill board and connect it again we should have two new tty USB based ports:

[35014.003313] usb 3-2.4: new full-speed USB device number 20 using uhci_hcd
[35019.346373] cdc_acm 3-2.4:1.0: ttyACM0: USB ACM device
[35019.349364] cdc_acm 3-2.4:1.2: ttyACM1: USB ACM device

Success!

Starting using the BMP probe:

To start using our blue pill board as a Blackmagic probe we need the following information and configuration:

  1. Connect a LED (with a resistor…) to pin PA8 to show the probe activity.
  2. The target SWD pins are CLK at pin PA5 and DIO at PB14.
  3. The support for the USB to UART bridge (the second ttyACM1 port) is PA3 – RX and PA2 – TX

So we now can use the BM probe instead of a ST-Link probe, and connect the target board SWD pins to PA5 e PB14: CLK and DIO respectively.

The led will blink when the program is running or it will fast blink when loading a program into the target board.

More information on this video from no other than the builder of the Magic Probe to see more of the probe capabilities. I also recommend the Blackmagic probe wiki for further information.

A quick example with an nRF52 based board connected to the BMP by using the ARM GDB debugger arm-none-eabi-gdb directly:

(gdb) target extended-remote /dev/ttyACM0
Remote debugging using /dev/ttyACM0
(gdb) monitor swdp_scan
Target voltage: unknown
Available Targets:
No. Att Driver
 1      Nordic nRF52
(gdb) att 1
(gdb) monitor
Black Magic Probe (Firmware v1.6.1-25-gaaa7b0e-dirty) (Hardware Version 0)
Copyright (C) 2015  Black Sphere Technologies Ltd.
License GPLv3+: GNU GPL version 3 or later 


Interesting links:

Most of this post wouldn’t be possible without gathering information from around the web. Here is a set of information that might be useful to gather more or missing information from this post:

  1. Black Magic Probe (BMP) on ST-Link v2 clones
  2. STM Discovery as Black Magic Probe
  3. STM32Duino forum

Setting up Openocd for programming the Nordic nRF52832 chip

The following post organizes a set of information gathered from around the web to allow the use openocd utility to also program/access the nRF52 based chips.

Openocd must be patched to be used against the nRF52832 chip. Most of the required information is on this pcbreflux post.

Retriving the sources and patchs
At least, at the current date, on Arch Linux, Openocd version is 0.10. We will keep this version and install side by side the patched version of Openocd that supports the NRF52 chip.

First let’s retrieve the code and patchs:

[pcortex@pcortex:opt]$ git clone git://git.code.sf.net/p/openocd/code openocd-code
Cloning into 'openocd-code'...
remote: Counting objects: 55979, done.
remote: Compressing objects: 100% (20335/20335), done.
remote: Total 55979 (delta 46033), reused 43114 (delta 35495)
Receiving objects: 100% (55979/55979), 12.54 MiB | 2.88 MiB/s, done.
Resolving deltas: 100% (46033/46033), done.
[pcortex@pcortex:opt]$ cd openocd-code
[pcortex@pcortex:openocd-code|master]$ git pull http://openocd.zylin.com/openocd refs/changes/15/3215/2
remote: Counting objects: 1482, done
remote: Finding sources: 100% (11/11)
remote: Total 11 (delta 0), reused 2 (delta 0)
Unpacking objects: 100% (11/11), done.
From http://openocd.zylin.com/openocd
 * branch              refs/changes/15/3215/2 -> FETCH_HEAD
Auto-merging src/flash/nor/drivers.c
CONFLICT (content): Merge conflict in src/flash/nor/drivers.c
Auto-merging src/flash/nor/Makefile.am
CONFLICT (content): Merge conflict in src/flash/nor/Makefile.am
Automatic merge failed; fix conflicts and then commit the result.
[pcortex@pcortex:openocd-code|master *+|MERGING]$ 

After this we have two conflicting files that have changes that we must deal manually.

The src/flash/nor/drivers.c merge conflict is easy to solve. The conflict error is due to clash between empty sections and some added code lines. The end result file is here.

The Makefile.am takes more work to merge, but it is available -> here <- with the merges done.

Then, for specifically support the nRF52832 chip which has 512Kb of flash we need to change the openocd-code/src/flash/nor/nrf52.c currently on line 133, by adding the chip information:

static const struct nrf52_device_spec nrf52_known_devices_table[] = {
	{
		.hwid   = 0x0053,
		.variant  = "QFAA",
		.build_code = "AA",
		.flash_size_kb  = 512,
	},
{
                .hwid        = 0x00C7,
                .variant    = "QFN48",
                .build_code    = "B00",
                .flash_size_kb    = 512,
    	},
};

Done!

We just need now to compile:

    cd /opt/openocd-code/
    ./bootstrap
    ./configure
    make

In my case I just didn’t executed the last sudo make install since I want to have two versions of Openocd side by side.

We should have now at /opt/openocd-code/src the openocd binary with the patchs:

[pcortex@pcortex:src|master *+|MERGING]$ ./openocd -v
Open On-Chip Debugger 0.10.0+dev-00146-g1025be36-dirty (2017-06-04-10:06)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html

Connecting to the nRF52832 using ST-Link

We can now use this version to connect to the nRF52 chip.
A sample openocd config file can be as follows:

nRF52832.cfg

#nRF52832 Target
source [find interface/stlink-v2.cfg]

transport select hla_swd

source [find target/nrf52.cfg]

But since I did not run the sudo make install command the tcl files from the Arch Linux package are different from the patched version, so it is important that the patched version also uses the patched/new files:

./openocd -s /opt/openocd-code/tcl -f nRF52832.cfg

The expected output:

Open On-Chip Debugger 0.10.0+dev-00146-g1025be36-dirty (2017-06-04-10:06)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
adapter speed: 10000 kHz
Info : Unable to match requested speed 10000 kHz, using 4000 kHz
Info : Unable to match requested speed 10000 kHz, using 4000 kHz
Info : clock speed 4000 kHz
Info : STLINK v2 JTAG v21 API v2 SWIM v4 VID 0x0483 PID 0x3748
Info : using stlink api v2
Info : Target voltage: 3.261252
Info : nrf52.cpu: hardware has 6 breakpoints, 4 watchpoints

We should be able now to run the nrf52 command:

telnet localhost 4444
Trying ::1...
Connection failed: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Open On-Chip Debugger
> nrf52
nrf52
  nrf52 mass_erase
nrf52.cpu
  nrf52.cpu arm
    nrf52.cpu arm core_state ['arm'|'thumb']
...

And programming:

> program /opt/nRF5_SDK_12.3.0_d7731ad/examples/ble_peripheral/ble_app_uart/hex/ble_app_uart_pca10028_s130.hex verify
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x000006d0 msp: 0x000007c0
** Programming Started **
auto erase enabled
nRF51822-QFN48(build code: B00) 512kB Flash
Padding image section 0 with 2112 bytes
Padding image section 1 with 32 bytes
using fast async flash loader. This is currently supported
only with ST-Link and CMSIS-DAP. If you have issues, add
"set WORKAREASIZE 0" before sourcing nrf52.cfg to disable it
target halted due to breakpoint, current mode: Thread 
xPSR: 0x61000000 pc: 0x2000001e msp: 0x000007c0
wrote 126976 bytes from file /opt/nRF5_SDK_12.3.0_d7731ad/examples/ble_peripheral/ble_app_uart/hex/ble_app_uart_pca10028_s130.hex in 3.972911s (31.211 KiB/s)
** Programming Finished **
** Verify Started **
target halted due to breakpoint, current mode: Thread 
xPSR: 0x61000000 pc: 0x2000002e msp: 0x000007c0
target halted due to breakpoint, current mode: Thread 
xPSR: 0x61000000 pc: 0x2000002e msp: 0x000007c0
target halted due to breakpoint, current mode: Thread 
xPSR: 0x61000000 pc: 0x2000002e msp: 0x000007c0
verified 121752 bytes in 1.346008s (88.334 KiB/s)
** Verified OK **
> reset run

Remember, if programming fails, with the program command, check if the correct path is provided for openocd through the -s switch.

Done!

NodeJS BLE Applications using BLENO on Arch Linux

BLENO is a greate NodeJS based library for building applications that communicat with other devices (Smartphones, tables, sensor tags) using Bluetooth Low Energy (BLE).

This post is just to quickly document some requirements for successfully use the BLENO library, in my case, on Arch Linux running the latest Plasma (KDE) desktop.

The tools:

Most the information available on the internet for using and controlling the bluetooth adapter uses the now deprecated tools hcitool, hciconfig and so on. Check here the deprecated list of commands.

So we need to use the new tools from the latest Bluez (Bluetooth Linux implementation): btmgm, btinfo, …

Making Bleno examples work:

The simplest example to try out the BLENO library is the battery example located at: […]/bleno/examples/battery-service

First let’s check if our computer/laptop bluetooth adapter is available: Note that all commands must be ran as the root user:

root@pcortex:/opt/bleno/examples/battery-service# btinfo local
Bluetooth information utility ver 5.45
Failed to open HCI user channel
root@pcortex:/opt/bleno/examples/battery-service# 

This issue can be circumvented by stopping the higher level bluetooth stack:

root@pcortex:/opt/bleno/examples/battery-service# systemctl stop bluetooth
root@pcortex:/opt/bleno/examples/battery-service# btinfo local
Bluetooth information utility ver 5.45
HCI version: 6
HCI revision: 7869
LMP version: 6
LMP subversion: 64512
Manufacturer: 2
root@pcortex:/opt/bleno/examples/battery-service#

In case of previously disabling the Bluetooth through the graphical interface:

Disabling the Bluetooth here will have this behaviour (in this case the bluetooth service is still running):

root@pcortex:/opt/bleno/examples/battery-service# systemctl start bluetooth   (<- After this disable bluetooth on the graphical interface)
root@pcortex:/opt/bleno/examples/battery-service# btinfo local
Bluetooth information utility ver 5.45
Failed to open HCI user channel
root@pcortex:/opt/bleno/examples/battery-service# btmgmt power on
Set Powered for hci0 failed with status 0x12 (Blocked through rfkill)
root@pcortex:/opt/bleno/examples/battery-service# 

Even stopping the Bluetooth service keeps the BT adapter disabled:

root@pcortex:/opt/bleno/examples/battery-service# systemctl stop bluetooth
root@pcortex:/opt/bleno/examples/battery-service# btmgmt power on
Set Powered for hci0 failed with status 0x12 (Blocked through rfkill)
root@pcortex:/opt/bleno/examples/battery-service#

We can check this with the rfkill command:

root@pcortex:/opt/bleno/examples/battery-service# rfkill list
0: phy0: Wireless LAN
        Soft blocked: no
        Hard blocked: no
2: hci0: Bluetooth
        Soft blocked: yes
        Hard blocked: no
root@pcortex:/opt/bleno/examples/battery-service# 

We can unblock now the adapter:

root@pcortex:/opt/bleno/examples/battery-service# rfkill unblock 2
root@pcortex:/opt/bleno/examples/battery-service# rfkill list
0: phy0: Wireless LAN
        Soft blocked: no
        Hard blocked: no
2: hci0: Bluetooth
        Soft blocked: no
        Hard blocked: no
root@pcortex:/opt/bleno/examples/battery-service# btinfo local
Bluetooth information utility ver 5.45
HCI version: 6
HCI revision: 7869
LMP version: 6
LMP subversion: 64512
Manufacturer: 2
root@pcortex:/opt/bleno/examples/battery-service# btmgmt power on
hci0 class of device changed: 0x00010c
hci0 Set Powered complete, settings: powered bondable ssp br/edr le secure-conn 
root@pcortex:/opt/bleno/examples/battery-service# 

So why we are having all this work for making sure that the BT adapter is powered on AND the bluetooth stack is stopped (systemctl stop bluetooth).

The answer is quite simple. If we don’t do this the BLENO examples will seem to work (they start) but the BLE advertised services are the bluetooth Bluez services and not our code.

To explain, check the following behaviour where we start the BLENO Battery Service with the Bluetooth stack started:

root@halcyon:/opt/bleno/examples/battery-service# systemctl start bluetooth
root@halcyon:/opt/bleno/examples/battery-service# node main.js 
on -> stateChange: poweredOn
on -> advertisingStart: success
setServices: success

Using the Nordic nRF Connect Android App we can see the non working behaviour vs what we should expect from the Bleno Battery example:

BLE Scan Results

Pressing Connect we can see on Client that no service are provided. This is due to the fact that the desktop bluetooth is enabled):

Now let’s disable the bluetooth stack (which powers the BT adapter) and start again the Bleno Battery example:

root@pcortex:/opt/bleno/examples/battery-service# systemctl stop bluetooth
root@pcortex:/opt/bleno/examples/battery-service# node main.js 

Example hangs in here, because BT adapter is disabled/off

^Croot@pcortex:/opt/bleno/examples/battery-service# btmgmt power on
hci0 class of device changed: 0x00010c
hci0 Set Powered complete, settings: powered bondable ssp br/edr le secure-conn 
root@pcortex:/opt/bleno/examples/battery-service# node main.js 
on -> stateChange: poweredOn
on -> advertisingStart: success
setServices: success

And now if we scan again and connect to the Battery example with our mobile phone through the Nordic application we have:

It works now!

We can confirm that because on the file battery-service.js the service identifier is defined:

function BatteryService() {
  BatteryService.super_.call(this, {
      //uuid: '180F',
      uuid: 'ff51b30e-d7e2-4d93-8842-a7c4a57dfb07',
      characteristics: [
          new BatteryLevelCharacteristic()
      ]
  });
}

and it is the same detected by the Android application.