Month: June 2016

Web Bluetooth on Chromium Debian SID – The Saga

If you are following my posts probably you saw my latest post about how to run Web Bluetooth on Chrome/Chromium:
https://acassis.wordpress.com/2016/06/28/how-to-get-chrome-web-bluetooth-working-on-linux/

Although in that post I got the Web Bluetooth working on Chrome/Chromium browser, I noted that after closing the browser and opening again the “get characteristic” sample was not able to list the BLE Device’s Characteristics again:
https://googlechrome.github.io/samples/web-bluetooth/discover-services-and-characteristics.html

Also I observed that after removing the bluez cache (entering in bluetoothctl and executing a “remove XX:YY:ZZ:KK:WW:AA”) the get characteristics sample was enable to list it again.

Then I worked with François Beaufort (a Google Chromium’s Developer) to figure-out what was going on. François was not facing this issue, because he uses a Chromebook powered by ChromeOS. At that moment we didn’t realize that even closing the sample page’s tab the Chromium keep running because it is the heart of ChromeOS. Later François discovered that if he “Sign out” and “Sign in” this issue also will affect him.

Initially we thought it could be some bug in the BlueZ 5.40, maybe bluez was not sending the data when it was cached. But we also discovered that after closing the browser if I issue a connection to device in bluetoothctl (“connect XX:YY:ZZ:KK:WW:AA”) and open the browser, then the get characteristics sample will work again. So it was not a fail of bluez to send cached data.

We decided to contact Luiz von Dentz (Bluez developer at Intel) at #bluez-users IRC channel and he figured out the issue:

vudentz: if (!IsGattServicesDiscoveryComplete()) {
vudentz:     VLOG(2) << "Gatt services have not been fully
resolved for device " << object_path_.value();
vudentz:     return;
vudentz:   }

vudentz: This is probably false if the device is disconnected since
ServicesResolved: no in that case
vudentz: This would explain why it is not enumerating the service on
InitializeGattServiceMap

vudentz:   // Notify on the discovery complete for each service
which is found in the
vudentz:   // first discovery.
vudentz:   DCHECK(adapter());
vudentz:   for (const auto& iter : gatt_services_)
vudentz:     adapter()->NotifyGattDiscoveryComplete(iter.second);
vudentz: This was also not in the original patch, why would we notify
on the InitializeGattServiceMap, there should be any client waiting for it

François was very kind and helpful instructing me to create many debug log to help him, his team and Luiz to debug the issue. Without his patience and dedication we couldn’t find a solution so fast. Thank you François!

The issue was fixed in the BlueZ 5.41 and latest chromium build.
Patch that was applied is https://codereview.chromium.org/2105423003

More info:
https://bugs.chromium.org/p/chromium/issues/detail?id=624400

How to get Chrome Web Bluetooth working on Linux

In my previous post I demonstrated how to test and scan for Bluetooth Low Energy:
https://acassis.wordpress.com/2016/06/27/getting-started-with-bluetooth-low-energy-on-linux/

Now I will explain what I did to get Bluetooth Low Energy working on Linux Debian.

First I installed the Chrome Dev version 53 from here:
https://www.google.com/chrome/browser/desktop/index.html?platform=linux&extra=devchannel

But the Bluetooth Scan Page example was not working:
https://googlechrome.github.io/samples/web-bluetooth/device-info.html

Then searching in the forums I discovered these four requirements to get it working:
1) A recente Chrome version 45+ (I’m using version 53);
2) A recente Linux kernel 3.19+ (my kernel was too old: 3.16);
3) BlueZ 5.40+ (my bluez version was 5.36);
4) Bluetooth daemon (bluetoothd) running with experimental interface (/usr/bin/bluetoothd -E).

Then I updated my Linux kernel:

$ sudo apt-get install linux-image-4.6.0-1-amd64

Compiled Bluez 5.40:

// Install the dependecies:
$ sudo apt-get -y install automake autotools-dev bison check clang flex lcov libcap-ng-dev libdbus-glib-1-dev libdw-dev libglib2.0-dev libical-dev libreadline-dev libtool libudev-dev

//Download bluez-5.40:
$ wget http://www.kernel.org/pub/linux/bluetooth/bluez-5.40.tar.xz

