Tuesday, November 29, 2016

Teensy Audio Board Headphone Level

For my home-brew Teensy Hearing Aid, I'm using the Teensy Audio Board as my audio interface.  The heart of the Teensy Audio Board is the Freescale SGTL5000 stereo codec.  This codec is very flexible, with lots of virtual knobs for tuning your system to suit your own application.  For my hearing aid, it is important for me to understand all settings related to loudness.  So, today, I'm going to look at the impact of the headphone volume control.

System Block Diagram:  The figure above is taken from the datasheet for the SGTL5000.  All of the blocks in yellow  are analog gain stages.  The headphone volume control is at the end of the chain, on the upper right.  It says that the headphone volume can be adjusted from -52 dB to +12 dB.

Teensy Audio Library:  Because this SGTL5000 is embedded within the Teensy Audio Board, I control it via the Teensy Audio Library.  The library hides many of the details of controlling the SGTL5000.  For example, it allows the user to control the headphone volume simply by commanding a value somewhere between 0.0 and 1.0.  Presumably, 0.0 maps to the -52 dB setting and 1.0 maps to the +12 dB setting.

Measuring the Response:  To see what this means for my system, I wrote a sketch for the Teensy that uses the Teensy Audio Library to continuously generate a nearly full-scale sine wave and to output it via the headphone jack (code is shared here).  The volume setting for the headphone output is controlled via potentiometer on the Teensy Audio Board.  To see the effect of the headphone volume setting, I measured the RMS voltage produced at the headphone jack using a Fluke handheld digital multi-meter.

Results:  The figure above shows the values that I measured.  As can be seen, the response in the middle section is linear, which is great.  At the low end, my results do deviate from linear, but that's presumably because my multi-meter had difficulty measuring such small signals (-50dBV is only 3.2 mVrms!).

Saturation:  The interesting result happens at the high end of my graph where I turn up the volume control to its highest values.  Here, my results saturate -- increasing the volume command does not increase the output voltage.  The break-over point is at a command of about 0.85.  This corresponds to an output signal level of +1.5 dBV, which is 1.2 Vrms, which is 3.4 Vpk-pk.  Since the power supply to the SGTL5000 is only 3.3V, it is not surprising that the output saturates when I ask for the output signal to be greater than the power rails.

Best Setting to Use:  Saturation will sound bad.  It will cause distortion in the audio.  To keep my hearing aid sounding good, I want to avoid this saturation.  If my full-scale sine wave causes saturation at a volume setting of 0.85, I am going to set my volume to 0.8.

Saturday, November 26, 2016

Reducing Current Draw

My previous post introduced my Teensy-based hearing aid.  While my primary goal was to make a platform for developing audio processing algorithms, I am interested in exploring its performance as an actual hearing assistive device.  From this viewpoint, battery life is important.  In assembling my device, however, I gave no thought to minimizing power consumption.  Does it draw too much current?  Will it have a usable battery life?  Let's find out!

Initial Measurements:  With my baseline Teensy Hearing Aid, I measuring the current being drawn from the battery during normal operation.  At this early stage of development, the Teensy isn't doing very much -- it is simply applying digital gain to the audio stream.  Because it is doing so little, I am hoping that we'll see the lowest power consumption.  My results are below.  Note that I measured the power consumption across a range of processor speeds.  You can set the speed of the processor via the Arduino IDE when you compile the sketch.

That's A Lot of Current!  I was surprised to find that at its normal speed (180 MHz) the system was drawing almost 91 mA of current.  That's a lot of current.  My battery has a capacity of 350 mA-hours, so my battery life will only be about (350 mA-hrs / 91 mA) = 3.8 hours.  For a "hearing aid", this is pretty short.  Yes, I could slow down the processor to reduce my power consumption, but this is an inelegant solution that requires me (the programmer) to ensure that my software will always live happily within the limits of the slower speed.  I'd prefer a more dynamic approach, where the code itself will switch between low-power and high-performance modes as the workload demands.  I don't know how to do that.

Sleep During Idle:  Luckily, I have a friend who is experienced with low power embedded systems.  He suggested that I could save a lot of power by putting the processor to sleep during idle periods.  Knowing that I'm working with an ARM processor (the heart of the Teensy board), he suggested that I insert the ARM-specific command asm(" WFI") into my main loop (yes, you do need the space before the W).  When the processor hits this command, it'll go to sleep and consume less power.  It'll stay asleep and "Wait For Interrupt" (hence "WFI") before waking to resume its work.

Wait for Interrupt:   Since I don't want it to sleep forever, I need to make sure that there is an interrupt (such as a timer) that'll wake the system periodically so that it can do its work.  As I don't know how to do this, I have a problem.  Luckily, I know that the Teensy Audio Library already uses interrupts to do its work.  I know that it fires at least one interrupt every 128 audio samples.  As any interrupt will trigger the WFI to wake up, I don't need to do anything more.  I can just add the WFI command and rely upon the Audio Library to wake the system.  The system will automatically go back and forth between sleep and wake.  One line of code -- what a simple solution.

