Biofeedback Smartwatch Update

I’ve been busy recently, with finishing my doctorate and a month long trip. However, I now have a fully wireless biofeedback smartwatch prototype.

The picture is not fully assembled, but everything works other than the lack of a power switch, usb plug, and IC for charging the Li+ battery on the back. I’ve switched from using a naked nRF52810 IC to a TAIYO YUDEN module, it is more expensive, but I was having a lot of trouble getting antennas to work. The wires to the right are for programming with SWD, and the pair of magnet wires soldered to the board itself are for power so I don’t rundown the battery in testing. To the right of the module are two holes for debugging with UART; it’s been really helpful to use that and the logic analyzer to test things during development.

On the finger strap are two electrodes for the GSR voltage bridge, and the MAX30102 SPO2 sensor, which is soldered onto a PCB out of view.

I’m using the following program to activate the ADC and SPO2 sensor and broadcast data over bluetooth. I’m using the nordic UART profile, which contains two characteristics, a read and a write one. I’ve had to learn a lot more about bluetooth than I wanted to for this project.

You can see in the above picture I can stream to my laptop, which live plots the data with matplotlib. I’ve had issues with plot update speeds… it sounds like pyqtgraph is a lot faster but not what I want. I’m probably going to try gnuplot if this is still an issue.

On the plotting side, it’s the same as usual, except with the source of data being:

subprocess.Popen("sudo gatttool -i hci0 -t random -b (nrf mac address) --char-write-req -a 0x10 -n 0100 --listen",shell=True,stdout=subprocess.PIPE)

Which writes 1 (0100 reverse endian) to the handle of the characteristic to enable notifications (0x10). Again, there’s a better way to do this with the actual gatt libraries.

In the end I’m pretty happy with everyting. The GSR data is a lot better since switching to a TI adc (ads1246), and the setup is not that encumbering overall. I plan on working on more data analysis for biofeedback (e.g. getting actual SPO2 values, heart rate counters,…) before doing anything with a phone app.


After all the frustrations with the optoisolators last time I designed a board for the ACSL-6400, which is a quad optoisolator, and ordered some. Today they came so I assembled one and tested putting the CS, MOSI and SCLK signals through it. This one has 4 signals in the same direction, but there is also a 3 out 1 in version specifically for SPI. I didn’t use this because the ADS1299 has both DRDY and the MISO signals I want to connect.

Custom breakout board for the ACSL-6400
When looked at with the signal analyzer, everything is right (inversion is done in MCU software).

Everything appears to work. I have a ton of extra boards, so if anyone is interested in buying assembled quad optoisolator breakout boards, please contact me.

Photoplethysmogram 3

I’ve gotten all of the sensors working at once now. One of the changes is that I’m now using a ’24’ bit differential external ADC. I’m using the NAU7802, which communicates with I2C and runs at a very slow 10-320 SPS. This is plenty fast and seems to be high enough resolution to measure GSR without any external amplifier. The ADC also has an internal PGA which hasn’t been nessesary so far.

More restricting than it could be

The spikes in graphs below for red and IR correspond to heart rate.

I’m currently using the MAX30102’s temperature sensor (which is meant for the LEDs) to measure finger temp. I will have to decide whether this is good enough.

I made several attempts dead-bug soldering the NAU7802. What worked best was to glue to face down on a peice of cardstock and then just solder to the prongs from there.

HX711 – Dynamometer part 1

Grip strength can be used as a measure of overtraining.

There are ADC + strain gauge meters on ebay for hobby bodyweight scales (HX711) that should be good for measuring up to around 200kgs. I ordered one and plan to put the gauges between a pair of half cylinders of wood to measure grip strength.

The HX711 can communicate with microcontrollers with a 2 wire interface like I2C. I’ve gotten this working with the Nucleo and tested it by having the Nucleo output a sin wave and reading the voltage that the HX711 measured.

project stuff here, remember that all the Nucleo stuff is compiled using the mbed compiler

Voltage measured by the HX711. Output is in two’s complement, which is why the sin wave is split between top and bottom. You can see the quantization in the DACs output because there’s a minimum 64 fold amplification for the HX711. This means that even a tiny voltage swing will saturate the output.

Galvinic Skin Response and Hand Temperature

Two biofeedback sensors I can probably get working faster than the EEG are hand temperature and galvinic skin response. Hand temperature biofeedback is mostly used to train relaxation. Adrenaline restricts bloodflow to the skin and hands, so by training yourself to warm your hands you can learn to reduce adrenaline levels. Galvinic skin response is similar. People sweat more when nervous, filling sweat ducts with sweat. This is most pronounced on the hands and feet. Sweating reduces skin resistance by providing a conductive channel into the skin. This effect happens in seconds, and is used in polygraphs to detect lies.

For the most part, the resistance inside the body is low enough not to matter when measuring galvinic skin response. The simplest way to measure skin resistance is to put a current through two electrodes in contact with the skin and measure the voltage difference. This is usually done with electrodes on the index and ring fingers.

(For much more detail on measuring galvinic skin response, see Electrodermal Activity by Wolfram Boucsein)

