12. Arduino Code Overview

Introduction and Apology

This article describes the Arduino code that interfaces to the ADAU1701 DSP.  It can be used for a variety of active speaker designs, and it can control a wide range of hardware, from the miniDSP board to the freeDSP board, to the custom designs that are documented on other pages on this web site.  This code provides a local graphical user interface, and it can be controlled using an Android application via Bluetooth. It can also interface to a PC application that provides low-level control such as sending the data to biquads in the DSP at the register level.

This code has evolved over many years.  The initial versions were written in assembly code for a 6801-series microcontroller that had 2K of flash memory and 256 bytes of RAM.  Given those constraints, the code was optimized for efficient execution rather than for reuse, portability and readability.  Those early designs controlled the TAS3004 DSP and the DSP resources inside the STA326 and STA308a amplifiers.  As the microcontrollers evolved, the code grew and gained more features, but some of the core routines, including the command interpreter and menu system, remained the same for many years.  All of this code has now been transitioned to C++, using the Arduino IDE for development.  However, the code still has vestiges of that assembly-code heritage, and that will remain the case until a major refactoring effort can be done.  And until that refactoring is done, the code will not be released as “open source”.  So if you are expecting to download the source code or a set of libraries that you can modify for your own needs, you may have a wait.  But on the other hand, the executable code works, it is a free download, and the interfaces are well documented, so you probably won’t have a compelling need to change this code, anyway.

It’s important to keep in mind that the Arduino code is just one part of the overall software that we need for designing these active speakers.  The Arduino code loads the ADAU1701 and provides real-time control of the DSP, by changing the DSP Parameter RAM while the DSP is running. It also provides an interface to other devices such as PC applications, LCD displays, or cell phone applications. But we also need to develop the code that gets loaded into the ADAU1701 DSP chip. This code is developed using the Analog Devices SigmaStudio tool, and we need some utilities to transfer this compiled DSP code to the Arduino CPU. Another type of software we need is code that runs in the cell phone app or on a “smart” LCD display such as the Nextion devices from ITEAD. This software provides the buttons and sliders and other controls that send messages to the Arduino CPU. The final type of software is loudspeaker design software running in a PC or other “heavy” client that lets the user read driver measurement files, and interactively design a multiway active loudspeaker system using the interfaces provided by the Arduino code.

Overview

The Arduino software can be viewed as a shell around the ADAU1701 DSP. The block diagram below, with the concentric circles, shows the various layers of software that surround the ADAU1701.

In the center are the library routines for the I2C interface. I2C is a two-wire communications protocol that allows changing the registers and internal memory of the ADAU1701. However, the “stock” Arduino Wire library routines are designed for relatively simple devices that use 8-bit addresses and single bytes of data. The ADAU1701 uses 16-bit addresses and sub-addresses to access all the resources, so we need a communications layer that extends the standard I2C protocol to work with the ADAU1701. That layer is shown in white on the block diagram.

Outside of that I2C Extensions layer is the DSP and Control layer (dark blue), which provides routines for controlling the DSP and provides some DSP processing. This control layer includes program loading, “safeloads” to update the ADAU1701 without causing the filters to be unstable, and routines to update volume controls and delay and other DSP functions that were designed using the SigmaStudio tool. The control functions also include the ability to read back ADAU1701 memory locations and to mute and unmute the device.

This DSP and Control layer also assigns biquad filters to crossovers and calculates the coefficients for the biquads using the Bilinear Transform. The Bilinear Transform equations are well documented in several “DSP cookbook” publications and DSP application notes, and we won’t delve into them in this project write-up. However, it’s worth noting that they require the Arduino to perform floating point computations, and for that reason it helps to use one of the faster Arduino CPUs for this project. The small 8-bit Arduino boards can do these calculations, but there is a noticeable delay due to the time it takes to perform the calculations.

Interfaces

The next layer outside of the DSP and Control is a set of three different interfaces. All these interfaces are operational, and they show how this project has evolved in the last two years.  The diagram labelled “User Input” shows these interfaces in more detail, with the associated logic for responding to the inputs.

The interface at the top of the concentric circle diagram, labelled “GUI Interface”, and colored light green, is the “original” external interface. That interface requires a “heavy” desktop client that manages the DSP and Control functions. The GUI Interface provides extensive control flexibility, as you can use this interface to directly write to memory and registers inside the ADAU1701. However, the GUI Interface is also responsible for assigning biquads, calculating the biquad coefficients, and even getting the data into the ADAU1701 in the correct order. So, the “price” of the increase flexibility is much greater complexity in the client.  The diagram labeled “Update HW from GUI” shows the Arduino logic used to implement this interface.