It Works!  After adding the WFI command (my code is here), I measured the current draw again.  The WFI command works!  At the default speed of 180 MHz, the system now draws only 57 mA, instead of 91 mA as seen before.  That's a 34 mA savings with no impact on system performance.  Fantastic.

Battery Life:  By adding the WFI command, power consumption has dropped to 2/3 of its original value.  My system will now have 50% more battery life.  Using my 350 mA-hr battery, I'll now get 6 hours of life instead of 4 hours.  That's a great improvement for adding just a single line of code.

More Power Savings?  While increasing my battery life by 50% is great, I went back to my friend asking if more savings could be had so easily.  He said that I could save more power, but not nearly as easily.  He said that the next step would be to identify and disable peripherals that I don't need.  But, to do this, I'd have to read through and understand my processor's datasheet, which is not an easy task for a newbie such as myself.  So, for now, I think that I'll be content with the easy savings provided by the WFI command.

For Fellow Nerds...My Raw Data:  For anyone who is really interested, my raw data is in the table below (or here).  It is interesting that, even at very slow processor speeds, I still see power savings when using the WFI command.  Clearly, my "Gain Only" audio processing algorithm requires very little effort from the processor.  That Teensy 3.6 sure is fast!

Sunday, November 20, 2016

A Teensy Hearing Aid

Hearing aids are totally closed devices -- their inner workings are hidden.  Access is limited to only those who work for the hearing aid companies.  But if innovation is to accelerate, we need more ideas iterated more quickly.  We need more people to participate in hearing aid development.  But if the devices are closed, there is no way to try new ideas.  So, let's consider the alternative.  Let's try to build an open-source hearing aid.  Yes, at first, an open-source hearing aid will be absurdly big and ugly.  But, you have to start somewhere.  I'm going to start here: take one Teensy microcontroller, add some supporting electronics, and VOILA! A Teensy Hearing Aid!

Basic Hearing Aid Elements:  While it is unfortunate that they are closed devices, real hearing aids are absolutely amazing pieces of technology.  Their minuscule packages are absolutely stuffed with functionality.  I, though, am going to start more simply.  I will start with some microphones, analog and digital converts, a digital audio processor, some speakers, and a battery.  Once this works, I can always add more features later.

Choosing a Processor:  For me, the biggest challenge is always with the software.  Therefore, I need to choose a digital audio processor that it is easy to program.  For me, that means choosing a processor that can be programmed from the hobbyist-friendly Arduino programming environment.  Within that universe of processors, I've chosen to use the Teensy 3.6 because it's fast and because it has a nice audio processing library to make it even easier to program for audio.

Supporting Elements:  To get audio signals into and out of the processor, the Teensy folks offer an inexpensive Audio Adapter Board that mates directly to the Teensy 3.6.  It has the audio ADC and DAC that I need.  For the microphones, I'm using a pair of mic breakout boards from Adafruit.  For speakers, I'm using whatever headphones or earbuds that I might have on-hand.  Finally, for the battery, I'm using a Li-Po battery and Li-Po charger from Adafruit.

Wiring It Up:  The figure above gives an overview of how everything was connected together.  As you can see, the Audio Board is at the center with everything else connecting to it.  The only tricky part of this setup is connecting the battery and charger into the Teensy system.  As indicated on the Teensy pinout diagram, you have to cut a trace on the backside of the Teensy so that you can insert the battery connections.  Once cut, the Teensy's 5V USB voltage goes to the battery charger and the battery's output goes back to the Teensy's "5V" input pin.  Not too bad.

Initial Software:  While this post is primarily about the hardware, I did write some basic software in order to see if the hardware is working (see my GitHub repo).  I used the Teensy Audio Library to configure the Audio Board to pass the "I2S" inputs (ie, my microphones) to the "I2S" outputs (ie, my headphones).  In between, I wrote a simple routine that applies a user-controllable amount of gain to make things louder.  I use the blue potentiometer on the Audio Board to set the amount of gain.

First Audio:  Of course, the first time that I tried to compile the code, my software didn't work.  Does anyone's code ever work the first time?  After some iteration, I finally got it to compile and upload.  Putting on my headphones, I could hear the audio being picked up by the microphones.  Turning the blue pot, I could control its volume.  Hardware knobs are so satisfying.  My favorite part, though, is being able to use the on-board battery so that I can move around freely.  Very fun.

Limitations:  Sure, my home-brewed "hearing aid" is ridiculously large -- no one (including me) would ever wear this around in everyday life.  But, unlike commercially-available hearing aids, my device is open.  Anyone can modify it to make it better.  Anyone can try out their own audio processing algorithms to try to improve one's hearing.  Will any of us beat the professional hearing aid algorithm designers?  Probably not.  But, for me at least, I will surely learn a lot by trying a few of the standard approaches.  And, I'll get to look really cool sharing pictures of myself with this (not so) Teensy Hearing Aid.  Happy hacking!

Follow-Up:  I measured the power consumption of my Teensy Hearing Aid.  Using the "WFI" command, I found a super-easy way to increase the battery life by 50%.  Wow!  See my post here.

Follow-Up:  I measured how the volume control affects the headphone ouput.  See here.