Bluetooth 100kHz+ Two-channel Function Generator

Introduction: Bluetooth 100kHz+ Two-channel Function Generator

I wanted to have a two-channel function generator that goes above audio frequencies.

I was inspired by this xmega-based waveform generator Instructable. But instead of using an xmega development board, I used the handy little Brainlink. That's a device with an atxmega 16a4, a Bluetooth adapter, a USB-rechargeable battery, various sensors, and a firmware designed for easy Bluetooth control, all in a cute package. They are sadly discontinued, but can bought for $39 at SurplusShed which is the cost of the parts (and SurplusShed has occasional sales that go up to 50% off all stock).

To get a two-channel function generator that I could control over Bluetooth from my phone, all I had to do was to extend the Brainlink's firmware to add a waveform generator function, and then to write a simple Android app that communicates over Bluetooth with the Brainlink.

Now that this is done, all you need to do is to install the firmware with my Android-based firmware uploader which sends the new firmware (which is backwards compatible) via Bluetooth to the Brainlink, and then use my Android app that controls the function generator. All source code is here.


  • Brainlink
  • Tether for Brainlink's 8-pin port (included with Brainlink, but I recommend buying extra 8-pin 1.25mm pin spacing JST cables on ebay)
  • Android device (theoretically any Bluetooth-enabled device will work with your own software, and you can just control the Brainlink directly with Realterm)
  • Optional: Capacitor(s) for bipolar mode (I used 0.1 microFarad)

The Brainlink, of course, remains fully usable for other purposes (e.g., this or this) when you're not using it as a signal generator.

Gratitude: While I have no affiliation with Birdbrain Technologies, the maker of the Brainlink, Tom Lauwers of Birdbrain was pleased to see my earlier firmware developments and very kindly gifted me three more Brainlinks.

Teacher Notes

Teachers! Did you use this instructable in your classroom?
Add a Teacher Note to share how you incorporated it into your lesson.

Step 1: Upgrade Brainlink Firmware

The updated firmware for the Brainlink with waveform generator is backwards compatible, but also adds some new features (e.g., Roomba bridge support) and fixes a nasty buffer overflow bug.

The easiest way to update the firmware over Bluetooth is from an Android phone or tablet. Just:

  1. make sure your Brainlink is fully charged
  2. download my firmware update app from Google Play
  3. pair your Android device with Brainlink (PIN 1234)
  4. turn off the Brainlink
  5. connect pins 2 and 8 (numbered from right to left; see photo) on the Brainlink's 8-pin port
  6. turn on Brainlink while keeping pins connected (blue firmware update light should turn on)
  7. run Brainlink Firmware Uploader on your Android device
  8. choose your Brainlink device (typically shows up as RN42-xxxx) and whether you want firmware optimized for connecting to a Roomba 500+ or for one of the older Roomba 400 / Create robots
  9. tap on "Program device"

Before the last step, you might also want to increase the Bluetooth connectivity setting in the Uploader. This sets the Brainlink's Bluetooth module to higher connectivity, making it easier to connect to it in the future (you do lose some battery life).

Step 2: Use Waveform Generator Via Android Device

  1. Install Brainlink Wave Generator on your Android device.
  2. If you're using a different Android device from the previous step, pair your Brainlink with it.
  3. Make sure Brainlink is turned on.
  4. Plug tether into the 8-pin port on the Brainlink, making sure no wires short together. (If you use this configuration a lot, you might make a modified tether where the lines irrelevant to the function generator are cut off.)
  5. Use Ohm's Law to ensure that the current draw at the voltages you want to generate won't exceed 20mA, as the Brainlink's pins are rated only for 20mA. For instance, if you're connecting to a 50 ohm load, make sure no voltage exceeds V=IR=(0.020)(50)=1v. If you're connecting to a 1 mega-ohm oscilloscope, no worries.
  6. Set the settings for channel 1 or channel 2 and press the right Play button.
  7. The waveform generator output will come from the pins marked in the photo. (On the original 8-pin tether, the CH1 and CH2 pins are blue, and the GND pin is black.)

The sine/square/triangle wave function requires an amplitude between 0 and 3.3v (with 254 steps in between). See step 5 for a warning. The square wave generator requires choosing duty cycle (percentage between 0 and 100). The arbitrary wave generator function requires a sequence of voltages, which whole sequence is played at the indicated frequency.