The next interface that evolved is the menu system for a local LCD display. This menu system is table-driven and can accommodate many different LCD’s, pushbuttons and an IR remote control. The menu uses up/down buttons to go from field to field and left/right buttons to select options within each field. The menu supports multiple pages, where going past the last field on the page will display the next page with different fields. The menu system includes provisions to locate fields anywhere on the page, and the tables have the captions for each option. The menu table and menu options are depicted in the diagram labelled “HCI Menu Pages (for LCD)”.

A recent implementation of this menu system uses the Nextion touch-screen displays. These displays come with some nice tools for designing buttons and sliders and using images as backgrounds. The Nextion tools compile the local touchscreen code into a file that can be copied to an SD card, and the display includes a card reader for loading the code. This project will not address the details of designing with the Nextion display, but later in this article there is a link for downloading code to an SD card, as well as a link for the project file that can be used to modify the display. The logic for executing the functions available in the menu system are shown in the diagram labeled “Update HW from Menu”.

The final interface shown in the following two block diagrams is the Bluetooth/WiFi serial interface. This interface still uses the menu system, but allows using simple character string messages to navigate the menu options. Most messages are 5 characters long, using a Command-Subcommand-Value format. These commands are summarized in the diagram labelled “Serial Commands (BT/WiFi)”. An important feature of this interface is that the menu state is stored in the Arduino, in the EEPROM memory. After every page load, the EEPROM is updated, and whenever the client needs to refresh the page, it simply needs to request the values for each field from the Arduino. That means the Bluetooth client doesn’t need to keep track of the state of the DSP. It also doesn’t need to “understand” the menu values, as the Arduino provides the character strings for updating the textboxes or buttons on the display.  The diagram labelled “Serial Commands” summarizes the commands available using the serial interface.  The diagram that follows, labelled “More Serial Commands” was recently added to provide bass enhancement and custom filters that can be used to tweak the loudspeaker response.

The SigmaStudio Program

It’s not necessary to use SigmaStudio for this project, because a useful program has already been designed and is included in the Arduino code. But it’s worthwhile understanding what that program does and how that program ended up in the Arduino code.

The SigmaStudio program used for this project is shown in the diagram labelled “SigmaStudio Program”. It’s probably impossible to read the fine print, but we can just look at the shape of the blocks and get a good idea of what’s going on. If you want to read that fine print, go the Audiodevelopers.com web site and read the article titled “ADAU1701 and SigmaStudio”. There is a link to download the SigmaStudio program, and you can download the SigmaStudio program from the Analog.com web site. Open the program and you will be able to see all the details.

 

On the left side of the diagram, there is a stereo selector cell and a master volume control. From the volume control, the signal goes to a row of 12 biquad filters. Each biquad filter can be programmed as a high-pass, low pass, 2-pole high-pass, 2-pole lowpass, bandpass, peaking, shelf or all-pass filter, just by setting up the right parameters for each biquad. For this project, 9 of those 12 biquads are used as peaking filters with a “Q” of .7, and one of the biquads is dedicated to baffle step compensation. The other two filters aren’t currently used, and are available for future applications. Each of these biquad filters is a double precision stereo biquad—both left and right channels are affected the same way.

After traveling through those 12 biquads, the signals go to a routing matrix that allows passing left, right or both channels to any of those biquads in the middle of the diagram. The current version of this project doesn’t provide a user interface for that channel routing, but it could be added quite easily. After the routing, the signals go to 6 channels of biquads: 3 for the left and 3 for the right. Each channel has 8 biquads, which is enough for implementing 8-pole Linkwitz-Riley crossovers. The crossover between the sub and woofer is limited to 4-poles, which means not all the biquads are allocated. In fact, there are 3 unallocated biquads for the tweeters, 2 unallocated biquads for the woofer, and 3 unallocated biquads for the subwoofer channel. These unallocated biquads are available for adding additional response tailoring, subwoofer bass enhancement, or other features that currently aren’t available from the user interface.