While high temperature measurements usually use thermocouples, the easiest way to measure hand temperature is by using thermistors. The thermistors linked go between about 80k-100k Ohms around 70-100F. They are incredibly small, which gives them really fast response times and makes it easy to keep them around skin temperature.

For measuring each of these resistances, I constructed voltage bridges with instrumentation amplifiers to increase the voltage range. I then used the integrated ADCs in the Nucleo microcontroller I have to measure the voltage.

Set up the voltage bridge with R3/R4 to be a bit below the lowest voltage between R1/R5. Select gain resistor so that Vout is below 3.3V when R1 at its highest. This setup can be used with both GSR and hand temp, but will require different resistors. GSR would probably benefit with variable resistors to set gain and comparison voltage.

See for example which reads the ADC 10 times a second and communicates it to a python program on a host which plots the output.

Plot of voltage measured for thermistor as I grabbed an icepack at t=50 and t=110.
Voltage for skin resistance, again grabbing an icepack at T=220

Like the EEG project, actually having a wearable probe is difficult. For GSR, I used the following copper coils:

I also tried mounting the thermistors in sections of pipe which I could use as GSR electrodes. While it looks neat, I think it will require rings which fit better.

Getting a Nucleo to work

Nucleos are very nice little dev boards for STM32 microcontrollers. I’ve been using a Nucleo-f446 for some embedded projects over the last two years, but always reluctantly because it would only work with my worst laptop which I keep around specifically for this purpose. They have integrated ST-Link programmers/debuggers which I’ve had issues using due to USB bugs. After a long time I’ve finally gotten it working.

When plugged in over USB, the Nucleo should register as both a 88k block device and as a serial console (/dev/ttyACM[0-9]). The Nucleo is programmed just by moving files onto the block device, and can be interacted with over the serial terminal. On some machines it would just show up as a block device, and on others it would not show up at all. When plugged in, the following would be outputted to dmesg:

[  555.818115] usb 5-2: new full-speed USB device number 5 using xhci_hcd
[  555.989838] usb 5-2: New USB device found, idVendor=0483, idProduct=374b
[  555.989840] usb 5-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  555.989842] usb 5-2: Product: STM32 STLink
[  555.989844] usb 5-2: Manufacturer: STMicroelectronics
[  555.989845] usb 5-2: SerialNumber: 0669FF515056805087142030
[  555.990035] xhci_hcd 0000:0a:00.3: ERROR: unexpected command completion code 0x11.
[  555.990320] usb 5-2: can't set config #1, error -22

I initially thought the kernel was responsible with cdc-acm. I’m not going to describe all the things I’ve tried and instead skip right to the solution. The Nucleo only properly registers when I plug it into my only USB3.1 port instead of any of the USB3.0 ports.

Edit: It also appears not always enumerate unless there are no periphereals plugged into it.

Edit2: I’ve moved to using SW4STM32, and the automatic stlink firmwire update allowed me to use it with any usb plug on my desktop.

EEG part 3: Different passive electrode types

Some notes first:

See for inspiration. From my experience here, maintaining a good and continuous contact is more important than actual materials. A discussion of elastic bands to secure electrodes would be useful.

All of these tests were repeated with different levels of skin preparation (basically before and after rubbing sandpaper and alcohol on) and electrode jelly/saline. For a quick test, getting ECG signals while holding the electrodes between the finger and thumb of each hand is the most convenient

Electrode Tests

Initially, these tests were done with electrodes made with meter long RG58 coax soldered to ‘silver’ disks I ordered off etsy. In retrospect, they were obviously not silver. I secured the disks to the insides of my forearms with rubber bands and then typed commands while trying not to mess that up too much. This was an issue, as I would like a wearable setup and RG58 is just too thick and stiff not to shove the electrodes around causing large jumps in potential. I’ve since tried other electrode types.

Pogo Pins

Pogo pins are small, spring loaded spears with resistances of around 1 Ohm. They are used normally as surface probes for automated testing of assembled PBCs. Because they are spring loaded, I imagined the physical contact might be more secure than a flat disk on the skin.

Pogo pin electrode, no cable attached yet

I assembled the array of pogo pins by stacking layers of protoboard to keep them aligned and then soldering them in. While they worked, they did not work as well as the silver disks. The pressure it took to maintain good connections left marks.

Gold Electrodes

One point of annoyance is that chemical effects can create large potentials compared to ECG signals. For my purposes this could be filtered out with a high pass filter, but I would prefer not to do this. Being relatively chemically inert, gold is a decent material for electrodes (see Evaluation of commercially available electrodes and gels… Clinical Neurophysiology Tallgren et al 2004 for more). Sintered silver chloride is understood to be the best, see the next section for that.

Cheap gold plated electrode. The cable is very flexible which is good for preventing the tugging which causes movement artifacts.

I tried some gold plated electrodes from ebay. I would have loved to use the included cables but well shielded coax has really proved nessesary to prevent strong 60Hz interference [see footnote at end]. These are better than the silver disks, but still not ideal.

Disposable Sintered Ag|AgCl

