This blog has been sort of a notebook for me to write down my own learning with Arduino and the TPA boards. Therefore the information presented assumes that the reader’ is learning at a pace equal to mine.

Beginners are overwhelmed with the amount of information here so this post is to help those by outlining the basics of building a controller board for the superb kits produced by Russ and Brian of Twisted Pear Audio. TPA is also developing a controller for their products so this is an alternative to their solution utilizing low cost, and widely available parts. (As of July 2011  April 2013, the TPA controller board in not yet available, so this is the only “ready-to-run” option)

Basically, all modern audio chips have a software interface and they communicate with a micro-controller through a communication protocol called “I2C”. I have chosen the Arduino platform because I am not a programmer and Arduino is geared towards that audience. In addition, the Arduino community provides a lot of help for beginners and non-programmers.

HIFIDUINO is about building a controller that can talk to those audio chips. So far I’ve interfaced to the OPUS DAC with the WM8741 and the Buffalo II boards. But the same platform can be used to interface to other chips such the WM8804 spdif interface and even the brand new TI PCM51x2 DACs with lots and lots of features that are available only through s/w programming.

The controller consists of:

Arduino board

NOTE: if you use Arduino UNO R2, there is a potential bug:

Any official board or clone will work. The current (v.09) code size is about 14K bytes, so even the bottom of the line Arduino will work. All of he following models work: UNO, Dueminalove, Seeeduino v.2.2, NANO and others. I have used the UNO and the Dueminalove. I have even used the Freeduino. If you want to be dead sure that it will work, then purchase the latest official Arduino UNO (R3 or above)

The Freeduino with a companion stationary shield

Rotary encoder

The rotary encoder is used to change volume and settings. In theory, you can use any “quadrature” or “gray code” encoder. However, I find that the preferred characteristics of the encoder are:

  • About 30 cycles per turn. This gives a good “feel” when changing the volume, changing 30 db per revolution -not too fast or too slow
  • Built-switch. The switch is used to change from volume control to DAC settings control. This is not mandatory, you can implement with a separate switch
  • A rotary encoder with “clicks” is preferred because you can feel the clicks when you select the different settings. I tried a rotary encoder without “clicks” and it does not work well because selection of the different settings take advantage of pushing the encoder to activate the switch. Often one you push the switch you can also inadvertently move the encoder. Rotary encoders without detentes (“clicks”) are not recommended.

I use a Panasonic model that has been discontinued, but available from Electronic Goldmine. Other candidates are: Bourns PEC11, BI EN12. The current version of the code (v.09) does not require that you build a debouncing circuit as the debouncing is done in the software (I had used the rotary encoder without hardware debouncing or a long while, but I finally added the debouncing capacitors).

  • More on debouncing: link
  • Here I recommend the “most suitable” rotary encoder: link

LCD display

The code assumes a 20×4 LCD. Any LCD that is compatible with the HD44780 protocol will work with the code: Do a search for “20×4 LCD HD44780” on eBay. The one I purchased is from Sure Electronics. You can also purchase directly from their website: [link]. Nowadays it is available pretty much everywhere. Here is another good source: iTeadStudio