After the 6 channels of biquads, the signal goes through delay cells, followed by individual channel volume controls. Even with all these biquads, the program is only using about 2/3 of the available clock cycles each sample period. So, if we needed to add more DSP processing, such as compression or additional filtering, the ADAU1701 still has enough resources available.

It should be noted that the ADAU1701 is an 8-channel device, even though there are only 4 digital-to-analog (DAC) convertors on the chip. The other outputs are available on a I2S port, and the DSP board we are using routes the I2S signal to an additional stereo DAC. As a result, we can use the Act 2 DSP board as a stereo 3-way crossover.

The block in the lower right corner just before the volume controls is the Analog Devices SuperBass algorithm.  This block implements a psychoacoustic bass enhancement that uses the addition of harmonic content to create the impression of deeper bass, while minimizing cone travel.  And it works!  It is not something that you would want to use for all types of music, but on some material the effect is quite impressive–much deeper-sounding bass from a small woofer.

After creating this program in SigmaStudio, we simply compile it and export the design files. The data in these files is not in the right format for the Arduino IDE, so we use some utilities that are available in the Active Speaker Designer (ASD) program. The ASD program reads the SigmaStudio compiler output and creates files for the Arduino IDE, as shown conceptually in the diagram labelled “SigmaStudio Interface”. As already noted, this work has been done, and the ASD-created files for this SigmaStudio design are part of the Arduino program. But if you want to add new DSP functions, you will need to rework the design with SigmaStudio, use the ASD utilities, and then copy those files into the Arduino sketch folder.  The diagram labelled “SigmaStudio Interface” summarizes that flow.

Initialization

The Arduino code is also responsible for some additional “housekeeping” at power-up.  It needs to reserve memory, define constants, set up memory structures, and initialize the CPU subsystems, including the I2C logic, the serial ports, and I/O pins.  Then it needs to populate the menu system tables, initialize the menu system state, and write the menu data to the displays.  When those housekeeping tasks are done, the CPU loads the ADAU1701 memory and issues it a soft reset to start the ADAU1701 code.  This flow is summarized in the diagram labelled “Initialization”

Loading the Software

As noted in the Introduction, this code is currently not designed in a way that supports source code sharing, and as a result the source code isn’t available for download.  However, the compiled code is available and you can download it into your Arduino CPU and it will run.  For now, the hardware must be the teensy3.2 Arduino board, and you must download the code that is specific to your hardware. The compiled code is a .hex file available at the Audiodevelopers download page. You will need a tool such as the TyCommander tool, available at http://neodd.com/tytools/ to upload the .hex file to the teensy3.2. And that’s it—the CPU will reset and all the code described in this write-up will be working, ready to process your audio.

If you are going to use the Nextion display, the file you need is at: http://www.audiodevelopers.com/Software/Nextion/Act_4/Rev01.tft.  Put this file on a microSD card, plug the card into the Nextion card reader, and then cycle power on the display. When power comes back up, the Nextion will load the code into internal flash memory. Reset the Nextion again and the display code will be running. You might find it useful to buy one of those USB to microSD card adapters—Bestbuy has an Insignia brand that is around $15.

If you are going to use the Android app, you can find the app by searching for “Audiodevelopers” on the Gallery at the MIT App Inventor web site: http://ai2.appinventor.mit.edu. Since the App Inventor tools started as a Google-funded effort, you will need to use Chrome to build the code. Select “Build”, then “provide QR code”, and wait for the QR code to appear. Scan the QR code and you will be directed to the server site that has the built code. Install that code on your phone and then look for a Bluetooth device that is named Audiodevelopers1.

With the App Inventor application, you will be able to customize the cell phone app—change colors, move things around, etc. Unfortunately, the App Inventor has a serious limitation with the Bluetooth implementation, in that you can’t use multiple screens (every time you change screens it drops the Bluetooth connection). The app uses “virtual” screens to get around that limitation, and it makes the code rather cumbersome. But hopefully the DIY community will come up with some better cell phone clients that are easier to customize.

What’s Next

I think one of the definitions of software is “the stuff that’s never finished”.  There are always those final features you leave until later, and there are always things you want to go back and re-do.  Right now the big items that still aren’t done are the bass enhancement features and the input switching/signal-routing.  And there are a number of routines that I very much want to rewrite to be more modular and more compact.  There is lots of “software sprawl” to work on.  But the real challenge with software is that about the time you need to finish and clean-up, you start seeing all of these new things you want to try, and you get the itch to move on.  I’m at that point.  But maybe by documenting some of these new directions, I’ll be able to keep working on this code to get it done and in better shape.  So the list below is my wish-list or maybe a look into where this code will be in another year.

 