Again off ebay I ordered electrodes, but this time disposable sintered Ag|AgCl ones.

The silver patchs on the ends of the coax are the undersides of used electrodes.

These are already coated with conductive adhesive so they stick to skin well. In an actual ECG, these are grasped with clips on the white tab, which has a conductive coating underneath it. I tried both using aligator clips on the tab and just sticking the wire underneath and the latter worked better. It is possible a different type of clip would be an improvement. This did not seem to be an improvement upon the gold electrodes, so I decided to stick with them.

*Most articles on ECG and power line noise emphasize the need for strong common mode rejection-CMRR is not the issue here. The issue is the differential signal which can be demonstrated by holding the wires out at different angles. When the wires are parallel and near to eachother, all the powerline noise is common mode and there is no 60Hz signal. When they are held out in opposite directions, the 60Hz noise is maximum, corresponding to a large differential 60Hz pickup. The obvious solution is to have wires take similar paths and only break apart at the end. I have tried this with dual conductor cables where there is only ~12″ of difference and the interference is still worse than with good coax.

Differential 60Hz signal still significant fraction of the total

EEG part 2: Replacing the ADC motherboard

The motherboard which came with the ADS1263 provides power (3.3V digital, 5V analog and ground) and an ability to communicate over USB to ADC board. The ADC itself transfers data using SPI.

ADC daughterboard, raspberry pi and voltage reference with electrodes.

To replace it, I used a raspi to power (as it has both 3.3V and 5V pins) and to get data off of the daughterboard. While the ADC worked, there was a problem with this. The raspi power pins are too noisy for accurate reference. I solved this by moving to some low noise linear power supplies. An alternative might have been to ensure constant power usage for the raspi by disabling features such as SD card use or WIFI. While testing this, it was actually possible to see the power usage change by watching the rail voltage change while typing over SSH. Reading data off with SPI also added noise, so the spi program only reads when triggered on the data out pin of the ADC

You can actually see the bits for SPI on both the 5V and 3.3V rails

(see for the raspi and analysis programs. The raspi transfers data over netcat to the graphing computer.)

Which produces scrolling graphs like the following:

(trace from girlfriend) There’s no 60Hz EMF if you sample at 60Hz. In all of these, it should be noted that these are the best traces, there are often terrible drifts and artifacts from electrodes moving. It would be ideal to have flexible lines to the electrodes.
At 1200 Hz, coax electrodes
400Hz, coax
After applying low and high pass filters. Exact settings forgotten

To be further continued…

SMD Soldering

My brother got me a practice surface mount soldering board with parts down to 0603. I spent an hour or two getting it assembled and learned a lot about surface mount soldering while doing it.

I ended up losing an LED, so L10 isn’t on the board. Which LED is lit progresses rightward before cycling back to L1.

One of the things I learned is to be very careful with winds. Several times I exhaled strongly and blew components around. In the end, my strategy went like this:

  • Decide a number of components to do at once.
  • Apply flux to those pads
  • Set components onto them, pushing them around slowly if nessesary. Remember that the tweezers can get sticky with flux.
  • Clean soldering iron and wet it with a bit of solder. If flux has evaporated from the soldering iron tip reclean and wet again.
  • Hold components in place with downward force from tweezers and go through touching one side of each of them. I’m aware that other people deal with tombstoning in different ways.
  • Solder the other side and clean up. Components can be moved by melting solder on both sides quickly and them pushing them around. Surface tension often corrects component location when both sides are melted.

For the ICs with more pins, the lazy thing worked best.  Generously apply solder  to the legs of the peice making no effort not to bridge them and clean up with some copper wick.

EEG stuff part 1

I heard about a cure for insomnia where you use biofeedback to train yourself to have more delta brainwaves, which are associated with deep sleep. This was on the Joe Rogan Experience, which means it has to be legit. Since then I’ve made some attempts at an EEG like the OpenEEG so I can play with different forms of neurobiofeedback.

There are a variety of biological electric potentials which can be measured for biofeedback. ECG signals are higher amplitude than EEG ones and can be used to measure heart rate and health. EMG is higher frequency and measures the signals causing muscle contraction. I’m starting with ECG because it has a very clear shape and large amplitude, which will help with debugging.

To make things even easier, I started by ordering a dev board for a 32bit ADC on digikey (

32 bits! That gives you minimum voltage increments of less than a nV! EEG potentials are a bit less then uV so this should make it easy.

Again, just to get something easy working, I installed windows so I could use the included software. As electrodes, at first I just tried a pair of wires soldered to silver disks as leads, which had massive amounts of interference. This was measured across my chest, with professional electrode jelly. There was always a ton of 60Hz signal. Then I moved to good shielded coax and connected my right leg to the intermediate voltage (1.6V) to stay within the voltage range. Articles mentioned grounding or driving the shields, both of which made the signal quality worse.

R and T components pretty visible, some drift and plenty of 60Hz.

And it worked! I got clear ECG traces (with a decent amount of 60Hz noise) and went to get something working on linux. In the meantime I broke the motherboard for the ADC, so I had to set up something to power it and get data off of it.

To be continued…