As it turned out, a larger portion of the code is the user interface and it assumes a 20×4 LCD. Thus, if you use a different form-factor LCD (for example a 16×2 LCD, you will have to overhaul a lot of code.

NOTE: if you use Arduino UNO R2, there is a potential bug:

IR receiver and a remote control

The code supports the Apple Aluminum Remote. Any IR receiver should work. However, I would recommend the Vishay TSOP32438 because it is designed for the 38KHz frequency used by the Apple Remote. The 32438 model also provides noise immunity. Additional information: [link]

Here is a good article on “how to choose IR receiver”: [link]

In fact, any one of these would work:






A level converter from 5V to 3.3V for the I2C lines

This part maybe optional. As the I2C inputs of the Buffalo are “supposed to be” 5v tolerant, but the data sheet does not say specifically and I have not determined that to be the case with 100% certainty. (You can easily build it if you do not wish to buy the module)

You can build your own level shifting by following this diagram from this document [link]


I Made my own here: [link]



The best use of this project is for you to experiment with your own choice of components and ideas. You can reuse whatever part of the code you wish (as I have reused code from other contributors. -This is the spirit of open hardware and software of the Arduino community). If you do this you will find that the audio hobby is not just about changing cables, capacitors and power supplies 🙂

However, if you wish to just replicate what I have done, this is what you do:

  • Get familiar with the Arduino development environment. At the minimum you must know how to compile code and upload to an Arduino. The Arduino tutorials listed in the side bar are a good start.
  • Procure the parts above and hook them up according to the different hookup diagrams in this blog. The current code does not require that you build a debouncing circuit for the rotary encoder so you can skip the debouncing circuit
  • Download the latest version of the code from the code tab. Compile and Upload to the Arduino
  • Done!

This is what my controller looks like:

User Interface summary

Here is a very nice summary of an older (v. 09) user interface from マルチチャネルDAC製作記 blog and in particular this post [link]

I have updated the user interface a bit:

Newer versions are a refinement. But the overall user interface is pretty much the same

NOTE: if you use Arduino UNO R2, there is a potential bug:

Arduino UNO R3: 1050-1024-ND [link]


Here is another implementation of the controller with a hand made Arduino “shield” to facilitate connections: LCD, Arduino, shield, rotary encoder and IR receiver.



The shield has the following components:

  • 5V to 3.3 Level translator with external pull up resistors (1.5K ohm) and local 0.1 uF power supply (5 and 3.3V) bypass. This will ensure clean I2C signals. External pull ups may or may not be required. Depends on your environment.
  • Potentiometer for LCD contrast adjustment
  • Potentiometer that adjust the current to the base of a transistor controlling the brightness of the LCD
  • Arduino reset button (since the reset button of the Arduino is covered by the shield)
  • Underneath, I had implemented a debouncing circuit for the rotary encoder. The code does not need the hardware debouncing circuit since it uses s/w debouncing, but it does not hurt.


The external 1.5 Kohm I2C pull up resistors were added afterwards to solve a noisy I2C connection. In most cases, the internal pull-up resistors or the pull-up resistors built-in in the level translator board should be good enough. I had also added power supply bypass capacitors to further clean up the I2C lines.


The h/w debounce circuit was built in accordance to a BOURNS “Signal Conditioning Technical Note” paper [link]. This is not required by the current version of the code because s/w debouncing is used. However, it is always a good idea to reduce spurious interrupts.


Connecting the LCD




Connecting the rotary encoder (with switch)


I find this rotary encoder very good. With solid clicks and good feel. You really need a rotary encoder with “clicks” because it is also used to make adjustment. I had also used an encoder without clicks and as you push the encoder to actuate the switch and make selections, you would also slightly rotate the encoder making inadvertent adjustments.

More info on rotary encoders:

  • More on debouncing: link
  • Here I recommend the “most suitable” rotary encoder: link


Connecting the IR receiver


  1. Michael
    August 30, 2012 at 19:52

    Hi! Great blog just burned the last 2 hours reading your posts.

    Even though I have some experience with Arduinos and a little with DACs (working in a laboratory) I was wondering if you could recommend a easy guide of a full built to get started (including some links where to order stuff).

    Thx in advance


    • BlogGeanDo
      August 30, 2012 at 21:57

      I enjoyed writing the blog 🙂
      The information here tells you what to buy and where…

    • BlogGeanDo
      August 31, 2012 at 06:13

      The software described here works with the buffalo DAC. You can check

  2. Anonymous
    February 8, 2013 at 13:07

    Hi, this is fantastic! Thanks for posting all this. I want to build my own 5v – 3.3v converter and see in the above photo that you have done the same. Can you point me in the right direction to a circuit diagram or list of components etc?

    • BlgGear
      February 8, 2013 at 17:29

      Added info in the post…

  3. f. arhun
    May 27, 2013 at 03:21

    Hi GLT, Your work here is much appreciated as in diyaudio. Thanks a lot!
    I’ve added “the system” to my diyinhk es9018 v.5 DAC. I use sainsmart uno R3 with large 20×4 LCD. Nothing has any frills! I made hifiduino successfully work in a way, only with one problem: the DAC requires reset once hifiduino starts, and each time when something is attempted to be changed (such as volume and other settings) through the remote or rotary encoder. Some basic nut or bolt is loose I suppose!!

    If you have any insight what might be the culprit or which direction should I look will be very helpful.

    Thanks in advance.

    • BlgGear
      May 27, 2013 at 21:57

      Tell me more. What happens right after you power both the DAC and Arduino. Usually you can start them at the same time. If you can externally mute the outputs, you can startup the DAC first and then Arduino. Also, I would recommend having all the wiring as twisted pairs (I2S and I2C) and make sure no wires crosses over the DAC chip

  4. f. arhun
    May 28, 2013 at 02:04

    Thanks for your answer. At the moment I have seperate power supplies for the DAC and Hifiduino unit with seperate switches, but starting them at the same time will not be a problem and eventually it will get the power from DAC psu. The problem with any interaction of Hifiduino with the DAC causing stalling I think may be due to current I2C wiring, which I haven’t tried to perfect it yet. Do you think using pull up resistors on SDA SCL lines will be any help? My DAC is very clean, with all seperate Salas shunt regulators after two stage inline regulation, etc. although everything is still on test setup, with minimized and careful wirings. I’ll try powering up both units at the same time and work on I2C line and I’ll post more info later

    Thanks again.

    F. Arhun

  5. Moltke
    May 31, 2013 at 04:20

    I also made me a small system with a DIYHK PCB. 🙂
    No leveltranslater used, because the DAC’s I2C pins are 5V convertible.

    I use an I2S signal, and I can see the samplerate is changing on the display (Means the system is communicating with the DAC and I’ts running), but I can’t measure any output of the DAC. I use 100 ohms resistors on the output, but I assume I should be able to measure something else than a DC voltage?

    Do I need to remap the DAC different compared to the BII DAC?
    Great page btw.

    • BlgGear
      June 1, 2013 at 17:19

      If you are using the I2S inputs of the diyinhk board, there is nothing to change. How are you measuring? Unless you have an oscilloscope, it is not easy to measure music with a voltmeter…

  6. WT
    June 15, 2013 at 13:47

    I just found your great block. I wonder if your code can be used with Buffalo 32s

    • BlgGear
      June 15, 2013 at 17:20

      I believe it should work as is. Just try it.

  7. wt
    June 17, 2013 at 07:05

    Thanks. Order Arduino board and other parts already. Should be fun.

  8. Wt
    June 18, 2013 at 16:37

    Just finish asambly but can not control the dac. On display board, it show no lock in up right corner. But the system play music as usual. The Buffalo 32s is locked to Mac mini using itune and audirvana plus fine. Could you please guide me to the right direction.

    • BlgGear
      June 18, 2013 at 17:55

      Did you remove the microprocessor in the B32S? only one microprocessor can control the board.

  9. wt
    June 19, 2013 at 03:54

    I did. First time that I connected I have not remove the microprosessor in Buffalo32S and Arduino just freeze, the screen show all white. Then I turn everything off and remove microprocessor in Buffalo32S and connect again, Arduino turn on normal with welcome screen and display response when I turn encoder. I try both open and shut Address pin on buffalo32S with no effect. I have not connect the IR receiver thought.

    • BlgGear
      June 19, 2013 at 07:20

      So the chip is not responding at all. The default address is “open pin”. Ensure the I2C wires are correct. Also need to connect GND between Arduino and DAC. Can you post some photos somewhere?

  10. Wt
    June 20, 2013 at 03:52

    I2c wires are checked. Ground is connect. Let try picture.

  11. Wt
    June 20, 2013 at 03:53

  12. Wt
    June 20, 2013 at 03:58

    I first connect with level converter that I order. But last night I build it my own because I thought the level converter was not function but that was not the case

    • BlgGear
      June 20, 2013 at 04:39

      Can’t see anything that is obviously wrong. Things you can try:
      – Use the older Arduino 1.0 (I have not upgraded the Arduino IDE to the latest one)
      – Try adding pull ups to the I2C. (I have used 1.5K pull ups in noisy environments)
      – Flip the I2C wires
      – See if the I2C lines are indeed connected to the chip (I suppose you have the datasheet)
      – If the Arduino does not freeze, and changing the volume does nothing, then either the Arduino is not communicating or the DAC is not responding – I have never experienced this. Typically if you have noise in the I2C, the Arduino would hang…
      – In theory, there is no difference between any of the Sabre32 DACs. I’ve heard people using it with BII, BIII, Acko, diyinhk and QuangHao DACs
      – Good Luck!

  13. Wt
    June 20, 2013 at 07:30

    It works now!!!. Flip the i2c wire works. May be Buffalo32s have a mistake in printing.
    Thank you so much in helping me figure this out. Really appreciate your help.

    • BlgGear
      June 20, 2013 at 15:07


  14. February 20, 2014 at 21:45

    How does one contact with you about a project I see here.

    This is quite exciting to me –

    HiRes SD Card Player: SDTrans192 v. 3.0

    Thank You,


    • BlgGear
      February 21, 2014 at 01:24

      That project belongs to Mr Bunpei at

  15. sebastian
    August 5, 2014 at 14:58

    If I turn the volume al the way up to 00, without a DAC connected, this value is stored in eprom right? because If I power up the adurino it’s back to 50

    • BlgGear
      August 8, 2014 at 04:22

      This is how the code works. The volume is not remembered. Every time it starts with a default value. The Default value can be changed.
      This is to prevent starting up with a high volume if you were listening to high volume before…

  16. Derek
    August 30, 2014 at 23:43

    Was thinking of using an Adafruit Pro Trinket 3V 12MHz board but they don’t have pins 2 and 7 available. Is it possible to reassign your pin 2 and 7 functions to, say, pins 6 and 13?

  17. Derek
    September 2, 2014 at 18:20

    Have had a look at the code and believe that, although I’m new to this, I can take a stab at altering the pins. Only doubt is, I read a comment saying pins 2 and 3 are interrupts; so if 2 is not available on the Pro Trinket and I have only one interrupt pin, am I sunk?

    Haven’t got all the bits yet but will take a shot at it unless you say it can’t be done with the Pro Trinket. I need a small footprint controller to fit it all in.

    • BlgGear
      September 5, 2014 at 22:54

      I am only using one interrupt. You will have to use that interrupt pin for the rotary encoder.

  18. Derek
    September 6, 2014 at 13:17

    Okay, thanks. Once I get everything I’ll report progress. And thanks for the project.

  19. Derek
    September 17, 2014 at 01:10

    Got it to work with the Adafruit Pro Trinket 3V. Minor alterations to the code for the LCD pin inputs and interrupt. Also, because the Pro Trinket is 3V there’s no need for level converters with the diyinhk K2M. Used an Adafruit quarter-size perma-proto board so it’s a very small footprint.

    Used with an Alix SBC using Voyage MPD and a Class D module to make an ‘all-in-one’ music server/remote controlled volume control/amplifier unit that fits on an 11×16 base – including linear power supplies.

    As it’s the first time I’ve ever used any kind of microcontroller or code I’m grateful for the extensive blog and explanation on the code – much appreciated. I’m old enough to still be amazed by what people will share on these blogs. Tip of the hat to you, sir.

    Only issue so far is that when I first plug it in the volume is really loud until I move the rotary encoder or touch the Apple remote. Will go through the code and blog again as I recall seeing something about muting the DAC on startup. May also just require stopping the music server before powering down so it does not boot with music playing – although that’s not always under our control!

    Thanks for a great project.

    • BlgGear
      September 21, 2014 at 23:45

      The issue is that when the micro-processor is programming the registers (eg setting the volume), the DAC is not ready. If you turn the DAC first, then it will be at full volume. But when the microprocessor starts it is able to program the registers and lower the volume. In the past turning on both the DAC and the microprocessor at the same time (at least with the regular ES9018 DAC), the DAC seems to start just a tiny bit faster than the microprocessor, so that you get loud volume for a fraction of a sec and then the microprocessor sets the volume to the default value.

      The solution for this is not to have any active source during startup.

    • branko
      March 4, 2016 at 17:33

      Hi Derek,
      would you mind to share your code for the pro Trinket?


      • Derek
        March 6, 2016 at 15:32

        Minor changes. Because the ProTrinket 3.3V does not have pins 2 and 7 you simply change the line for the LCD pins from ‘LiquidCrystal lcd(12,11, 10, 9, 8, 7)’ to ‘LiquidCrystal lcd(12, 11, 10, 9, 8, 13)’ and, of course, wire the pin 7 LCD wire to pin 13 on the ProTrinket.

        To take care of the lack of pin 2 on the ProTrinket you change the original line ‘#define ROTPINB 2’ to ‘#define ROTPINB 3’ and wire the rotary encoder pin to the ProTrinket’s D3 instead of the non-existent D2.

        Finally, because the original sketch used D3 as the IR receiver’s input pin you change ‘# define REMOTEPIN 3’ to ‘# define REMOTEPIN 6’ and wire the IR receiver’s output pin to D6 on the ProTrinket. Pretty simple and straightforward.

        Just remember it needs to be the 3.3V version of the ProTrinket to avoid the level changing.

  20. Steve Williams
    November 8, 2014 at 19:51

    Apple Remote only? Some may want to keep it simple. Use an Arduino Nano or the Pro Mini, a MCP42010 digital pot to the Buffalo III (SE) volume input and the IR receiver shown in the Intro section. First, I built the Hifiduino with a LCD then a graphic display. For my second build I liked the simplicity of using the Buffalo’s controller (which worked with DSD using Foobar and up to 384KHz sample rates using the Amanero USB interface) and its built-in volume input, connected to the MCP42010. Works great.

    You can use the Apple Remote code in Hifiduino to receive the IR codes. Decode this up/down, left/right (fast volume change), volume reduction (center) and mute (pause). Increment/decrement a Volume variable (byte) and send it out using Serial Peripheral Interface to the pot.

    // REF: CE-DESIGN.NET and
    // SPI functions were copied from CE-DESIGN.NET
    // getIRkey function and decoding framework is from HIDUINO but ramping is modified
    // and Volume is direct instead of using attenuation as used with the Sabre DAC.

  21. TKilvaer
    February 7, 2015 at 14:42

    Trying to implement your code, but cant get a lock on my source. Using the sidecar to switch between the 1:4 mux and the exa i2s. Should I connect the arduino directly to the sidecar to make this work (i this supporter by the code?)? or should I remove the sidecar and mux and try to hardwire the inputs?

    • BlgGear
      February 7, 2015 at 17:23

      There is no code to support the side car. Try hardwire first and work from there.

      • TKilvaer
        February 7, 2015 at 19:27

        Thougth so. Just had to ask before i cut the sidecar off. Second-hand Buffalo and was stuck right on the board with silver solder. Works now though.

  22. Rodrick
    September 12, 2015 at 17:11

    Hi, very interesting post! Do you have any suggestions for the filters included in the Opus DAC WM8741? And did you try a direct DSD aplication with the Opus and the arduino in control? Thanks!

  23. Rodrick
    March 13, 2016 at 21:03


    I have doubts about my configuration. Maybe someone can help me here:

    I have a dual mono configuration Opus DAC and I want to use I2C with an Arduino Uno R2 to control the two dacs with the same input from arduino. I don’t know if I can do a parallel from the 3.3V line of the level-shifter to the two dacs or if I’ll have to do it independently for each DAC because of probable interference between two DACs. What are your thoughts about this?


    • BlgGear
      March 26, 2016 at 15:28

      Yes you can, the I2C protocol is designed to work with multiple devices, this is why you send a device address first.

  24. Fredrik Aandal
    September 3, 2016 at 19:34

    I am having problems with LCD. I started with a display behaving good, then it got corrupt characters after some minutes, now it shows only squares. Every now and then shows readable characters in upper left corner.

    Noise, bad connection or some timing issue in code? Confuses me as it has gotten worse over time. I cannot find any bad connections, and rerouting cables seem to eliminate noise theory.

    Thankful for any ideas.


  25. September 14, 2016 at 14:59

    iphone repair worcester

  26. September 14, 2016 at 16:04

    Make your resume fast with Workiza

  27. September 14, 2016 at 16:12

    martini shaker set

  28. September 14, 2016 at 16:35

    49.95 any sewer or drain

  29. September 14, 2016 at 17:39

    ibuprofen 800mg

  30. September 14, 2016 at 18:46

    what is alkaline water

  31. bernard
    November 29, 2016 at 20:13

    Are they ready to use kits for ES9018k2m ? (diyinhk)
    Don’t the controller inject some noise into the DAC ship though I2C ? there is no isolation…

    thank you


  32. Prakit
    April 17, 2017 at 15:14

    Hi, I have a TPA’s Buffalo32S DAC which also uses the ESS9018. The board is also provided with I2C. Will this project work with it?
    Thank you
    BTW, great blogs, great writing!

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s