//Extract it:
$ tar xvf bluez-5.40.tar.xz

// Configure and compile it:
$ cd bluez-5.40
$ ./configure --prefix=/usr           \
            --mandir=/usr/share/man \
            --sysconfdir=/etc       \
            --localstatedir=/var    \
            --enable-library        \
            --disable-systemd       \
            --disable-android       \
            --enable-experimental
$ make

// Create a debian package with checkinstall:
$ sudo checkinstall

Here checkinstall didn’t create the /usb/bin/bluetoothd link, let us to create it:

# ln -s /usr/libexec/bluetooth/bluetoothd /usr/bin/bluetoothd

We need to stop bluetoothd daemon and call it with -E:

# /etc/init.d/bluetooth stop
# /usr/libexec/bluetooth/bluetoothd -E &

Now let see if Chromium could communicate with the BLE device:

$ ./chrome --enable-web-bluetooth

Then open the sample page to test Discover Services and Characteristics:
https://googlechrome.github.io/samples/web-bluetooth/discover-services-and-characteristics.html

I will test the Nordic Serial Service, then I enter:

6e400001-b5a3-f393-e0a9-e50e24dcca9e

After updating bluez to version 5.40 the Bluetooth Chooser pop-up window stopped to list the nearby Bluetooth LE devices.

This issue was caused because I used “ControllerMode = le” in the /etc/bluetooth/main.conf. This BUG didn’t exist in the bluez 5.36.

Changing “ControllerMode = dual” in the /etc/bluetooth/main.conf fixed the issue (thanks François Beaufort for the help).

And after restarting bluetoothd and clicking on “Discover services and characteristics” and choosing the Nordic_UART device, it returns:

Requesting any Bluetooth Device...
> Name:             Nordic_UART
> Allowed Services: 6e400001-b5a3-f393-e0a9-e50e24dcca9e
Connecting to GATT Server...
Getting Services...
Getting Characteristics...
> Service: 6e400001-b5a3-f393-e0a9-e50e24dcca9e
>> Characteristic: 6e400003-b5a3-f393-e0a9-e50e24dcca9e [NOTIFY]
>> Characteristic: 6e400002-b5a3-f393-e0a9-e50e24dcca9e [WRITEWITHOUTRESPONSE, WRITE]

References:
https://github.com/beaufortfrancois/sandbox/blob/gh-pages/web-bluetooth/Bluez.md
http://www.linuxfromscratch.org/blfs/view/svn/general/bluez.html

Getting started with Bluetooth Low Energy on Linux

I’m working with BLE on Linux and decided to share here my finding.

First you will need a Bluetooth Low Energy (BLE) compatible host, then if your laptop’s bluetooth is not BLE compatible you will need a bluetooth dongle.

Searching in the Internet I discovered that this low cost CSR V4.0 is compatible.

When plugin it on my laptop I got this info:

#dmesg
...
[ 8972.648662] usb 3-3: new full-speed USB device number 16 using xhci_hcd
[ 8972.870695] usb 3-3: New USB device found, idVendor=0a12, idProduct=0001
[ 8972.870699] usb 3-3: New USB device strings: Mfr=0, Product=2, SerialNumber=0
[ 8972.870702] usb 3-3: Product: CSR8510 A10

Let see the lsusb listing (idVendor=0a12, idProduct=0001):

# lsusb 
...
Bus 003 Device 016: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)

Ok, but for some strange reason my Debian 8.0 delayed some time (~30s) to get it working, strange but at least:

# hciconfig -a hci0
hci0: Type: BR/EDR Bus: USB
BD Address: 00:1A:7D:DA:XX:XX ACL MTU: 310:10 SCO MTU: 64:8
UP RUNNING PSCAN
RX bytes:10241 acl:0 sco:0 events:348 errors:0
TX bytes:1738 acl:0 sco:0 commands:47 errors:0
Features: 0xff 0xff 0x8f 0xfe 0xdb 0xff 0x5b 0x87
Packet type: DM1 DM3 DM5 DH1 DH3 DH5 HV1 HV2 HV3
Link policy: RSWITCH HOLD SNIFF PARK
Link mode: SLAVE ACCEPT
Name: 'inspire'
Class: 0x00010c
Service Classes: Unspecified
Device Class: Computer, Laptop
HCI Version: 4.0 (0x6) Revision: 0x22bb
LMP Version: 4.0 (0x6) Subversion: 0x22bb
Manufacturer: Cambridge Silicon Radio (10)