Limitations: The xmega is limited to 1.0 MS/s in single-channel mode and 0.67 MS/s in dual-channel mode. This means that the theoretical maximum for a single-channel square wave is 500 kHz. In practice, about 320 kHz is the highest I'd go for a single-channel square wave, and "square" is a bit of an overstatement (see picture). For sine waves, rather lower frequency is better. Even at 100 kHz, a sine wave doesn't look great, given how few samples it has per period. My experiments suggest that generally dual-channel operation is best at 100 kHz and below.

Step 3: Optional: Bipolar Waveform Generator

The xmega in the Brainlink has a unipolar Digital to Analog Converter (DAC). This means that it generates a voltage between 0 and 3.3v. If you want to generate a bipolar wave, say between -0.5v and +0.5v (e.g., for audio use), you need to pass the output through a capacitor. A 0.1 microfarad one worked perfectly for me. Note that if you use the capacitor, then the voltage you specify in the app will become the peak-to-peak voltage. Thus, if in the app you specify a symmetric wave of 1v amplitude, you'll get a bipolar wave ranging from -0.5v to +0.5v.

Step 4: Optional: Control From Other Devices

The custom Brainlink firmware adds three new functions. To access them, first enter Brainlink command mode by sending an ASCII '*' (outside of command mode, the Brainlink emits a repeating 'BL' sequence).

To play a sine, triangle or square wave, use the 'w' function. Just send a w followed by (with less than a second in between characters) seven bytes:

  • byte 1: channel, either ASCII '0' or ASCII '1'
  • byte 2: type, either ASCII 's' (sine), 't' (triangle) or 'q' (square)
  • byte 3: duty, between 0x00 and 0x3F; only matters for square waves and is otherwise ignored; however, I recommend setting it to 0x20 for other waves in case I want to use it to describe sawtooth waves in the future
  • byte 4: amplitude, between 0x00 (=0v) and 0xFF (=3.3v)
  • bytes 5-7: frequency in Hz, 24-bit number, most significant byte first

To play an arbitrary wave, use the 'W' function. Just send a W followed by (with less than a second in between characters) 5+n bytes:

  • byte 1: channel, either ASCII '0' or ASCII '1'
  • bytes 2-4: frequency in Hz, 24-bit number, most significant byte first
  • byte 5: number n of data points (between 1 and 0x40)
  • bytes 6 through 6+n-1: amplitudes, between 0x00 (=0v) and 0xFF (=3.3v)

To stop playback, send ASCII '@' followed by the channel (ASCII '0' or '1').

Note that the first wave channel ('0') cannot be used simultaneously with the Brainlink buzzer (buzzer will turn the channel off, and vice versa) and the second wave channel ('1') cannot be used simultaneously with the Brainlink IR emitter (IR turns off the wave channel and vice versa).

Microcontroller Contest

Participated in the
Microcontroller Contest

Tech Contest

Participated in the
Tech Contest

Remix Contest

Participated in the
Remix Contest

Be the First to Share


    • Finish It Already Speed Challenge

      Finish It Already Speed Challenge
    • Arduino Contest 2020

      Arduino Contest 2020
    • First Time Author Contest

      First Time Author Contest

    7 Discussions

    Ok, I recant my previous statements. I went ahead and tested the setup and it absolutely works. Learn something new every day!


    Reply 5 years ago

    Glad to hear!
    I don't know much about electronics theory, but it sure works for me. My oscilloscope images have offset at 0v which makes the middle lines of each waveform be ground.


    Reply 5 years ago on Introduction

    I went ahead and conducted some further testing just to put my mind at ease. The main issue you will encounter with this approach is that you will see a bit of phase change AND you might see amplitude loss at lower frequencies. If you will be working only in a tight, high frequency band then you should be ok with this cap approach. If you dip down to lower frequencies like 0-50 Hz you will see amplitude loss, and if you attempt to compensate for this with a higher capacitance you start to shift the bias of the output signal. All of this made sense after I sat and thought about the fundamental performance of capacitors. Thanks for putting this out there and expanding my mind :-)

    I did look at the screenshots, without scale those images don't mean anything. Also there is no indication of the ground reference in those readings.


    5 years ago on Step 3

    Call me crazy... but I don't think this actually works. Passing a unipolar waveform through a capacitor should only affect the phase.


    Reply 5 years ago

    Have a look at the oscilloscope screenshots in step 3. Sure seems to work.