IP control vs Bluetooth

The Bluetooth control is a novelty, but it’s not entirely practical.  Bluetooth is designed for point to point connections, and with left and right speakers you can only address only one channel at a time.  So IP control makes more sense as a final solution, and IP control can still use cell phone clients.  So, IP control, using a simple WiFi-to-serial-adapter, is a good next step.

Improved cell phone client.

The cell phone client actually works OK, but it was done using App Inventor, which has some major limitations.  First, it only runs on Android.  That’s not a crippling deficiency, given the availability of low-cost Android devices, but it would be nice to have support for IOS and Windows-based web clients as well.  But secondly, and much more importantly, App Inventor is “weird”.  App Inventor was designed for learning, and it is an interesting graphical approach that is being used to introduce school kids to programming.  It’s somewhat fun to play with, but the simple graphical approach gets cumbersome as the program size increases, and the graphical editing tools start to feel “annoying” when you want to re-arrange the code or do simple cut and paste operations.  But third, App Inventor has some serious limitations for this type of code.  For example, the tools allow having multiple screens, which are important for this type of user interface, but whenever you switch screens the Bluetooth connection gets dropped.  There is a lot of documentation on this limitation, and there is a work-around using “virtual” screens, but the result is clumsy and it generates lots of confusing code.

So, it would be nice to have a cell phone client for controlling the DSP that runs on Android, IOS, or from a web browser, using IP connectivity.  This would be a very nice challenge for someone, and there is enough information in this article to implement the interface.  Send me an email if you need more information.

Migration to off-the-shelf hardware

The biggest challenge in the projects described in these pages is that there aren’t too many good options for the DSP board described in Case Study #2:  the stereo 3-way.  The board really isn’t that hard to build if you have the right tools, but soldering SMD parts just doesn’t appeal to a wide audience.  Sure Electronics has released a number of products using the ADAU1701, and the JAB3 amps look great for implementing low-cost 2-way systems (an article on using the JAB3 will be posted soon in the Parts Express Project Pages).  However, there still isn’t an off-the-shelf stereo 3-way solution, and we’ll just have to wait for that to arrive.  In the meantime, you’ll probably want to ask Santa for an SMD rework station this Christmas.

Customized menus

The menu system used for this Arduino project has tables to look up pre-selected crossover frequencies or EQ frequencies, but the DSP code that calculates the biquad coefficients can use any frequency you specify.  By providing a way to customize the menu tables, or by adding a command to specify the frequency, you could have filters at any frequency or quality factor.  The hardest part of extending the menu system to allow downloadable menu tables would be dealing with the added complexity in the  user interface.  It wouldn’t be hard to implement this feature, but obviously, it’s worthwhile seeing whether there is a need for this capability before doing the work.

EQ from measurement data

The GUI interface, along with the Active Speaker Designer application, is probably the best way to use measurement data to optimize the loudspeaker design.  However, there are a number of cell phone applications that take frequency measurements, and it would be possible to implement an auto-EQ algorithm in the cell phone software that would  calculate the needed corrections using biquad filters.  The existing EQ filters could be used, or new ones added using SigmaStudio that could be programmed from the phone.

ADUA1452

The ADAU1452 chip has about 6 times the capability of the ADAU1701, and with the higher clock rates and larger program memory it is possible to implement large FIR filters that simplify equalization calculations.  There is a two-board set using the ADAU1452 available from a low-cost overseas vendor that looks promising.

WiFi Module Software

The Dayton WiFi module is made by Linkplay, and Linkplay has a development kit that allows extending the software in the CPU that is in the WiFi module.  There is a voice recognition capability that uses the Alexa tookit from Amazon, but there are other capabilities that are worth exploring.  It would be a nice convenience to be able to forward the commands from the left or right channel to the other, so that the client wouldn’t need to send out commands to two different IP addresses.  And being able to establish a master/slave relationship by reading the status of a switch on the back of the speaker could be very useful.  These possibilities haven’t been investigated, and it will probably require approaching Linkplay as a developer to get the information, but it is worthwhile keeping these ideas on the roadmap.  Also, recently PE started selling two of the Linkplay modules at a very reasonable price, so another possibility is a stereo 3-way board with embedded WiFi audio.