Now let search for a Bluetooth LE device:

# hcitool lescan
LE Scan ...
BC:6A:29:AB:3F:46 (unknown)
BC:6A:29:AB:3F:46 SensorTag
BC:6A:29:AB:3F:46 (unknown)
BC:6A:29:AB:3F:46 SensorTag
BC:6A:29:AB:3F:46 (unknown)

You can connect to this device using the gattool

# gatttool -I
[                 ][LE]> help
help                                           Show this help
exit                                           Exit interactive mode
quit                                           Exit interactive mode
connect         [address [address type]]       Connect to a remote device
disconnect                                     Disconnect from a remote device
primary         [UUID]                         Primary Service Discovery
included        [start hnd [end hnd]]          Find Included Services
characteristics [start hnd [end hnd [UUID]]]   Characteristics Discovery
char-desc       [start hnd] [end hnd]          Characteristics Descriptor Discovery
char-read-hnd                          Characteristics Value/Descriptor Read by handle
char-read-uuid   [start hnd] [end hnd]   Characteristics Value/Descriptor Read by UUID
char-write-req              Characteristic Value Write (Write Request)
char-write-cmd              Characteristic Value Write (No response)
sec-level       [low | medium | high]          Set security level. Default: low
mtu                                     Exchange MTU for GATT/ATT
[                 ][LE]> connect BC:6A:29:AB:3F:46
Attempting to connect to BC:6A:29:AB:3F:46
Connection successful

// Let to list primary Services:
[BC:6A:29:AB:3F:46][LE]> primary
attr handle: 0x0001, end grp handle: 0x000b uuid: 00001800-0000-1000-8000-00805f9b34fb
attr handle: 0x000c, end grp handle: 0x000f uuid: 00001801-0000-1000-8000-00805f9b34fb
attr handle: 0x0010, end grp handle: 0x0022 uuid: 0000180a-0000-1000-8000-00805f9b34fb
attr handle: 0x0023, end grp handle: 0x002a uuid: f000aa00-0451-4000-b000-000000000000
attr handle: 0x002b, end grp handle: 0x0035 uuid: f000aa10-0451-4000-b000-000000000000
attr handle: 0x0036, end grp handle: 0x003d uuid: f000aa20-0451-4000-b000-000000000000
attr handle: 0x003e, end grp handle: 0x0048 uuid: f000aa30-0451-4000-b000-000000000000
attr handle: 0x0049, end grp handle: 0x0054 uuid: f000aa40-0451-4000-b000-000000000000
attr handle: 0x0055, end grp handle: 0x005c uuid: f000aa50-0451-4000-b000-000000000000
attr handle: 0x005d, end grp handle: 0x0061 uuid: 0000ffe0-0000-1000-8000-00805f9b34fb
attr handle: 0x0062, end grp handle: 0x0068 uuid: f000aa60-0451-4000-b000-000000000000
attr handle: 0x0069, end grp handle: 0xffff uuid: f000ffc0-0451-4000-b000-000000000000

//Let see the visible characteristics:
[BC:6A:29:AB:3F:46][LE]> char-desc 0x0018 0x002A
handle: 0x0018, uuid: 00002a26-0000-1000-8000-00805f9b34fb
handle: 0x0019, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x001a, uuid: 00002a27-0000-1000-8000-00805f9b34fb
handle: 0x001b, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x001c, uuid: 00002a28-0000-1000-8000-00805f9b34fb
handle: 0x001d, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x001e, uuid: 00002a29-0000-1000-8000-00805f9b34fb
handle: 0x001f, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0020, uuid: 00002a2a-0000-1000-8000-00805f9b34fb
handle: 0x0021, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0022, uuid: 00002a50-0000-1000-8000-00805f9b34fb
handle: 0x0023, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x0024, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0025, uuid: f000aa01-0451-4000-b000-000000000000
handle: 0x0026, uuid: 00002902-0000-1000-8000-00805f9b34fb
handle: 0x0027, uuid: 00002901-0000-1000-8000-00805f9b34fb
handle: 0x0028, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0029, uuid: f000aa02-0451-4000-b000-000000000000
handle: 0x002a, uuid: 00002901-0000-1000-8000-00805f9b34fb
[BC:6A:29:AB:3F:46][LE]> 

