Portable Healthcare – Hybrid Cardiography Monitoring via BLE

We build a FPGA prototyping board to collect cardio-related bio-signals.


  1. Robust heartbeat tracking using wrist mounted photoplethysmography(PPG) signals;

  2. Synchronous ECG/PPG sampling during fitness on a treadmill with speed ranging from 2km/h to 15km/h;

  3. PPG data with strong motion artifact can be effectively compressed via low-power compresssed sensing.


lx9micro + pmodAD2 + pmodACL + pmodBT2

building a 4-channel, 3-axis accelerometer evaluation system

phealth – architecture

Lx9 Microboard for Healthcare 

FPGA captures 3-axis accelerometer reads from ADXL345, 4-channel biosignals (one for ECG, and three for PPG) from AD7991. These recordings are transferred to PC via USB2UART using CP2102, or remotely via a bluetooth device RN-42.

Two peripherals are used, which are I2C and UART. SPI may also be used if we utilize the 4-wire connection of ADXL345. Those codes, i2c_master.vhd and uart.vhd are publicity available, and borrowed from I2C master @ eewiki and uart @ pabennett.

FPGA, is simply a logic wrapper of all the auxiliary peripherals.

pmodAD2 – AD7991

PmodAD2, ad7991, has an I2C interface and up to 4 channels of ADC conversion. It supports 12-bit resolution. AD7991 remains in shutdown mode, powering up only for conversions. The conversion process is controlled by an I2C command. The range (when REF_SEL disabled) is 0V to VDD. We enable 4-channel conversion by disable REF_SEL, and connet jumper JP1 to vin4.

The serial clock frequencies for AD7991 are standard (100KHz), fast (400KHz) and high speed(3.4MHz). The address of AD7991 is b“0101000”, followed by a tailing bit denotes whether it is write (RW=0) or read (RW=1). You may refer to AD7991 datasheet, Table 10, for more details.

The converted samples, each has 2-Byte, where D15-D14 are 0s, D13-D12 is the channel identifier, D11-D0 are the ADC conversions in the range 0 to VDD.

The workflow of ad7991.vhd wrapper is,

  1. put address b“0101000” on the ADDRESS bus of i2c_master.vhd, RW=0 for write, I2C data is b“11110100”;

  2. RW=1 for read, wait until i2c_busy is pulled up;

  3. put AD7991 in continuous read mode, issue RW=1 and register valid and dout for the incomming data.

see the code ad7991.vhd for more details.

pmodACL – ADXL345

We connect the ADXL345 cable to the pmod slot by,

1 2 3 4 5 6

The I2C address of ADXL345 is 0x1D. In order to use this address (rather than SPI interface or the alternate address), you should tied CS to HIGH and SDO to HIGH; if you want to use the alternate address 0x53, pin SDO must pulldown to GND. You could test the function of I2C interface by reading the chip ID from the CHIPID address 0x00, see if you can get 0xE5.

  1. Hint 1, in SPI interface, DATAX0 is stored in 0x32 and 0x33 respectively, so you may put address (0x80 | 0x32) = 0xB2 on that bus, where the MSB is for read; or (0x80 | 0x40 | 0x32) = 0xF2 for continuous read operation. While for I2C to function, you only need 0x32 for single byte read, or 0x72 for continuous read. No MSB tunation is needed.

  2. Hint 2, in I2C mode, when your read DATAX0 using 0x32, and continuous trigger the I2C read operation, it by default works in the continous read mode. 0x32 has the same effect as 0x72 in I2C mode.

The adxl345.vhd wrapper works as,

  1. ADDRESS x“1D”, RW=0, continuous write data x“31” (DATA_FORMAT) and x“01” (4g range); stop;

  2. ADDRESS x“1D”, RW=0, continuous write data x“2C” (BW_RATE) and x“0C” (400Hz rates); stop;

  3. ADDRESS x“1D”, RW=0, continuous write data x“2D” (POWER_CTL) and x“08” (start measure); stop;

  4. ADDRESS x“1D”, RW=0, write data x“72” (0x40 | 0x32 = 0x72, continuous read from DATAX0); restart

  5. ADDRESS x“1D”, RW=1, continous read 6-Byte; idle.

USB2UART – cp2102

The interface of uart.vhd is very pleasant ! We may connect rx, tx pins to proper direction, (tx on uart.vhd denotes bits streamed out this module, data_stream_in_* denote the Byte to be write into this module.)

  1. WRITE, put data on bus, issue data_stream_in_stb, wait until data_stream_in_ack;

  2. READ, register data when data_stream_out_stb is valid, responds by issue data_stream_out_ack.

pmodBT2 – RN-42

We may use RN-42 as a replacement of CP2102, where

uart.vhd CP2102 (fpga is master) RN-42 (rn42 is master)

The serial can be debuged using minicom. Warning: it was said that RN42 enable hardware flowcontrol, however when I connect via minicom -s, (remember to enable echo by Ctrl + A, E), I had to disable hardware flowcontrol, to enter the command mode of RN42. (where 3 dollar signs may enter the CMD prompt).

you may use the command mode to debug the connection of RN42

connect to RN42 and record data

References : Archlinux FAQ 1, FAQ 2, Archlinux bluetooth tutorial, Thinkwiki – Bluetooth, write a rfcomm.conf. We may use either bluetooth dongle or the bluetooth in the PC.

$ rfkill list
$ pacman -Q | grep blue
$ systemctl status bluetooth.service

enable the bluetooth.service

$ lsusb
Bus 003 Device 005: ID 0a5c:21e6 Broadcom Corp. BCM20702 Bluetooth 4.0 [ThinkPad]
Bus 001 Device 017: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)

The bluetooth on-board is hci0, then

$ sudo hciconfig hci0 up
$ sudo hcitool scan
Scanning ...
    00:06:66:43:0F:2E   RN42-0F2E

The device name of RN42 as well as the MAC address are listed.

We may add a udev.rules to bringup the bluetooth by default.

$ vim /etc/udev/rules.d/10-local.rules
# Set bluetooth power up
# ACTION=="add", KERNEL=="hci0", RUN+="/usr/bin/hciconfig hci0 up"

Finally, we use the bluetooth as a replacement of Serial interface, via rfcomm,

$ sudo modprobe btusb
$ sudo modprobe ath3k
$ sudo modprobe rfcomm
$ sudo rfcomm bind rfcomm0 00:06:66:43:0F:2E

We now have two serial interfaces, one is USB2UART /dev/ttyUSB0, another is bluetooth UART /dev/rfcomm0. By setting 115200 8N1 for both serial devices, we can communicate in minicom ! Remember to enable ECHO in minicom via Ctrl + A, E.

NOTE When we connect to the bluetooth serial (via python, minicom, etc.,) and receive data, the pairing LED on RN42 will flash, and the connection status LED will pulldown (connected). Data are now transmitted from slave to our PC.


comments powered by Disqus