In April of 2020, with COVID-19 on the rise, health monitoring became a hot topic in the tech industry, and Codethink decided it was a good time to further build on our existing medical/fitness story.
The Bloodlight project was designed to test for new health metrics in the blood by testing multiple LED wavelengths of light at high-frequency and accuracy. We hoped to process the signals to determine the most appropriate wavelengths for low-power sensing and find new potential data in the signals. Our holy-grail would be HbA1C detection for diabetes, but other metrics such as carbon monoxide inhalation, hydration and breathing rate are also possible.
PPG sensors work by shining light at or through tissue and measuring the light absorbed over time to provide a pulse waveform. Pulse oximeters use multiple wavelengths and compare the absorption to calculate an approximate pulse oxygen concentration.
At their simplest, a PPG sensor is an LED and a photodiode, with a mechanism to block light from travelling directly from the LED to the photodiode.
Revision 1: STM32F303
For our first hardware, we designed a small circuit board that housed 16 wavelengths of LED between 470nm and 1650nm and four photodiodes to cover the ranges efficiently.
We selected the STM32F303 because we find the tooling and documentation around STM microcontrollers to be very clear, simple and compatible with Linux. It was also well supported by libopencm3, which is our preferred library.
Additionally, the STM32F303 supports OPAMPs, which allowed us to use an additional amplification stage, which was a good way to de-risk our trans-impedance amplifier (TIA) design. These were not supported by libopencm3, but were well documented in the datasheets, so we made a patch here >>
We were fortunate that our TIA design gave reasonable ranges, but the on-chip OPAMPs still allowed us to zoom in reasonably on the signal.
The design worked well, and with sufficient oversample (typically 512), we could read a strong pulse signal. Oversampling limits were ultimately limited by the CPU frequency, as oversampling for each ADC channel was done in software.
Revision 2: STM32G474
We were pleased with the original design, but we wanted to improve on it significantly. Somewhat optimistically, we wanted to achieve a few orders of magnitude improvement in signal-strength and reduce the board’s size at the same time and for a similar cost.
OPAMPs: Offset & Scaling
The OPAMPs on the STM32G4 series offer an interesting feature; they allow the DAC output to be used as a DC offset for the incoming signal. Since most of our data is a small signal riding on a high DC offset, this feature allows us to scale the ADC values within the correct range. While this added an additional calibration stage, this feature alone allowed us to produce visible heartbeats without any oversampling required.
The improvement in signal quality varies per wavelength of light, but a reasonable estimation for the improvement of signal quality is between 4-64x.
Hardware Oversampling & Clock Frequency
The ADC's on STM32G4 provide hardware oversampling. While this is not a unique feature among microcontrollers, it significantly reduced our CPU overhead since we could get hardware oversample by 16x without any loss of accuracy and reduce the software oversample used by the same factor. Combined with the fact that the STM32G4 supports 170MHz compared to the 72MHz of the original, these features reduced CPU usage by a factor of 38.
In our first revision, we needed a large diode to ensure that the VDDA pin never provided more than 0.4V more in voltage than the VDD.
The STM32G4 separated VDDA from VREF and moved some potentially noisy components like the PLL out of the analogue domain, which provided an opportunity for the reduced component count and noise.
Our second revision has a dedicated voltage reference for the TIAs and analogue voltage reference and can power the analogue domain by simply filtering the main supply. This both simplified the board and offered the opportunity to reduce noise further.
Library Support While STM32G4 hardware provided numerous improvements, it was not yet supported by our favoured libopencm3 library, so we needed to contribute a patch series for it here >>
The patches required for STM32G4 were fairly significant, but the documentation was accurate, and most peripherals were backwards compatible.
In addition to the improvements provided by the MCU upgrade, we also refined the LED voltages and TIA resistors based on results from our initial testing, which in some cases provided a signal strength improvement of more than 4x.
The board size was reduced by about 1cm in each dimension.
We achieved a significant improvement in signal quality which allowed us to achieve a feat we'd considered a long-shot: We could record pulses at audio frequencies (48kHz+) with full resolution (16-bit).
This chart shows the improvements between revision 1 and revision 2. Both hardware revisions have the same photodiode and LED parts. With a 250Hz acquisition, overall accuracy was increased by 192 times when picking up a pulse from a reflection of 528nm green light and 124 times for 590nm orange light. For both revisions, acquisition configuration parameters were chosen to maximise the signal's strength up to the hardware's limits, including the use of software oversampling.
Not only could revision 2 record pulses at very high resolution and frequency, but it could also directly record audio from vibrating objects.
Bang in a table recorded using Bloodlight
Music recorded using Bloodlight
Source & Contributions
Our project is fully open-source, so please feel free to download, copy and contribute to both the hardware and software for this project.
Related blog posts:
- More about Bloodlight: Bloodlight: A Medical PPG Testbed >>
- Improving the medical industry: The Case For Open Source Software In The Medical Industry >>
- Tracking Players at the Edge: An Overview
- What is Remote Asset API?
- Running a devroom: FOSDEM 2021 Safety and Open Source
- Meet the codethings: Understanding BuildGrid and BuildBox with Beth White
- Streamlining Terraform configuration with Jsonnet
- Making the tech industry more inclusive for women
- Bloodlight Case Design: Lessons Learned
- Safety is a system property, not a software property
- RISC-V: Codethink's first research about the open instruction set
- Meet the Codethings: Safety-critical systems and the benefits of STPA with Shaun Mooney
- Why Project Managers are essential in an effective software consultancy
- FOSDEM 2021: Devroom for Safety and Open Source
- Meet the Codethings: Ben Dooks talks about Linux kernel and RISC-V
- Here we go 2021: 4 open source events for software engineers and project leaders
- Xmas Greetings from Codethink
- Call for Papers: FOSDEM 2021 Dev Room Safety and Open Source Software
- Building the abseil-hello Bazel project for a different architecture using a dynamically generated toolchain
- Advent of Code: programming puzzle challenges
- Improving performance on Interrogizer with the stm32
- Introducing Interrogizer: providing affordable troubleshooting
- Improving software security through input validation
- More time on top: My latest work improving Topplot
- Cycling around the world
- Orchestrating applications by (ab)using Ansible's Network XML Parser
- My experience of the MIT STAMP workshop 2020
- Red Hat announces new Flatpak Runtime for RHEL
- How to keep your staff healthy in lockdown
- Bloodlight: A Medical PPG Testbed
- Bringing Lorry into the 2020s
- How to use Tracecompass to analyse kernel traces from LTTng
- Fixing Rust's test suite on RISC-V
- The challenges behind electric vehicle infrastructure
- Investigating kernel user-space access
- Consuming BuildStream projects in Bazel: the bazelize plugin
- Improving RISC-V Linux support in Rust
- Creating a Build toolkit using the Remote Execution API
- Trusting software in a pandemic
- The Case For Open Source Software In The Medical Industry
- My experiences moving to remote working
- Impact of COVID-19 on the Medical Devices Industry
- COVID-19 (Coronavirus) and Codethink
- Codethink develops Open Source drivers for Microsoft Azure Sphere MediaTek MT3620
- Codethink partners with Wirepas
- Testing Bazel's Remote Execution API
- Passing the age of retirement: our work with Fortran and its compilers
- Sharing technical knowledge at Codethink
- Using the REAPI for Distributed Builds
- An Introduction to Remote Execution and Distributed Builds
- Gluing hardware and software: Board Support Packages (BSPs)
- Engineering's jack of all trades: an intro to FPGAs
- Bust out your pendrives: Debian 10 is out!
- Why you should attend local open source meet-ups
- Acceptance, strife, and progress in the LGBTIQ+ and open source communities
- Codethink helps York Instruments to deliver world-beating medical brain-scanner
- Codethink open sources part of staff onboarding - 'How To Git Going In FOSS'
- Getting into open source
- How to put GitOps to work for your software delivery
- Open Source Safety Requirements Analysis for Autonomous Vehicles based on STPA
- Codethink engineers develop custom debug solution for customer project
- Codethink contributes to CIP Super Long Term Kernel maintenance
- Codethink creates custom USB 3 switch to support customer's CI/CD pipeline requirements
- Codethink unlocks data analysis potential for British Cycling
- MIT Doctor delivers Manchester masterclass on innovative safety methodology
- Balance for Better: Women in Technology Codethink Interviews
- Introducing BuildGrid
- Configuring Linux to stabilise latency
- GUADEC 2018 Talks
- Hypervisor Not Required
- Full archive