Nice! Everthing is working!

The “gatttool” is deprecated and will be removed soon, then we need to use bluetoothctl instead! This way:

# bluetoothctl
//scan for BLE devices:
[bluetooth]# scan on
Discovery started
[CHG] Controller 00:1A:7D:DA:71:10 Discovering: yes
[CHG] Device EC:F2:E5:CE:30:5B RSSI: -44
[CHG] Device EC:F2:E5:CE:30:5B RSSI: -52
[CHG] Device EC:F2:E5:CE:30:5B RSSI: -44

//connect to it:
[bluetooth]# connect EC:F2:E5:CE:30:5B
Attempting to connect to EC:F2:E5:CE:30:5B
[CHG] Device EC:F2:E5:CE:30:5B Connected: yes
Connection successful

//get information from device
[Nordic_UART]# info
Device EC:F2:E5:CE:30:5B
	Name: Nordic_UART
	Alias: Nordic_UART
	Paired: no
	Trusted: yes
	Blocked: no
	Connected: yes
	LegacyPairing: no
	UUID:                           (1800)
	UUID:                           (1801)
	UUID: Vendor specific           (6e400001-b5a3-f393-e0a9-e50e24dcca9e)
	RSSI: -44

//list the attributes
[Nordic_UART]# list-attributes
Service /org/bluez/hci0/dev_EC_F2_E5_CE_30_5B/service0009 Vendor specific (Primary)
Characteristic /org/bluez/hci0/dev_EC_F2_E5_CE_30_5B/service0009/char000d Vendor specific
Characteristic /org/bluez/hci0/dev_EC_F2_E5_CE_30_5B/service0009/char000a Vendor specific
Descriptor /org/bluez/hci0/dev_EC_F2_E5_CE_30_5B/service0009/char000a/desc000c Client Characteristic Configuration

//get information from an attribute:
[Nordic_UART]# attribute-info /org/bluez/hci0/dev_EC_F2_E5_CE_30_5B/service0009
Service - Vendor specific
	UUID: 6e400001-b5a3-f393-e0a9-e50e24dcca9e
	Primary: yes
	Characteristics: /org/bluez/hci0/dev_EC_F2_E5_CE_30_5B/service0009/char000a
	Characteristics: /org/bluez/hci0/dev_EC_F2_E5_CE_30_5B/service0009/char000d

The listing of primary services you can find here:
https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx

The listing of characteristics you can find here:
https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicsHome.aspx

Case you don’t have a BLE compatible device to search for, you can transform your smartphone in a BLE device using the peripheral mode application:
https://github.com/WebBluetoothCG/ble-test-peripheral-android

References: https://learn.adafruit.com/reverse-engineering-a-bluetooth-low-energy-light-bulb/control-with-bluez

How I got fooled by Nordic’s app_uart_init

The Nordic nRF51822 SDK supports two serial communication modes: raw and fifo.

There are two macros used to initialize each mode:

APP_UART_INIT(P_COMM_PARAMS, EVT_HANDLER, IRQ_PRIO, ERR_CODE)

APP_UART_FIFO_INIT(P_COMM_PARAMS, RX_BUF_SIZE, TX_BUF_SIZE, EVT_HANDLER, IRQ_PRIO, ERR_CODE)

Once initialized you can use “app_uart_put()” to send a character and “app_uart_get()” to get a character.

If you initialize with APP_UART_FIFO_INIT() macro, but link your application to app_uart.c instead of app_uart_fifo.c everything will compile fine.
You could send some text using app_uart_put in your main() function, but when you get some BLE data received event and try to use it… you will get troubles!

Only the first character will be sent to UART, nothing else…

I spent much time trying to figure-out why it was not working, finally I found someone with same problem and he give a hint:

https://devzone.nordicsemi.com/question/20383/sending-via-uart/

Just linking to app_uart_fifo.c instead of app_uart.c fixed the issue!

Testing the Nordic UART Service for nRF51822

Today I decided to test the Nordic Uart Service (NUS) to enable a serial communication (emulated) between a Bluetooh Low Energy device (nRF51822) and an Android device.

The Nordic SDK comes with an example (nordic/examples/ble_peripheral/ble_app_uart) used for serial communication over BLE. For more info:
https://devzone.nordicsemi.com/documentation/nrf51/6.0.0/s110/html/a00066.html

I download the SDK modified to compile with open-source toolchains:
https://github.com/relayr/nrf51-sdk.git

For more info read me previous post:
https://acassis.wordpress.com/2016/02/25/using-openocd-to-program-a-homebrew-nrf51822-board/

The compilation was not so easy as it is supposed to do. I got some undefined references, like this one:

.../newlib/libc/reent/sbrkr.c:58: undefined reference to `_sbrk' 

I fixed it editting “relayr/ld/libc-nano.ld” file and adding:

EXTERN(_sbrk_r)
EXTERN(_write_r)
EXTERN(_close_r)
EXTERN(_lseek_r)
EXTERN(_read_r)
EXTERN(_fstat_r)
EXTERN(_isatty_r)

Also I created a custom board definition based on wunderbar-master-nrf.h

$ cp relayr/include/wunderbar-master-nrf.h relayr/include/custom_board.h

And finally created a build.mk with all files needed to compile the example:

DEVICE_VARIANT?= xxaa

DEFINES+= NRF51 NRF51822_QFAA_CA BOARD_CUSTOM
SDKINCDIRS+= toolchain toolchain/gcc drivers_nrf/hal device libraries/scheduler
SDKINCDIRS+= softdevice/common/softdevice_handler libraries/timer
SDKINCDIRS+= ble/ble_advertising libraries/button ble/ble_services/ble_nus
SDKINCDIRS+= drivers_nrf/uart drivers_nrf/gpiote drivers_nrf/config drivers_nrf/common
SDKINCDITS+= drivers_nrf/hal libraries/fifo

EXPINCDIR+= bsp
EXPINCDIR+= ble_peripheral/ble_app_uart/config

SDKSRCS+= toolchain/gcc/gcc_startup_nrf51.s toolchain/system_nrf51.c
SDKSRCS+= libraries/timer/app_timer.c
SDKSRCS+= ble/common/ble_advdata.c
SDKSRCS+= ble/common/ble_conn_params.c
SDKSRCS+= softdevice/common/softdevice_handler/softdevice_handler.c
SDKSRCS+= libraries/scheduler/app_scheduler.c
SDKSRCS+= libraries/timer/app_timer_appsh.c
SDKSRCS+= drivers_nrf/uart/app_uart_fifo.c
SDKSRCS+= ble/ble_services/ble_nus/ble_nus.c
SDKSRCS+= ble/ble_advertising/ble_advertising.c
SDKSRCS+= libraries/button/app_button.c
SDKSRCS+= drivers_nrf/gpiote/nrf_drv_gpiote.c
SDKSRCS+= drivers_nrf/common/nrf_drv_common.c
SDKSRCS+= libraries/fifo/app_fifo.c

EXPSRCS+= bsp/bsp.c
EXPSRCS+= bsp/bsp_btn_ble.c

USE_SOFTDEVICE?= s110

SDKDIR:= $(abspath $(dir $(lastword ${MAKEFILE_LIST})))
ifndef SDDIR
SDKINCDIRS+= softdevice/${USE_SOFTDEVICE}/headers
else
CFLAGS+= -I${SDDIR}/include
endif

SOFTDEV_HEX?= $(lastword $(wildcard ${SDKDIR}/nordic/components/softdevice/${USE_SOFTDEVICE}/hex/${USE_SOFTDEVICE}*softdevice.hex))

SDKINCDIRS+= $(sort $(dir ${SDKSRCS}) )

SRCS+= $(patsubst %,${SDKDIR}/nordic/examples/%,${EXPSRCS})

ifdef USE_RTX
DEFINES+= RTX __HEAP_SIZE=0 __STACK_SIZE=1024
SRCS+= ${SDKDIR}/nordic/external/rtx/port/RTX_Conf_CM.c
CFLAGS+= -I${SDKDIR}/nordic/external/rtx/include
LDLIBS+= ${SDKDIR}/nordic/external/rtx/source/GCC/libRTX_CM0.a
endif

ifeq ($(filter FALSE false NO no 0,${USE_SIMBLE}),)
include ${SDKDIR}/relayr/src/build.mk
endif

CPPFLAGS+= $(patsubst %,-D%,${DEFINES})

CFLAGS+= -I${SDKDIR}/relayr/include
CFLAGS+= $(patsubst %,-I${SDKDIR}/nordic/examples/%,${EXPINCDIR})

CFLAGS+= $(patsubst %,-I${SDKDIR}/nordic/components/%,${SDKINCDIRS})
CFLAGS+= -mcpu=cortex-m0 -mfloat-abi=soft -mthumb -mabi=aapcs	\
	-ffunction-sections -fdata-sections -fno-builtin \
	-fplan9-extensions
CFLAGS+= -std=gnu11
CFLAGS+= -fshort-wchar -Wl,--no-wchar-size-warning
CFLAGS+= -Wall -Wno-main -Werror
CFLAGS+= -g

LINKERSCRIPT?= gcc_nrf51_${USE_SOFTDEVICE}_${DEVICE_VARIANT}.ld

LDFLAGS+= -Wl,--gc-sections -fwhole-program --specs=nano.specs
LDFLAGS+= -Wl,-Map=${PROG}.map
LDFLAGS+= -Wl,-T,${SDKDIR}/relayr/ld/libc-nano.ld
LDFLAGS+= -Wl,-L${SDKDIR}/relayr/ld
LDFLAGS+= -Wl,-L${SDKDIR}/nordic/components/toolchain/gcc
LDFLAGS+= -Wl,-T,${LINKERSCRIPT}
LDFLAGS+= -lgcc -lc -lm -lg -lrdimon -lnosys

ASFLAGS+= -x assembler-with-cpp


SRCS+=	$(patsubst %,${SDKDIR}/nordic/components/%,${SDKSRCS})


CC=	arm-none-eabi-gcc
OBJCOPY=	arm-none-eabi-objcopy
OBJDUMP=	arm-none-eabi-objdump
GDB=	arm-none-eabi-gdb

GENERATE.d=	$(CC) -MM ${CFLAGS} ${CPPFLAGS} -MT $@ -MT ${@:.d=.o} -MP -MF $@ $<
COMPILE.s=	${COMPILE.S}


all: ${PROG}.hex ${PROG}.bin

define compile_source
ifneq ($(filter %.c %.S %.s,${1}),)
$(addsuffix .o,$(notdir $(basename ${1}))): ${1}
	$${COMPILE$(suffix ${1})} $${OUTPUT_OPTION} $$<
endif

ifneq ($(filter %.c,${1}),)
$(addsuffix .d,$(notdir $(basename ${1}))): ${1}
	$$(GENERATE.d)
endif

OBJS+=	$$(addsuffix .o,$(notdir $(basename ${1})))
endef

$(foreach f,${SRCS},$(eval $(call compile_source,$f)))

ifneq (${MAKECMDGOALS},clean)
-include $(patsubst %.o,%.d,${OBJS})
endif

CLEANFILES+= ${OBJS} ${OBJS:.o=.d} ${PROG}.hex ${PROG}.elf ${PROG}.bin ${PROG}.map ${PROG}.jlink ${PROG}-all.jlink

${PROG}.elf: ${OBJS}
	${CC} -o $@ ${CFLAGS} ${LDFLAGS} ${OBJS} ${LDLIBS}

%.hex: %.elf
	${OBJCOPY} -O ihex $< $@

%.bin: %.elf
	${OBJCOPY} -O binary $< $@

%.jlink: %.hex
	${OBJDUMP} -h $< | \
	awk '$$1 ~ /^[0-9]+$$/ {addr="0x"$$5; if (!min || addr < min) min = addr} END { printf "\
	loadbin %s,%s\n\
	r\n\
	g\n\
	exit\n", f, min}' f="$ $@

%-all.jlink: %.jlink ${SOFTDEV_HEX} FORCE
	@[ -e "${SOFTDEV_HEX}" ] || echo "cannot find softdevice hex image '${SOFTDEV_HEX}'" >&2
	# w4 0x4001e504, 0x2 -> enable erase: CONFIG.WEN = EEN
	# w4 0x4001e50c, 0x1 -> erase all: ERASEALL = 1
	printf "\
	device NRF51822_XXAA\n\
	halt\n\
	w4 0x4001e504, 0x2\n\
	w4 0x4001e50c, 0x1\n\
	sleep 1\n\
	loadbin %s,0\n" ${SOFTDEV_HEX} > $@
	cat $> $@

flash: ${PROG}.hex ${PROG}.jlink
	JLinkExe -device nRF51822_xxAA -if SWD ${PROG}.jlink

flash-all: ${PROG}.hex ${SOFTDEV_HEX} ${PROG}-all.jlink
	JLinkExe -device nRF51822_xxAA -if SWD ${PROG}-all.jlink

gdbserver: ${PROG}.elf
	JLinkGDBServer -device nRF51822_xxAA -if SWD

gdb: ${PROG}.elf
	${GDB} ${PROG}.elf -ex 'target extended-remote :2331'

GITREV= $(shell git describe --always)
MAILFILE= ${PROG}-${GITREV}.hex
CLEANFILES+= ${PROG}-*.hex

mailfile: ${MAILFILE}
	-$(foreach f,$(filter-out $<,$(wildcard ${PROG}-*.hex)),rm $f;)
	-@md5sum $<
	-@sha256sum $<

${PROG}-${GITREV}.hex: ${PROG}.hex
	cp $< $@

clean:
	-rm -f ${CLEANFILES}

.PHONY: all flash flash-all gdbserver gdb clean FORCE

Running NuttX on a less than U$2.00 board

Few months ago I discovered a low cost board powered by STM32F103C8T6 microcontroller.

That board is referenced as “STM32 Minimum System Development Board” or as “BluePill Board”:

http://www.cnx-software.com/2016/05/17/bluepill-is-a-2-arduino-compatible-development-board-based-on-stmicro-stm32-mcu/

http://www.stm32duino.com/viewtopic.php?t=117

I bought that board from Aliexpress for U$1.96:
http://aliexpress.com/item/STM32F103C8T6-ARM-STM32-Minimum-System-Development-Board-Module-ForArduin/32282374854.html

Then when it arrived I got NuttX running on it and submitted a patch to Mr. Greg to add it to NuttX mainline. Now everybody can get NuttX running on it easily.

This tutorial will explain how to do that, first let me list what you will need:
– The STM32F103C8T6 Minimum board;
– A STLinkV2 programmer (or a low cost clone) ;
– A USB/Serial adapter 3.3V compatible (like this one on ebay);
– A USB to MicroUSB cable, like these used to recharge your smartphone;
– A computer running Linux Debian or Ubuntu (it is possible on Windows using Cygwin or Mac OS, but I don’t use these OS).

First step is the instalation of development tools:
1) Install gcc-arm-none-eabi package:

$ sudo apt-get install gcc-arm-none-eabi

2) Compile and install OpenOCD
Note: If your system doesn’t have the development tools and libraries then install these packages listed here: https://acassis.wordpress.com/2013/10/07/quais-pacotes-de-desenvolvimento-instalar-no-linux/

$ git clone http://repo.or.cz/r/openocd.git
$ cd openocd
$ ./bootstrap
$ ./configure --enable-internal-jimtcl --enable-maintainer-mode --disable-werror --disable-shared --enable-stlink --enable-jlink --enable-rlink --enable-vslink --enable-ti-icdi --enable-remote-bitbang --enable-usb-blaster --enable-presto --enable-osbdm

You will see it at end of this process:

libjaylink configuration summary:
 - Package version ................ 0.1.0
 - Library version ................ 0:0:0
 - Installation prefix ............ /usr/local
 - Building on .................... x86_64-pc-linux-gnu
 - Building for ................... x86_64-pc-linux-gnu



OpenOCD configuration summary
--------------------------------------------------
MPSSE mode of FTDI based devices        yes (auto)
Segger J-Link JTAG Programmer           yes
ST-Link JTAG Programmer                 yes
TI ICDI JTAG Programmer                 yes
Keil ULINK JTAG Programmer              yes (auto)
Altera USB-Blaster II Compatible        yes (auto)
Versaloon-Link JTAG Programmer          yes
OSBDM (JTAG only) Programmer            yes (auto)
eStick/opendous JTAG Programmer         yes (auto)
Andes JTAG Programmer                   yes (auto)
USBProg JTAG Programmer                 yes (auto)
Raisonance RLink JTAG Programmer        yes
Olimex ARM-JTAG-EW Programmer           yes (auto)
CMSIS-DAP Compliant Debugger            yes (auto)

Now compile and install it:

$ make
$ sudo make install

Now the next step is download and compiling NuttX:

1) Download the NuttX kernel and its applications:

$ mkdir NuttX
$ cd NuttX
$ git clone https://bitbucket.org/nuttx/nuttx
$ git clone https://bitbucket.org/nuttx/apps
$ git clone https://bitbucket.org/nuttx/tools

2) Compile the Kconfig Frontend needed by NuttX:

$ cd tools/kconfig-frontends
$ ./configure
$ make
$ sudo make install

3) Compile NuttX for stm32f103-minimum board:

$ cd ../..
$ cd nuttx/tools
$ ./configure.sh stm32f103-minimum/nsh
$ make menuconfig

Enter into "Build Setup" menu and confirm that "Build Host Platform" is defined to Linux
Enter in "System Type" -> "Toolchain Selection" and confirm that:
(X) Generic GNU EABI toolchain under Linux

Select <EXIT> and confirm to save everything.

Now you can compile it:

$ make

At end of compilation you will see:

make[2]: Leaving directory '/tmp/NuttX/nuttx/configs/stm32f103-minimum/src'
LD: nuttx
make[1]: Leaving directory '/tmp/NuttX/nuttx/arch/arm/src'
CP: nuttx.bin

3) Flashing the firmware nuttx.bin in the stm32f103-minimum board:
Connect the USB Cable and the STLinkV2 programmer to STM32F103 board this way:

Create a file openocd_stm32f1.cfg with this content:

# Using stlink as SWD programmer
source [find interface/stlink-v2.cfg]

# SWD as transport
transport select hla_swd

# Use STM32F103 target
set WORKAREASIZE 0x4000
source [find target/stm32f103c8t6.cfg]

Execute OpenOCD passing this configuration file:

$ sudo openocd -f openocd_stm32f1.cfg

Open On-Chip Debugger 0.10.0-dev-00300-g89bf96f-dirty (2016-05-20-17:42)
Licensed under GNU GPL v2
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.297181
Info : stm32f1x.cpu: hardware has 6 breakpoints, 4 watchpoints

Open a new shell terminal and execute:

$ telnet 127.0.0.1 4444

You will be presented with this message:

Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Open On-Chip Debugger
> 

Now execute this command to store nuttx.bin in the stm32f103 flash memory:

> reset halt

stm32f1x.cpu: target state: halted
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x080003ac msp: 0x20000730

> flash write_image erase nuttx.bin 0x08000000

auto erase enabled
device id = 0x20036410
ignoring flash probed value, using configured bank size
flash size = 128kbytes
stm32f1x.cpu: target state: halted
target halted due to breakpoint, current mode: Thread 
xPSR: 0x61000000 pc: 0x2000003a msp: 0x20000730
wrote 40960 bytes from file nuttx.bin in 2.384699s (16.774 KiB/s)
> 

Finally all you need to do is to connect a USB/Serial and use a Serial Console as Minicom/Picocom/Screen to get access to NuttX terminal .

-------------------------------
|USB/Serial | STM32F103 Board |
-------------------------------
|   RXD     |       A9        |
|   TXD     |      A10        |
|   GND     |       G         |
-------------------------------

Configure Minicom or use your preferred serial program to 115200 8n1 with your USB/Serial adapter, i.e /dev/ttyUSB0. You will get this message after pressing the RESET button:

NuttShell (NSH)
nsh>