Because WordPress only allows uploading .doc and .pdf, I have renamed the file xx.pde (Arduino file extension) to xx.pdf  in order to upload it. (For versions 10 and above, the s/w is compatible with Arduino 1.0 and thus the original file extension is x.ino

1-Download the link

2-Save Link As and change the file extension:

  • Files “B10x” and newer from “.pdf” to “.ino” [in the file name box]
  • Files ” B09x” and earlier from “.pdf” to “.pde” [in the file name box]

3- Open with Arduino IDE

  • v. 1.0 and newer [download here] for code files “B10x” and later
  • v. 0022  [download here] for code files “B07x” to “B09x” and earlier

edit the code if necessary as indicated in “code customization” below and upload to Arduino board

/******************* Code Customization Section *********************/

/* First: Choose the clock frequency you have and comment the other */

#define USE80MHZ  
//#define USE100MHZ

/* Second: Choose your configuration

   | CONFIGURATION       | #define DUALMONO | #define TPAPHASE |
   | Dual mono in-phase  | un-comment       | comment          |
   | Dual mono TPA phase | un-comment       | un-comment       |
   | Stereo              | comment          | comment          |
   |---------------------|------------------|------------------|    */

#define DUALMONO
#define TPAPHASE

/* Optionally choose the number of inputs. 6 is the max without 
   modifying the code. You could lower the number of input choices
   here                                                             */

#define ICHO 6

/* Optionally change the name of the inputs. Keep 6 characters
   Use blanks if necessary                                          */

char no0[] = "PC-BST";
char no1[] = "PC-LOW";
char no2[] = "SPDIF1";
char no3[] = "SPDIF2";
char no4[] = "SACD-1";
char no5[] = "AMANRO";

/* Make sure you use the correct chip address for each board

   for stereo Buffalo: use address 0x90
   for dual mono: Use address 0x90 for mono left Buffalo 
                  Use address 0x92 for mono right Buffalo           */


As an example, the configuration above is for 80 MHz, DUALMONO TPAPHASE


I’ve added a Creative Commons License if for no other reason that some people have asked me before they decide to use the code. This is also good practice and lowers the risk of any potential copyright issue.

I’ve chosen the most permissive license available under Creative Commons:

Creative Commons License

This work is licensed under a Creative Commons Attribution 3.0 Unported License.

This license lets others distribute, remix, tweak, and build upon your work, even commercially, as long as they credit you for the original creation. This is the most accommodating of licenses offered. Recommended for maximum dissemination and use of licensed materials.

Keep in mind that in the absence of any explicit licensing, there is an automatic copyright for any work created.

Under the Berne Convention, copyrights for creative works do not have to be asserted or declared, as they are automatically in force at creation: an author need not “register” or “apply for” a copyright in countries adhering to the Berne Convention [link]

Thus if someone wishes to use the code for a project, that person doesn’t know whether in some future I would bring up a copyright claim. With the explicit Creative Commons license, the legal uncertainty is removed.

If you like the code, please write a comment in the comment section 🙂

——————————– CODE VERSIONS —————————————–

Version K2M05 (6/29/14)

This version supports the new ESS ES9018K2M DAC and has been fully tested with diyinhk DAC board. More info here [link]

Download: k2m05


  • Should be fully compatible with diyaudio’s syllable DAC [link]
  • Make sure you read the code customization section in the code and make the proper adjustments (clock frequency, type of rotary encoder, etc)

Version K2M04 (6/10/14)

This version supports the new ESS ES9018K2M DAC. For the ES9018, please use the B11f version (which is the latest version as of this writing). Please report any bugs. Be sure to read the “code customization” section in the code.

Download: k2m04


  • This version has been somewhat tested by diyaudio’s syllable [link] on his board
  • I have not tested it myself as I am still building my DAC based on the diyinhk version

Version B11f (3/23/13)

Download: B11f


  • Code if actually around 14K in size, if you turn off the serial port which is used for debugging, so it runs in any version of Arduino including the AT168-based Arduinos
  • Have not used the “improved” wire library in the newer releases, so the code is compatible with Arduino 1.0 or above. In some future version I may use the new wire interfaces, but for now there doesn’t seem to be any reason to use the newer interfaces.


  • Code fixes for “Smart Input Switching” [link]
  • Cleaner code for DUAL MONO

More info here: [link]

Version B11d (11/28/12)

Download: B11d


  • Code has grown to over 15K, so it can no longer fit in the AT168 based Arduino
  • Works with Arduino 1.0 or newer


  • Changed the EEPROM writing routine to only write if there is a change. This will improve somewhat the longevity of the EEPROM
  • Choice of sample rate display format: nominal value or exact value
  • Input selection now includes SPDIF #1, 3, 7 and 8 to support “smart wiring on Buffalo III boards [link]
  • Sample rate reading is more accurate to compensate for integer operation
  • Removed the “primeDpll” function. Doesn’t seem to do anything…
  • Fixed remote control bug that prevented reading repeat keys
  • Minor code clean up here and there, cleaned up comments.

More info here: [link]

Version B11a (11/11/12)

Download: B11a



  • Supports all Apple remotes without the need to adjust the code
  • Changed UI for better support for input data format and sample rate display. Sample rate is correct for all three formats (DSD, PCM and SPDIF) and value of the sample rate is nominal rather than exact
  • When there is no lock to a signal, the screen displays the input mode setting (Serial or SPDIF) rather than the data format (DSD, PCM and SPDIF)
  • Option for selecting the serial mode setting for I2S: LJ, RJ, 32 bit, 24 bit, 16 bit
  • Tested with “New LCD library” for improved code efficiency
  • Some minor bug fix with Jitter eliminator bypass and general code cleaning/optimizing

More info here: [link]

Version Buffalo II 10b (1/8/12)

Download: B10b

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

This version is compatible with Arduino 1.0. It is not compatible with previous Arduino environments, but you can easily make the changes.


  • Made the code change for Arduino 1.0
  • Minor (potential) bug fixes
  • Oversampling filter bypass
  • Jitter eliminator ON/OFF
  • Code configuration -see below- remains the same

Version Buffalo II 09e, g (8/26/11)

Download: B09g This version fixes the problems in version 09f (no longer available). It also supports the output phase configuarion of B09e, so B09e is here just for historical reasons…

Download: B09e In this version, the mono outputs on each board are of the same phase and thus not exactly like the TPA’s  firmware. For more info see the announcement post


  • 80MHz and 100 MHz oscillators
  • Support for DUAL MONO In-Phase (all outputs have the same phase and thus not the same as TPA dual mono output phase configuration)
  • Support for DUAL MONO TPAPHASE (Fully compatible with TPA dual mono configuration)
  • Support for DPLL bandwidth 128x multiplier setting. Doesn’t seem to be very useful, but BIII supports it
  • Support for up to 6 customizable inputs (or more)


In order to support your device and configuration look for this section in the code and make the changes as instructed in the code:

/******************* Code Customization Section *********************/

/* First: Choose the clock frequency you have and comment the other */

#define USE80MHZ  
//#define USE100MHZ

/* Second: Choose your configuration

   | CONFIGURATION       | #define DUALMONO | #define TPAPHASE |
   | Dual mono in-phase  | un-comment       | comment          |
   | Dual mono TPA phase | un-comment       | un-comment       |
   | Stereo              | comment          | comment          |
   |---------------------|------------------|------------------|    */

#define DUALMONO
#define TPAPHASE

/* Optionally choose the number of inputs. 6 is the max without 
   modifying the code. You could lower the number of input choices
   here                                                             */

#define ICHO 6

/* Optionally change the name of the inputs. Keep 6 characters
   Use blanks if necessary                                          */

char no0[] = "PC-BST";
char no1[] = "PC-LOW";
char no2[] = "SPDIF1";
char no3[] = "SPDIF2";
char no4[] = "SACD-1";
char no5[] = "CDROM1";

/* Make sure you use the correct chip address for each board

   for stereo Buffalo: use address 0x90
   for dual mono: Use address 0x90 for mono left Buffalo 
                  Use address 0x92 for mono right Buffalo           */


The code above is configured as 80 MHz, DUALMONO TPAPHASE


The code has 6 predefined inputs. As coded they are “virtual” inputs because you need to switch the inputs externally and you can automate the process by adding your own code to the input selection.

There is a benefit to using virtua inputs to quickly change parameters to one input. For example, you can set up and input named “spdifB” where you use “best” DPLL and another input named spdifL where you use “low” DPLL both using the same external input.

Buffalo II was designed to handle a single input at a time. In order to switch inputs, you need to add some code to control a MUX. With BII configured in manual input mode (as opposed to automatic input detection in the  BII firmware) you can take advantage of internal switching and reduce the external components as described in “leveraging internal source selection” [link]

Buffalo III removes the single source constraint and gives access to all 8 inputs in an individual manner. Sabre32 has a built-in8-channel  SPDIF MUX. You could for example hard-wire 1 I2S  input and 3 spdif inputs and make the switching entirely in software without requiring an external MUX


The code for selecting input is shown below:

void setAndPrintInput(byte value){
  setAndPrintInputFormat(settings[input][FORMATVAL]%FORMATCHO);  // Setup input format value
  setAndPrintFirFilter(settings[input][FIRVAL]%FIRCHO);          // Setup FIR filter value
  setAndPrintIirFilter(settings[input][IIRVAL]%IIRCHO);          // Setup IIR filter value
  setAndPrintDPLL(settings[input][DPLLVAL]%DPLLCHO);             // Setup the DPLL value
  setAndPrintQuantizer(settings[input][QUANVAL]%QUANCHO);        // Setup quantizer value
  setAndPrintNotch(settings[input][NOTCHVAL]%NOTCHCHO);          // Setup notch delay value
  setAndPrintDPLLMUL(settings[input][MULVAL]%MULCHO);            // Setup dpll x value
  switch (value){
  case 0:
  case 1:
  case 2:
  case 3:
  case 4:
  case 5:

For each input selection it first sets the 7 parameters that have been set for that particular input. Then it prints the name of that input inside a switch statement. You can add your own code here to control external switching. For example, the code below shows turning Arduino pin 6 “on” when selecting input N01 and turning pin 6 “off” when selecting input No2. Pin 6 can be used to control a two pole relay for switching input sources.

 switch (value){
  case 0:
  case 1:
    digitalWrite(6, HIGH); // Turn on relay
  case 2:
    digitalWrite(6, LOW); // Turn off relay
  case 3:
  case 4:
  case 5:

Version Buffalo II 09b,c

Fixed small bug in the mute function: B09c_80.Release

Download 80Mhz version: B09b_80.Release

What is new:

  • Named input: you can create a arbitrary number of inputs (this version of the code has 2 inputs)
  • Each input can have its own configuration for the available 6 parameters: Input format, FIR filter, IIR filter, DPLL setting, quantizer setting and notch delay.
  • Settings are saved in EEPROM so there are no default values to worry about. When you first upgrade the firmware, the settings will be arbitrary because the EEPROM has no data, but once you set them up, they will be saved in EEPROM
  • The controller always remember the last setting after power cycle, except for the volume setting which always starts at -50dB (This can be easily changed in the code)
  • The center button in the remote has been mapped to “soft mute” or “dim”. It is currently set at -70 dB. Clicking the button toggles between mute and un-mute. It returns to the previously set volume with a slow ramp up. The speed of ramp up can also be easily changed in the code
  • The buttons in the remote default to non-repeating unless specified. In previous versions of the s/w, the default was repeating unless specified. I realized that except for volume selection, all other selections are better handled with non-repeating keys
  • The code for the 100 Mhz version (to correctly read the sample rate) is also in the code but commented out. You can easily change it to handle the 100 Mhz version of the code

Version Buffalo II 08a

Download 80Mhz version: B08a_80_Release

What is new:

  • Rearranged and simplified the display to reclaim some real state and improve looks. Removed redundant information
  • Added selection of IIR filter and notch delay
  • Further optimization and clean up of the code

Display Mode:

Rotary Encoder adjusts volume level

DIGITS: Digital volume attenuation setting in db. -99db to 0db. I removed the “vol -db” label to reclaim some real state.

IN: Input selection: SPDIF or I2S/DSD, indicated by a left pointing arrow.  Absence of the arrow indicates a detected signal type: I2S, SPDIF or DSD.

SR: Sample Rate in Hz when there is a signal present. Display of the sample rate implies that there is lock on a signal (and thus I eliminated the need to display “lock”). The s/w calculates the sample rate to the nearest hertz by reading the value of the DPLL used for locking into the signal. Most implementations will round off to the nearest 100 Hz (e.g. 44.1KHz).

Fi: Filter selection. The first item indicates the FIR filter selection: Sharp or Slow. The second item indicates the IIR filter selection: PCM, 50KHz, 60KHz or 70 KHz.

PL: DPLL bandwidth selection: Best, Lowest, Low, Low-Medium, Medium, Medium-High, High or Highest. DPLL  for SPDIF and for I2S can be independently selected and tracked.

Qz: Quantizer bit-length selection: 6-bit True-Differential, 7-bit Pseudo-Differential, 7-bit True-Differential, 8-bit Pseudo-Differential, 8-bit True-Differential. See “effect of quantizer setting“. Next to the quantizer setting is the NOTCH delay: No Notch, clock/4, clock/8, clock/16, clock/32 or clock/64. [I don’t really know what this does, but it is a selectable parameter in the DAC]

Heartbeat: Next to “Fi” there is a “heartbeat” indicator to show that the Arduino is running and has not hanged or crashed. The sample rate and the input signal type are detected once every heartbeat. The current setting is one “beat” every 2 seconds.

Select Mode:

Pressing the rotary encoder enters select mode.  A “select bar” is displayed and every press of the rotary encoder moves the selection arrow to the next position. Turning the rotary encoder changes the selection. The system reverts to display mode after 4 seconds of no selection activity.

Version Buffalo II 07d

Download 80Mhz version: B07d_80_Release

Download 100Mhz version: B07d_100_Release

What is new:

  • Bug fix: fixed bug that did not update dpll setting display when switching between I2S and SPDIF
  • Multiple DPLL setting: DPLL is now tracked separately for I2S and SPDIF. It still defaults to “lowest” for SPDIF and “best” for I2S at power-on as these are the most stable settings especially when the DAC is just powered-on

Note: requires Arduino software v. 0022

Version Buffalo II 07c

Download: B07c

What’s new:

  • Jitter reduction is always ON. Jitter reduction is one of the key features of the Sabre32 DAC so I saw no point of having the option to shut it off. The real state (in the LCD) left from this feature deletion is taken by the quantizer options.
  • Selection for quantization bit  length: 6bit true differential, 7bit pseudo and true differential, 8bit pseudo and true differential, and 9 bit pseudo differential. For more information on the quantizer, see the diyaudio forum [link]
  • DPLL “priming”: This is a feature which goes through all the possible settings for the DPLL when the DAC first locks unto a signal. This takes about 5 seconds every time the Arduino is power cycled. The display will show “Optimize” :-). I was hoping this would help the DPLL “best” locking problem, but seems to have no effect. See if it works for you…
  • Improved DAC start-up: this is accomplished by writing known (even default) values to most of the registers. In the previous versions, I left many registers to startup on their default values.
  • Code optimization. The code has been re-organized and further optimized. For example, you can easily choose power-on defaults settings for input, quantizer, volume and FIR filter as these variables have been gathered in one place in the code. The code size is slightly over 10K bytes which is small enough to fit into the original Arduino

Note: requires Arduino software v. 0022

Version Buffalo II 06e

Download: B06e

Supports both SPDIF and I2S/DSD input (in accordance to Buffalo II input wiring)

  • At power-on, the controller defaults to SPDIF input. You can select the default mode by changing a variable in the code
  • Manual selection of SPDIF or I2S/DSD
  • When selecting SPDIF, the DPLL bandwidth defaults to “lowest”
  • When selecting I2S, the DPLL bandwidth defaults to “best”
  • These settings have been empirically determined to be the best for each interface. They can be also manually changed.

DISPLAY MODE (only volume can be adjusted)

  • NLCK: no input signal or the DAC cannot lock into the signal
  • <-: (left arrow) shows the active input when there is no input signal.
  • SR:  incoming sample rate; it displays zero when there is no input signal or no lock
  • Fi: FIR/PCM filter selection: SHR is sharp, SLW is slow
  • Jt: jitter eliminator ON/OFF
  • PL: DPLL bandwidth setting

  • LOCK: DAC is locked into that signal
  • No left arrow indicates that there is a signal in the selected input
  • SR: calculated to 1 Hz resolution as the DAC locks onto the input signal
  • vol: Volume in dB attenuation. Can be independently changed with the knob or the remote control
  • Between SR and vol there is a “heart beat” indicator changing every two seconds

SELECT MODE (Use rotary encoder to make selections)

  • Push down the rotary encoder to enter “select mode”. A side bar is displayed to the left of the screen
  • Every push of the knob will move down the arrow to indicate the parameter that can be changed
  • IN: input selection. SPDIF or I2S/DSD
  • Fi: PCM filter selection. Fast roll-off or slow roll-off
  • Jt: ON or OFF
  • Pl: DPLL bandwidth selection. Can select “Be” (best), “<L” (lowest), “L” (low), … all the way to “>H” (highest)
  • If there is no selection activity for a few seconds, the controller reverts to DISPLAY mode. This time out can be adjusted in the code


  • Up button (1) increases the volume 1 db at a time. Holding the button down will continuously increase the volume
  • Down button (3) decreases the volume 1 db at a time. Holding the button down will continuously decrease the volume
  • The rest of the buttons are not currently mapped to any function, but there is support in the code to read all the buttons


If you are looking for older code: [link]

  1. Guglielmo
    June 3, 2011 at 15:09

    I’d like to use your code to control my Neoy2k board and I’d like to know whe I can find more info about the circuit of the controller.
    There is any schematic available on the blog?

  2. BlogGeanDo
    June 3, 2011 at 16:33

    Hello Gugleilmo,

    You can check out these links:

    The main thing to consider with the Neoy2k board is how the inputs and outputs are configured. If you have further questions, post it and I’ll try to answer it.

    Have fun…

  3. Anonymous
    June 10, 2011 at 21:46

    Thank you very much for sharing this code. Most helpful.

  4. Branko
    July 6, 2011 at 10:57

    it here an option to use an other display type with higher resolution?


  5. BlogGeanDo
    July 6, 2011 at 17:11

    Different display will require different code. The next level of display is a graphics type of display (The one I am using is character based). Using a graphics display will require an Arduino with more pins… So the answer is no with the current implementation.

    • Branko
      August 23, 2011 at 18:05

      Thank you.

  6. Anonymous
    July 18, 2011 at 09:09

    Hi, thanks for codes!

    Can indicate the best settings for an audio signal spdif and an output Single?. The audio material does not exceed 96 kHz.


  7. Michele
    August 23, 2011 at 14:06

    Hi, thank for the codes.
    I’m controlling two BII in a two way system, and I’ve modified your code to control the volume of both BII (Address 0x48 and address 0x49).To do so, I’ve added some line on wich I refer to address 0x49.
    What I can’t do is change all the other settings.
    For example in the following lines you set some parameters at startup:

    void startDac1(){ // Set registers not requiring display info
    writeSabreReg(0x0A,0xCF); // Mute DACs. Earliest we can mute the DACs to avoid full vol
    setSabreVolumeA(currAttnu); // Reg 0 to Reg 7 Set volume registers with startup volume level
    setSabreVolumeB(currAttnu); // as above but for 0x49
    writeSabreReg(0x0D,0x00); // DAC in-phase
    writeSabreReg(0x13,0x00); // DACB anti-phase
    writeSabreReg(0x25,0x00); // Use built in filter for stage 1 and stage 2
    writeSabreReg(0x0E,reg14); // Reg 14: BuffII input map, trueDiff, normal IIR and Fast rolloff

    In a two BII set up these lines work fine for the BII with address 0x48.
    wich are the register for the second BII (the one with address 0x49)?

    • BlogGeanDo
      August 23, 2011 at 16:58

      The best is to modify the writeSabreReg() routine to write to both DACs. I’ll see if I can find some time to make the modification for dual mono.

      You can change the code
      void writeSabreReg(byte regAddr, byte regVal)
      Wire.beginTransmission(0x48); //Hard coded to the the Sabre/Buffalo device address
      Wire.send(regAddr); // Specifying the address of volume register
      Wire.send(regVal); // Writing the volume value into the register

      to the following:

      void writeSabreReg(byte regAddr, byte regVal)
      Wire.beginTransmission(0x48); //Hard coded to the the Sabre/Buffalo device address 1
      Wire.send(regAddr); // Specifying the address of register
      Wire.send(regVal); // Writing the value into the register

      Wire.beginTransmission(0x49); //Hard coded to the the Sabre/Buffalo device address 2
      Wire.send(regAddr); // Specifying the address of register
      Wire.send(regVal); // Writing the value into the register

      • Branko
        August 23, 2011 at 17:59


        i am also locking for a way to control a dual mono setup. So far i did not succeed by myself :(.
        And nobody i asked for so far shared a solution. I think it is not suitable here as it is all about diy but i would beg for such a thing.
        Please duall mono?

    • Branko
      August 23, 2011 at 18:19


      did you succeed with the dual mono setup arduino control?
      would you share it?


      • Michele
        August 23, 2011 at 20:33

        Hi Branko,
        Yes, I’ve modified the code in order to work with two Buffalo II. At the moment I can control the volume of both BII with rotary encoder and with remote too. What I still missing is the ability to modify all the other setting (like DPLL, FIR etc…) on both BII (now this can be made only on the BII with address Ox48). I’m a newbie to C programming so let’s see what GLT will came out with. I don’t know if I can share a modified code, since this is GLT property. If he agree I can send it to you to test.

      • BlogGeanDo
        August 23, 2011 at 21:00

        Hehe… I have been trying to change the culture over at diyaudio to be more like the Arduino community and freely share their projects but I have not been too successful 🙂 I have neither a copyright or a creative commons license in my code mainly because I’ve been too lazy to figure out what to do (I guess there is an implicit copyright but that is another subject).
        I would encourage anyone to use, modify and share the code…
        I’ll work on the code tonight for dual mono and I will depend on you guys to test it because I don’t have a dual mono setup.
        And since I am doing something for your guys (with the $$ to buy 2 sets of everything :-)) I only ask one thing: consider giving to the African famine relief effort or your favorite charity.
        Have fun!

  8. Michele
    August 24, 2011 at 17:14

    Well, I just had a short test with the dual mono setup and the code is fine. Everithing work well.
    Now I’ll try it in my usual configuration, a two way active system. I believe I must use the dual mono code, but modify reg17 for stereo
    You made a very good job. Thanks again for your effort.
    PS: your interest on African famine give honor to you. On my little I’ve made a distance adoption since several year ago. Not too much, but better than nothing….

    • BlogGeanDo
      August 24, 2011 at 18:01

      Congratulations to you on your charity work.
      Your question got me thinking. I did not change the phase for one of channels as the Buffalo II code for dualmono does (in order to support dual mono with two IVYs and then sum the single ended outputs of the IVY) -But you can easily support the official TPA dual mono/dual IVY by flipping one set of wires. If it works for you than means that your output stage is not the “official TPA configuration”.
      For dual mono in active 2-way configuration I think you don’t have to do anything. One DAC board outputs two channels of RIGHT and the other DAC board outputs two channels of LEFT.
      Can you describe your output stage wiring?… Thanks.

      • Branko
        August 24, 2011 at 19:14

        Thank you so much. As for charity: my wife is supporting several projects but i will give extra for this (btw this is a really good idea). I use two IVY output stages and will try things tonight. which wires do i have to change on which channel (sorry noob). I use balanced outputs. why they have to be phase and antiphase?

      • BlogGeanDo
        August 24, 2011 at 20:27

        I am happy to see that diy’ers are also generous people 🙂
        If you look at the BII dual mono diagram, you will notice that you match the labels of the DAC to the I/V (+ to +, – to -, etc). With the current code you will get two outputs for each board that are in-phase. When IVY does the Bal to SE conversion, both sides have the same phase so your balanced out connector will give you two signals that are in the same phase (and exactly the same) and your amp will think it is common-mode and give you silence. Try this out first (and tell me if you get silence). In order to fix this you change the polarity of one of the two outputs in each board (I will do that in the code in order to be compatible with existing products). In order to fix this in hardware for one of the outputs on each board (probably doesn’t matter which of the outputs, but lets do according to what TPA implemented in s/w): MONO LEFT board: flip the wires on the right channel output; MONO RIGHT board: flip the wires in the left channel output. Flip the wires means switch + with – and – with +.
        Hope it works (only tested in my head :-))

      • BlogGeanDo
        August 24, 2011 at 20:37

        Yes, I will make the change in the code in the next version.
        For your active two way: It would be “DUAL STEREO” mode. You will have to change more than just reg17 for stereo if you want to experiment yourself, search for DUALMONO in the code and decide if you need that part or not. I think basically you take the stereo code and just change the writeSabreReg() function to write to both boards.

        However, the code I posted is perfect for “DUALMONO Active two-way”: you will use one Right DAC to feed both high and low frequency and the Left DAC to feed high and low frequency. This way you will get infinite channel separation 🙂

  9. Michele
    August 24, 2011 at 21:10

    BlogGeanDo :
    Yes, I will make the change in the code in the next version.
    For your active two way: It would be “DUAL STEREO” mode. You will have to change more than just reg17 for stereo if you want to experiment yourself, search for DUALMONO in the code and decide if you need that part or not. I think basically you take the stereo code and just change the writeSabreReg() function to write to both boards.
    However, the code I posted is perfect for “DUALMONO Active two-way”: you will use one Right DAC to feed both high and low frequency and the Left DAC to feed high and low frequency. This way you will get infinite channel separation

    Hummm….You gave me a very good hint. I just need to re-route the I2S signal in order to use your DUALMONO Active two-way… is much easier than modify the code 🙂
    Great!! I will try tomorrow.

  10. BlogGeanDo
    August 24, 2011 at 22:40

    Here is my instruction:
    Assuming you are using the official two IVY dual mono with balanced outputs:
    In your MONO LEFT board: flip the wires on the right channel output to the IVY. (switch + with – and – with +.)
    In your MONO RIGHT board: flip the wires in the left channel output to the IVY. (switch + with – and – with +.)

  11. Michele
    August 25, 2011 at 21:40

    What a shame….I’ve been too much In a hurry to try, that I didn’t considered what I was doing.
    I think you should delete my previous posts about this, in order to not confuse future readers

    • BlogGeanDo
      August 25, 2011 at 22:11

      No problem. We are here learning together…

  12. Michele
    August 26, 2011 at 08:36

    Ok, I’m finally listening in DUAL MONO :-). I’ve used some short wire to flip the input on my two IVY/III as per your instruction. I don’t know if it’s just a matter of “suggestion”, but….hey, they sound sooo good

    • BlogGeanDo
      August 26, 2011 at 15:35

      Very nice! Let me know if there are any bugs in the s/w…

  13. Anonymous
    September 6, 2011 at 11:17

    Hi, thanks for posting and sharing your experience!. Novices like me can aspire to something better.

    I have ridden a buffalo dac II according to your instructions to the components that you say in the guide “Introduction and Guide to HIFIDUINO.” Everything works fine with the code “B09c_80.Release.” My clock is 80Mhz.

    I have a single problem. There are two changes to the settings every time I turn the rotary encoder “clicks”. Similarly, the volume goes up one by one and sometimes two at a time, every time I turn the rotary encoder “click” of the 24 has.

    I have used the rotary encoder you say in the guide (Bourns PEC11) and I connected “no H / W debounce”. My duomilanove arduino is powered by usb.

    Can you fix the code?


    • BlogGeanDo
      September 6, 2011 at 16:16

      Seems you are catching some of the switching noise. You can try the increasing the debounce time:

      Look for
      #define INTERVAL_BOUNCE 2

      and change it to:
      #define INTERVAL_BOUNCE 3

      You can also add simple h/w debounce by soldering some capacitors on the outputs to GDN.

  14. Anonymous
    September 11, 2011 at 10:39


    I got this latest version B09g working perfectly with remote and encoder but there is a common ( remote and encoder ) problem, volume always goes up or down 2 dBs at a time
    and values within a selection in menu mode always go 2 at a time also.
    In menu mode if i hold the selector at mid notch then i see the next choice but if i let it rotate to end of notch it jumps to another choice….what could be the problem ?

    Thanks for great work and for sharing,

    All the Best,

    Carlos Viegas (aka CeeVee at diyaudio )

    • BlogGeanDo
      September 11, 2011 at 21:32

      Does the remote changes two at a time all the time or only when you do a quick click? My experience with remote is that the repeat code is emitted very fast after you click, so if you only want a single change, you have to click very fast.

      For the rotary encoder, likely is because the clicks are not mapped to one cycle but to two cycles. I’ve read elsewhere that manufacturers do not often match the clicks to the cycles. This can be solved with more complex software but the simplest solution is to use an encoder that has no clicks or if you can find one where one click matches one cycle. I only tested the panasonic encoder I have (no longer manufactured) and that one has one click per cycle.

      Another user shared with me that in his encoder, the clicks are mapped to 1.5 cycles

      Let me know if you have further questions…

    • BlogGeanDo
      September 12, 2011 at 16:30

      I reviewed my code. You can try the following:
      Search for:
      search for:

      attachInterrupt(0, rotEncoder, CHANGE);
      and change to
      attachInterrupt(0, rotEncoder, FALLING);
      attachInterrupt(0, rotEncoder, RISING);

  15. Pepe
    September 26, 2011 at 10:34

    It seems that the link to download the b09g pdf is dead … 😦 . Could anybody share it ?


    • BlogGeanDo
      September 26, 2011 at 16:15

      The link works fine for me. The comment in the code still says “B09f” but it is “B09g”. Forgot to update the comment 🙂

  16. avr300
    October 8, 2011 at 18:01

    Thank you for this wonderful code.

    I have one tiny question. I’m running a Squeezebox Touch where the volume control is disabled (fixed at 100%), so I have my remote control volume-up/down free for the Auduino.

    Has anyone by any change altered the code to handle the JVC coded Logitech remote ?

  17. BlogGeanDo
    October 8, 2011 at 19:31

    You are welcome.
    Here is a document that would help:
    A quick look shows that the protocol is similar to the NEC-like protocol used in the Apple remote which measures pulse distances (rather than pulse width). It could be as simple as adjusting the pulse interval times for “1” and “0” and using the correct hex codes for the remote keys. Read the comments in the code and also several posts where I describe the remote code.

  18. avr300
    October 9, 2011 at 15:53

    No need to adjust timing. It works out of the box.I’ll post the code as soon I have the system running, perhaps I’m not the only one with a Touch.

    The IR code is described here:

  19. Pepe
    October 9, 2011 at 18:41

    I would love see that code once you have it, if you are happy to share.

    Thank you.

  20. avr300
    October 10, 2011 at 18:29

    No problem. I’ll show as soon I have it running.

    glt, any reason you have started:

    // #define BRIPIN 6 // Pin to control the LCD brightness with analogWrite

    but don’t use it ?

    • BlogGeanDo
      October 10, 2011 at 19:01

      For some reason, (which I did not further pursue) I was getting a lot of noise in the IR receiver when using analogWrite to control the brightness. So I am using a pot now.

  21. avr300
    October 11, 2011 at 16:07

    I’ll see if I can get it running. Along with an LDR and a time out function, it will form a nice automatic light control / screen saver.

    In my own program I have it running here controlling a LED – and I have not problem detection the IR codes.

    More to follow…

    • BlogGeanDo
      October 11, 2011 at 17:03

      According to this paper: (page 14),

      “AGC4 is optimized for most common remote control standard applications in very noisy environments (including dimmed LCD backlightings)”.

      This seems to imply that LCD backlights are notoriously noisy in the IR region. I am not sure why using analogWrite() is worse than using a pot to control the brightness of the LCD.

      And yes, keep us posted on your project…and some photos too.

  22. avr300
    October 11, 2011 at 17:24

    If we assume that the back light also emits light in the IR spectrum, modulating it with a PWM voltage could be read as noise by the IR receiver.

    If that’s true, it explains why you succeeded with a pot.

  23. avr300
    October 17, 2011 at 19:28

    Now I got it running. Differences from stock software:

    – Backlight is set as function of surrounding light hitting an LDR. Very nice digital porn. Totally useless.
    – ECO mode, backlight timeout after a preset amount of time (you have to be green), switches on again either due to rotary encoder movement or IR activity.
    – Volume up/down/mute is controlled from a Logitech Squeezebox remote. Mute is the “0” buttom (I don’t use it).

    Now what ?

    • BlogGeanDo
      October 17, 2011 at 22:08

      Very nice!. Post some photos. What specific changes did you do to support the Logitech remote?

    • Turbon
      April 10, 2012 at 07:10

      Hey AVR300.

      Can you share this digital porn please?


  24. avr300
    October 19, 2011 at 15:20

    None specific – else than tracking both c3 and c4, since they make up the unique code. I couldn’t figure out the “return(c3);” so I invented another variable, IRcode.

    switch (c3) { // Test the received code
    case 0: // If c3=0 and c4=255 we got volume down
    switch (c4) {
    case 255:
    IRcode = 100; //set IRcode to 100
    case 1: // If c3=1 and c4=254 we got volume up
    switch (c4) {
    case 254:
    IRcode=101; // set IRcode to 101
    case 25: // If c3=25 and c4=230 we got 0 (zero) = mute
    switch (c4) {
    case 230:
    IRcode = 102; // set IRcode to 102
    IRcode = 255; // If no recognizable code has been received set IRcode to 255

    Timing is the same.

  25. avr300
    October 21, 2011 at 18:25

    I cleared up my programming a little, reusing your code again. No need for variable IRcode any more (learning along the path).

    But, your detection of repeating IR commands is unfortunately not going to work on the JVC based remote. According to this page:

    it’s very different to way the NEC transmits it’s repeating command.

  26. avr300
    October 22, 2011 at 12:33

    Found a “bug”. My Arduino didn’t enter a run state when the display was connected. It simply didn’t start until i pressed the reset button. Tried with 2 displays, it was the same. Cold start was not possible. It’s not particular for your software, a simple display test software behaved similar.

    In frustration I took off all datalines from the display. Hello! now it’s starting. Connecting them one by one, when connecting Arduino pin7 to the display, the halt was there.

    I altered the code to use display 12,11,10,9,8,6 and moved the rotary push button to pin 7. Now it’s booting correctly 10 out of 10 times.

  27. avr300
    October 22, 2011 at 18:07

    Nailed that “bug” down to a “feature” in Arduino UNO R.2 boards.,64256.30.html

    “try placing a diode between RESET and +5V on the POWER connector, with the cathode (end with the bar) towards the +5V.”

    I did, an it solved my problem. Thanks to the author of that post.

  28. BlogGeanDo
    October 22, 2011 at 23:57

    Thanks for all your contributions. Seem you are having a lot of fun 🙂

  29. Dominic Valois
    January 4, 2012 at 06:20

    I get this message when pressing “verify” using B09g and Arduino 1.0 program

    As of Arduino 1.0, the ‘BYTE’ keyword is no longer supported.
    Please use Serial.write() instead.

    Do you have a fix?


    • BlogGeanDo
      January 6, 2012 at 06:15

      The “fix” is easy. Just replace each instance of lcd.print() with lcd.write and omit the BYTE keyword. However, there are other problems with the I2C protocol that has changed. So better stick with version 0.22

  30. Rodrigo Rocha
    January 12, 2012 at 03:27

    I can not view your files in Linux and Android.

    • BlogGeanDo
      January 12, 2012 at 06:23

      You need to save the file as .pdo or .ino
      I uploaded them as .pdf because wordpress is picky as to what you can upload…

  31. Anonymous
    March 10, 2012 at 12:09

    Hi GLT – thanks for the great work, have a dual mono Buff2 setup working perfectly with your code and Arduino setup.

    I would like to build a mutli channel DAC pre for active x over and surround use – i am struggling to modify the code succesfully to DUAL STEREO being a complete code newby – can i make a donation to have this feature added to the code?

    I need 4 seperate channels from 2 Buff2 boards with Arduino remote volume control. Ideally i would like to use 3 or 4 dac boards with a i2c multiplexer to provide 6-8 seperate channels all controlled from one remote but unfortunately the code to achieve this is well beyond me!!

    Any input would be greatly appreciated as the control is my only stumbling block on this project.

  32. BlogGeanDo
    March 10, 2012 at 19:58

    Hello, Sure, no problem. Dual stereo is easy. I suppose you will need channel trim which I have not implemented.

  33. Anonymous
    March 11, 2012 at 20:04

    Hello GLT, channel trim for each channel would be the ultimate solution but it can also be done in the pc – probably not as good as in the DAC but certainly workable if its difficult to impliment in the code. Where do you want the donation sent?


    • BlogGeanDo
      April 7, 2012 at 23:53


      I’ve put together a dual stereo version. You can find it the the “Other” tab. Have fun…

      • Anonymous
        April 29, 2012 at 20:58

        Just noticed the dual stereo code glt – really appreciate it; thanks for helping less knowledgeable diy folk like myself. Looking fwd to getting it uploaded. cheers

  34. BlogGeanDo
    March 12, 2012 at 17:13

    No need to send donation. I’ll make the changes to “dual stereo” and just enjoy :-). Give me a few days.

  35. Richard
    April 5, 2012 at 14:28

    Hi GLT. I thinks there maybe a small bug in your code (or it may just be my mis-understanding!)

    In the main loop section you are calling the setAndPrintBypassOSF routine and passing a parameter (0 or 1, depending on samplerate) yet the routine has no parameter input defined:

    void setAndPrintBypassOSF(){

    Am I missing something?

    Cheers Richard

  36. BlogGeanDo
    April 5, 2012 at 16:14

    Hi Richard, thanks for the feedback. I’ll take a look when I get a chance…
    I think it had to do with “automatically turning off oversampling” if the sample rate was >192K and that was only for the version of BII with 80 MHz clock. Unfortunately oversampling off only works if you are feeding the clock synchronously. (ie, disabling the local oscillator and feeding an external clock)

    I’ll take a look and thanks for reporting the bug

    • Richard
      April 6, 2012 at 07:03

      As you say it’s not an issue likely to effect me or many others.
      BTW thanks for the great project and code. I’m in the process of writing similar code for the Buffalo, but using a Microchip PIC and no LCD, just LEDs. All the info here has a been a HUGE help. Cheers!

  37. Anonymous
    April 11, 2012 at 19:40

    Turbon :
    Hey AVR300.
    Can you share this digital porn please?

    It’s still in lab setup, so nothing really to show yet.

  38. ed linssen
    June 18, 2012 at 13:40

    Thank you so much for making it possible using your Arduino code and blog builing this setup!
    I managed so far setting up an Arduino uno for controlling my Buff III. My four bar diplay is showing eveything I want to know and control. Such as volume etc. I got stuck in choosing the various inputs, I am using the 4*spdif board and the sidecar for USB.I2s. Could you push me a little?
    Thanks so far,


  39. Will
    November 6, 2012 at 09:48

    Hi, I was wondering if anybody has used the code with a Buffalo B32s specifically? I see no reason for it to be a problem, but was wondering. I’ve an Arduino One sitting here looking sad :O)

    • BlogGeanDo
      November 6, 2012 at 15:14

      It should work as the inputs and outputs are configured similarly to BII.

      • Will
        November 6, 2012 at 20:39

        Thanks for the reply. I’ll start with older code and work up, so that I can understand what the changes are doing. Only way to learn!

      • BlogGeanDo
        November 7, 2012 at 03:40

        …although the newest code has the best comments. 🙂

  40. Zoran
    November 16, 2012 at 09:48

    Hi I have Arduino UNO (R3 board model)
    want to try with my own version of ESS dac chip
    I do not need for this relly great code, but rather more simpler one.
    My design is based on 2 dac chips used. one DAC per channel.
    Dual mono mode.
    ALL internal dac-s on each channel IN PHASE.
    So the very first lines of the simple code should be to determine
    the dac chip channels?
    And after that other few things to define like selector
    I dont need for volume control…
    (like old old programmer by the school, i have some knowledge and partial understanding,
    with reading this new code.)

    • BlgGear
      November 16, 2012 at 15:04

      First thing is to get a hold of the datasheet from your distributor.
      Then learn how to program I2C in Arduino
      Then set address of each chip (there are only two options)
      Set the chip for MONO mode: one for MONO right and the other for MONO left
      The rest of the registers can be left on power-on default (almost shure, but you will need to check against the datasheet).

      Then figure out what you want to select and program the registers accordingly.

      Good Luck

  41. Zoran
    November 16, 2012 at 22:37

    Are the chips will back automatically to the factory settings
    when arduino is disconnected? (after uploading any code)
    Is there any order of teling the arduino what to do.
    for instance first define the adresses for left and right?
    and then 2 times (the same code, into the bodies of the L and R?
    Because it is the same settings, the same code for L and R, could be added after in the script?
    It is not clear to me?

    • BlgGear
      November 17, 2012 at 02:40

      The chips will always start in default condition. Arduino will then reprogram the registers. No code is ever uploaded to the chips. The chip address is hard coded in the chips address pin.

      I recommend you get familiar with Arduino, I2C, register programming, before you start your project. Take your time. You can read my old blog too:

      • Zoran
        November 17, 2012 at 08:57

        Now it is clear about factory settings defaults states.
        So this issue about auto SPDIF You mensioned in the script
        ” NOTE on auto/manual SPDIF selection”
        will also back to hard locked the factory registers settings?
        I will add on this than nuber 3 option putpose is for testing and optionally measure the specs of the the chip without any of input signals
        from Your script it is clear than You first define and set variable for DUALMONO (If case) in 8 bit lenght with values for each physical chip defining L and R. And later when updating registers with arduino using 7 most significant bits of the 8-bit address. In Your example is
        0x90 becomes 0x48 as follows:
        0x90: 10010000 (we eliminate the rightmost bit to get I2C address)
        0x48: 1001000
        When using dual-mono configuration, the other device can be set to addres 0x92
        0x92: 10010010 (we eliminate the rightmost bit to get I2C address)
        0x49: 1001001
        I read the ESS pdfs off-course, and Your code for arduino which is excelent complementary information source.
        I will go to Your blog too.

      • BlgGear
        November 17, 2012 at 14:36

        You are in the right track. The way the addresses are coded is because of the I2C protocol requirements. (Learn about I2C protocol :-))

  42. Zoran
    November 16, 2012 at 22:44

    I downloaded and went trough the last code. Really good
    and educational with comments at the end of the lines. Thanks a lot.
    Please understand me with all “this” questions

  43. Zoran
    November 17, 2012 at 23:53

    So for the each phisical chip has to be defined
    with pin 41 = ADDR (input pin)
    0 = connect to digital ground = mono LEFT = chip address = 0x90
    1 = connect to digital + = mono RIGHT = chip address = 0x92
    before any uploading?
    You mentioned two ways to acheive chip separtion (infact, merging all dac units to folow L data stream)?

    • BlgGear
      November 19, 2012 at 01:00

      Yes. There is no “uploading”, just writing values to registers (memory locations) in the chip. When you power cycle, everything you write is gone. And the next time you power up, Arduino writes the values again. The I2C protocol requires that you specify the address of the chip before you write a value

  44. Zoran
    November 19, 2012 at 10:33

    Yes sorry, I use wrong term uploading, against writing the registers, thanks.
    according to the ESS issue about the ADDR state (pin 41),
    on page 14 of the ESS ES9018 PDF, table 7, diagram 1
    Could You tell me one thing please:
    if I just select ADDR pin by setting one dac to 0 and other to 1
    without ANY changing the registers values, without arduino connected
    would I have, with the very same default factory preset input.
    the left channel output at one and right channel output on other dac chip.
    With booth dac chip default factory settings like in the data-sheet?

    • BlgGear
      November 19, 2012 at 16:47

      Both chips will default to 8-channel (not MONO)

  45. Zoran
    November 19, 2012 at 16:14

    please someone take a look into this lines
    and comment mistakes?
    void setup()
    Wire.begin(); // join i2c bus
    void loop()
    Wire.beginTransmission(0x48); // transmit to device: ADDR pin 41 set to logic 0
    Wire.send(0x11); // Specifying the address of register
    Wire.send(0x45); // Writing the value into the register
    Wire.endTransmission(); // stop transmitting
    Wire.beginTransmission(0x49); // transmit to device: ADDR pin 41 set to logic 1
    Wire.send(0x11); // Specifying the address of register
    Wire.send(0xC5); // Writing the value into the register
    Wire.endTransmission(); // stop transmitting
    use form void() against the void loop()?
    void WriteReg(byte register, byte data)
    Wire.beginTransmission(chip address)

    • BlgGear
      November 19, 2012 at 16:54

      Hey Zoran, the best advise I can give you is to get the DACs set up and try the code yourself.

  46. Zoran
    November 19, 2012 at 18:05

    the simple code will be tryed that is for sure, thanks.
    I just wrote one to simpe split the chips
    for the start
    maybe it will be of inerest for someone dont have a need for big script
    and more open to the open source spirit…
    1. determine which one of th physical chip is L and R
    by setting the ADDR pin 41 on ESS ES9018, page 14, diagram 1, ESS pdf
    0 = connect to digital ground = mono LEFT = chip address = 0×90, Arduino 7bit = 0×48
    1 = connect to digital + = mono RIGHT = chip address = 0×92, Arduino 7bit = 0×49
    2. make a change on register #17 EACH dac unit, 2 different addresses
    7 6 5 4 3 2 1 0 [ bits ] marked like in ESS .pdf
    x x x x x x x 1 BIT [0] has to be the selected for all_mono = 1
    3. for the LEFT 0×48 ADDR, exchange BIT [7] to 0
    0 x x x x x x 1 BIT [7] use LEFT when for all_mono
    4. for the RIGHT 0×49 ADDR, exchange BIT [7] to 1
    1 x x x x x x 1 BIT [7] use LEFT when for all_mono
    all other bits in register #14 for booth devices can be left the same as it is.
    I will post the very simple code
    checked and uploaded into arduino, no errors reported
    Just need some INFO to complete my little test script…
    Can someone tell from the praxis:
    For the LEFT dac output phases are like in the datasheet
    for the RIGHT channel is there any exchange of output phasses?
    is it reverse from LEFT unit?
    OR remains the same output phases like in the LEFT cham

  47. chryses
    January 2, 2013 at 22:11

    Not sure I’d characterize this as a bug, but the display updates the input source and sample rate every “heartbeat” even if they haven’t changed. I’m using a NewHaven OLED display and this behavior causes a noticeable flicker, which I found sort of annoying. I’ve updated the code to only update the display if the sample rate or input source changes. I didn’t want to clutter up this comment thread with all the changes, so I put them here:

    • BlgGear
      January 2, 2013 at 22:50

      Thanks for sharing the code.
      This is by design because the sample rate it is displaying is what the controller is reading from the status register. Input source shows more than input source: it shows whether the incoming signal is PCM, DSD or SPDIF.

      True, you don’t have to re-display of there are no changes, but the code is simpler if you re-display and in the LCD displays, there is no flicker whatsoever…

  48. Branko
    February 1, 2013 at 19:40

    As for controlling the 4:1 mux with arduino is there need for level conversion to 3.3v for the two (0;1) lines. I used it a few times while testing code for mux switching without level conversion (no problem so far) but i read somewhere ist has to be converted?


    • BlgGear
      February 2, 2013 at 05:48

      The mux pins has pull-ups so you can pull down or leave “open”. Leave “open” is like setting the pin as input. Try setting the pin to output when pulling down and setting the pin to input if you want to “pull up”

      Try setting the pin low and switching it input (open) or output (pull to gnd)

      • Branko
        February 16, 2013 at 14:21

        i gave this info to corpius who wanted to implement it to his ce644 board firmware. today itreid and it did not work. here is the code:

        pinMode(MUX_TERMINAL1, INPUT); // Set pin as input
        pinMode(MUX_TERMINAL0, INPUT); // Set pin as input

        digitalWrite(MUX_TERMINAL1, LOW); // set to high impedance output
        digitalWrite(MUX_TERMINAL0, LOW); // set to high impedance output

        . }
        . switch(value){
        . case 1:
        . if (!firstP)lcd.print(“1”);
        . pinMode(MUX_TERMINAL1, OUTPUT); digitalWrite(MUX_TERMINAL1, LOW); // 4:1 ch MUX
        . pinMode(MUX_TERMINAL1, OUTPUT); digitalWrite(MUX_TERMINAL0, LOW); // 4:1 ch MUX
        . break;
        . case 2:
        . if (!firstP)lcd.print(“2”);
        . pinMode(MUX_TERMINAL1, OUTPUT); digitalWrite(MUX_TERMINAL1, LOW); // 4:1 ch MUX
        . pinMode(MUX_TERMINAL1, INPUT); digitalWrite(MUX_TERMINAL0, LOW); // 4:1 ch MUX
        . break;
        . case 3:
        . if (!firstP)lcd.print(“3”);
        . pinMode(MUX_TERMINAL1, INPUT); digitalWrite(MUX_TERMINAL1, LOW); // 4:1 ch MUX
        . pinMode(MUX_TERMINAL1, OUTPUT); digitalWrite(MUX_TERMINAL0, LOW); // 4:1 ch MUX
        . break;
        . case 4:
        . if (!firstP)lcd.print(“4”);
        . pinMode(MUX_TERMINAL1, INPUT); digitalWrite(MUX_TERMINAL1, LOW); // 4:1 ch MUX
        . pinMode(MUX_TERMINAL1, INPUT); digitalWrite(MUX_TERMINAL0, LOW); // 4:1 ch MUX
        . break;
        . }

        any hints on how to get to work?

        thank you

      • BlgGear
        February 16, 2013 at 19:02

        Hello, try this:

        . case 1:
        . if (!firstP)lcd.print(“1″);
        . pinMode(MUX_TERMINAL1, OUTPUT); digitalWrite(MUX_TERMINAL1, LOW); // 4:1 ch MUX
        . pinMode(MUX_TERMINAL1, OUTPUT); digitalWrite(MUX_TERMINAL0, LOW); // 4:1 ch MUX
        . break;

        Your second pinMode should be for MUX_TERMINAL0

        Same for the other case statements…

      • Branko
        February 17, 2013 at 18:44


        thank you for your kind help (as always).
        I checked today and the schematics for the 4:1 Mux from tpa is not correct (at least for booth my version boards) terminal 0 and terminal 1 are pulled down to ground via 10 k resistor. Therefor it has to be used with voltage divider to switch inputs with there Arduino.

      • BlgGear
        February 18, 2013 at 17:54

        So how does it work without Arduino? Does it use a mechanical switch? And how is the switch connected?

  49. David Quayle
    February 5, 2013 at 21:31

    I have started modifying DimDim’s version (different screen etc) of your code to get my BIIISE up and running. What I was wondering was, with my existing BIII where the BIII firmware chip is still in place I start the DAC, Crossover & Amps at the same time as the amps have a short (1-2 Sec) delay before they connect the signal. With the new BIIISE (Biii firmware removed) setup do I need to delay the amps startup further, to give the BIISE time to get up & running?

    Also just out of interest, why is there 2 x Startup routines ie startup 1 & startup 2?

    • BlgGear
      February 5, 2013 at 21:57

      There are two startup because you need to mute the DAC ASAP upon power on. The DAC (compared with ARduino UNO) actually starts up a fraction of a second faster, so if you have signal input, it will start up at full blast for a fraction of a second -Can’t fix this with code…

      Since it just a split second, you don’t have to delay further.

  50. March 30, 2013 at 22:01

    At the moment my DAC has a life of it’s (the Frankenstein DAC, it lives!!!) I keep coming home from work & finding it on!! Which means the whole system is on, & chewing up the power. The other morning it turned itself on, then off then on again in a 30 second window. I’m very sure there are no stray IR signals.

    What do you think might be the most likely cause of this issue?

    Bye the way, the valve/tube sound is pretty good, I like it.

    • BlgGear
      March 31, 2013 at 22:28

      What command turns the system on? A switch? a command from the remote? (It is very hard to randomly generate a valid code as the IR code only responds to valid commands). if it is a switch, it could be a bad connection. Make sure the soldering is solid.

  51. April 1, 2013 at 10:36

    The rotary encoder switch will turn it on & the remote will turn it on. I’m going to try disconnecting the IR tonight & see what happens.

  52. April 2, 2013 at 11:16

    I tried putting masking tape over the IR receiver & it still turned itself on, it’s either in the loop code or the Mega is getting some interference which is upsetting it. My first DAC doesn’t have this issue & it was sitting in exactly the same spot for months.

    • BlgGear
      April 2, 2013 at 16:06

      Does it only turn on? or also off while you are listening to music. It is almost impossible to generate a valid IR code from random noise… The switch can have noise. Try putting a small capacitor across the switch.

  53. April 3, 2013 at 01:07

    It turns on & off, but mostly on as I normally find it & turn it off. I have only had one occasion where I can guarantee it turned itself off, which should eliminate the switch, but I might disconnect the switch anyway & see what happens.

    • BlgGear
      April 3, 2013 at 15:57

      Is the pull up resistor enabled in the pin connected to the switch? I suppose when you actuate the switch, you pull it down?

  54. April 3, 2013 at 21:23

    Yes in that area my code is the same as yours, it is yours 🙂

  55. April 5, 2013 at 21:55

    With the switch disconnected it still turned itself on, I must be suffering from audio gremlins

    • BlgGear
      April 6, 2013 at 00:00

      Use another pin. If the pin is picking up noise for whatever reason, including a faulty chip/board, then the code will read it.

  56. wktk_smile
    April 20, 2013 at 11:38

    bug in dual mono-tpa phase.

    writeSabreLeftReg(0x0D,0x22); // MONO LEFT DACx: odd dacs=in-phase; even dacs=anti-phase

    -here I think register 0x0D value should be 0x55

    writeSabreRightReg(0x0D,0x11); // MONO RIGHT DACx: odd dacs=anti-phase; even dacs=in-phase

    -I think register 0x0D value should be 0xAA

    #endif TPAPHASE

    • BlgGear
      April 20, 2013 at 16:46

      Hi, thanks for testing. I’ll check it out…

  57. wktk_smile
    April 21, 2013 at 00:33

    Sorry, checked again with actual dual mono dac and found your code was correct.

    What confused me was BII input remapping seems to affect register 13, I hadn’t realized before…

  58. Kim.C
    August 11, 2013 at 20:08

    Hi all,

    I would like to know how to change program code, to set the volume setting to -20db all the time?

    Can somebody help please?


    • BlgGear
      August 12, 2013 at 22:31

      change this:

      #define DEFAULTATTNU 0x64 //-50 dB this is 50×2=100 or 0x64. Sabre32 is 0 to -127dB in .5dB steps


      #define DEFAULTATTNU 0x28 //-20 dB this is 20×2=40 or 0x28

  59. David Quayle
    August 15, 2013 at 11:17

    Kim.C :
    Hi all,
    I would like to know how to change program code, to set the volume setting to -20db all the time?
    Can somebody help please?

    If you use a Decimal to HEX convertor you can change it to whatever you want

  60. Kim
    August 15, 2013 at 19:07

    Thanks David:)

    But what if I want -15dB, can it also be done and how do I calculate that setting?

  61. Kim
    August 15, 2013 at 19:41

    I found out:) and I changed the volume to -16db:) The reason to -16db is because I am using Lcaudio Zapfilter 2, for I-V stage and it distorts if i try with higher output.

    Is it possible to change the program so “PC-BST SPd” input is always default input?


  62. David Quayle
    August 16, 2013 at 10:24

    When you select it (“PC-BST SPd”) in the settings it should remain the default input until you change it.

    • BlgGear
      August 16, 2013 at 16:23

      Hey David, thanks for chiming in. You are getting good at this. Yes, all the settings are saved in EEPROM everytime you make a change. During power on, the last settings are read from the EEPROM.

  63. David Quayle
    August 18, 2013 at 07:54

    BlgGear :
    Hey David, thanks for chiming in. You are getting good at this. Yes, all the settings are saved in EEPROM everytime you make a change. During power on, the last settings are read from the EEPROM.

    Thanks, I find this coding thing doesn’t come naturally.

    I have my code working fine but I suspect that it’s not exactly as it should be with the source (Input) selection side of things but I can’t quite put my finger on it.

    When changing the source (input) I assume what is happening is the changes (Input & settings) are sent to the BIII and the EEPROM, but the only time they are sent (read) from the EEPROM to the BIII is at power on, is this correct.

    So every time I change the Input, I need to send the, Input & it’s settings to the EEPROM and BIII.

    • BlgGear
      August 19, 2013 at 17:20

      No. Every time you change the input setting, the settings for all the different registers are read from the EEPROM and the DAC is programmed accordingly…

  64. David Quayle
    August 18, 2013 at 08:06

    It would be relevant to tell you that I have setup a simple screen which is the default screen & your screen is only called when I want to change settings.

    So the source(Input) selection I am talking about is from my simple screen, not from your screen.

  65. Anonymous
    September 7, 2013 at 10:09

    Hi Glt, I populated a Diyinhk ES9018 board which works perfect in hardware mode. I wired Ardunio uno R3, loaded your code.LCD,remote and rotary encoder works but I got low and distorted sound when DAC works in software mode. LCD shows the sampling ratio but same distorted sound is heard from other inputs despite I only connected XMOS USB board via I2S. ES9018 board has 100 Mhz SAW crystal and the code comes with 100 Mhz as default. Could you help me?

    • Anonymous
      September 7, 2013 at 12:53

      I found the problem, after selecting I2s the problem has been solved but there is another one:Music comes from all inputs! How can I fix it?

      • BlgGear
        September 7, 2013 at 14:39

        You need to separate the inputs but cutting the trace. By the way, the frequency “setting” in the code is only to calculate the sampling frequency. It does not affect the operation of the DAC.

  66. Anonymous
    September 8, 2013 at 03:09

    Thank you very much. Is there any specific reason of bridging the inputs? Is it necessary for hardware mode?

    • Anonymous
      September 8, 2013 at 08:33

      Hi Glt,

      I am sorry but I totally confused. There is no document provided with ES9018 board nor XMOS USB board and I cannot make sure about the connections.I will cut the traces between Data – D5. I have Diyinhk 384k USB board and also ordered Amanero board. I want to connect one of these USB boards and spdif inputs. There are three connection schematics in this link:
      1.There is LRCK pin on ES9018 board but the diagram shows, it must be connected to D1. If D1 is LCRK, what is the pin named Data on ES9018 board? Is it D2? Data is also shorted with D2 and others.
      2. BCK pin is actually DCK on your diagram?
      3. MCK pin on Xmos board should be clock, while I have 100 Mhz SAW on ES9018 board, I will not connect it.
      4. If I connect Amanero with smart wiring, do I have to change the code? Anything else I need to modify?
      5. If I do not cut the traces and use D6,D7 and D8 pins for spdif, do I have to change anything on the code for spdif?

      I am sure your answer will help many newbies who do not have enough info about ES9018.

      Thank you

  67. Jose
    March 19, 2014 at 18:33

    I burn the code onto Arduino and try to control BIIISE. It is able to read the sampling rate, but not able to control any other functions, like volume, IIR setting, etc. What is the DIP switch setting should I use on the BIIISE, do I need to remove the controller chip on the BIIISE.

    • BlgGear
      March 19, 2014 at 19:28

      Yes, have to remove the controller on the BIIISE. Otherwise you will have two controllers trying to be the master of the I2C lines… Lots of people have made this work, so it should work. Regarding the dip switches, I believe those are used by the local microcontroller for the settings in the DAC. If you use my code, all the settings are done in the user interface. (Haven’t looked at the BIIISE manual for a long time, so I am not 100% sure). Enjoy!

      • Jose
        March 19, 2014 at 23:28

        Great thanks … it works now. I really enjoy this blog… Excellent.

  68. sdo
    April 5, 2014 at 23:34

    v b11f.

    In the handling routing for the rotary encoder, the code does not use constants for pins, i.e. the hardcoded (“if (digitalRead(4) == digitalRead(2)” should be perhaps “if( digitalRead(VOLUPPIN) == digitalRead( VOLDOWNPIN))”.

    The variable ‘rotating’ should be declared volatile and access to it in the ‘loop’ should be within a block with disabled interrupts, i.e.
    uint8_t oldSREG = SREG;
    int localRotating = rotating;
    SREG = oldSREG;
    if( localRotating){

    oldSREG = SREG;
    rotating=false; // Reset the flag
    SREG = oldSREG;
    The interrupts changes are based upon Nick Gammon material at

    I’m running both of the above changes

    I ported the code to work with MatrixOrbital(MO) LVK204-25. One change that would be helpful is relative positions on the screen. For 4×20, MO starts numbering from 1rows and columns. Consistent usage of something like
    #define COLBASE 0
    #define ROWBASE 0

    lcd.setCursor( COLBASE+7, ROWBASE+1)

    would make porting easier. I currently just add teh offset in MO library code. Another change was due to the different default character table in the MO LCD, so that caused a bit of work. For example, MO does not have a solid block symbol defined in the default set. I ended up using an old 3 row font from HiFIDuino that uses only the custom defined chars. MO has built in 4 row font, so I’ll may play with a different layout to use the built-in large font for the volume.

    Along the same ‘porting’ lines I added constants to replace hard coded values
    const char separatorChar =0xCD,
    pulseChar = 0xB2,
    spaceChar = 0x20;

    Having ‘A’ and ‘B’ for ‘space’ and ‘solid block’ chars was fun to figure out. I’d change them to ‘SPACE’ and ‘SOLID_BLOCK’.

    Some refactored code to save a bit of space. Some functions with long switch statement may be shortened by moving ‘recurring code’ above ‘switch’. For example,
    #define DPLL_SETTINGS 8

    const char *DPPL_Label[DPLL_SETTINGS]={

    const unsigned int DPPL_Code[DPLL_SETTINGS]={

    void setAndPrintDPLL(byte value){

    bitSet(reg25,1); // Reg 25: set bit 1 for “use best dpll”
    writeSabreReg(0x19,reg25); // Write value into reg 25 for best dpll

    case 0:
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
    case 6:
    case 7:
    writeSabreReg(0x0B, DPPL_Code[value]); // Reg 11: Set corresponding DPLL bandwidth
    lcd.print( DPPL_Label[value]);
    #define MENUITEMS 10
    static byte menuPositions[MENUITEMS][2]={

    void printSelectBar(byte value){
    for( int i=0; i < MENUITEMS; i++){
    lcd.setCursor( menuPositions[i][0], menuPositions[i][1]);
    lcd.write( value);

    • BlgGear
      April 8, 2014 at 01:17

      Thank you so much for pointing out improvements to the code and those to facilitate porting.

  69. sdo
    April 5, 2014 at 23:54

    Correction for the last table
    static byte menuPositions[MENUITEMS][2]={


  70. Anonymous
    April 30, 2014 at 20:11

    I reviewed your suggestions (thanks), For me, the “long hand” code is more readable, so I am still deciding to shorten it. Implemented your interrupt handling code and other minor corrections… Thanks again.

  71. July 4, 2014 at 02:03

    Quick question…

    On the display there’s a place where I can select “MUL, INV, NOR” what are these settings for? Also another one which is (^) or (•) and I have no clue what the caret or dot do. Any help would be appreciated.
    What would also be the optimal setting for a BII stereo mode with 100Mhz clock?


    • BlgGear
      July 7, 2014 at 18:45

      These are additional settings for the DPLL values: “MUL” applies a 128X multiplier to the DPLL setting, “NOR” is normal, “INV” locks to the inverted edge of the incoming signal. (^) is oversampling filter on and (.) is oversampling filter off….

  72. July 9, 2014 at 15:37

    Thanks for the information. What is your preferred config?

    • BlgGear
      July 10, 2014 at 21:41

      I can’t hear much difference among the different settings. Others with more discerning hearing may. But I try to use the lowest DPLL bandwidth possible (lowers jitter) and also higher bit quantizer which theoretically lowers noise. Unless you have external upsampling, running the DAC in NOS mode cuts the high frequencies, so I always run it in oversampling mode.

  73. sebastian
    July 16, 2014 at 10:58

    If you can find the time, can you please take a look at the diyinhk ess9018 build topic?

    I have 2 problems interfacing the arduino with the dac board.

    (1) After power on, it mutes the es9018 but does nothing further, until I use the reset button on the dac then I can see the sample rate and control the volume by remote.

    (2) strange symbols on screen. The heartbeat symbol and the . symbols are wrong. The custom symbols all work fine. I have put up some pictures in the topic.

    I hope you can help me, because I don’t have a clue what’s going on.

  74. sebastian
    August 3, 2014 at 19:30

    The strange symbols on screen was due to a non completable display so that’s oke now.
    Used a new adruino new display new psu. the same problem after power on the DAC mutes until I reset the dac en then everything is fine. I don’t know what to do next. I am really out of options 😦 There is nothing special about the DIYIHK ES9018 dac, this should work.

    • BlgGear
      August 8, 2014 at 04:21

      The code mutes and then unmutes the DAC at startup. So it cannot be code leaving the DAC muted. What happens if you reset the Arduino without resetting the DAC? Also, what are you using as a source? And, is there another device using the I2C bus (like the XMOS device from diyinhk that allows controlling the volume?)

      • sebastian
        August 8, 2014 at 14:58

        Hey!, I was hoping you would show up 🙂 First of all thank you for your blog, without it I would never dared to start all this.

        I have made a short movie of it.

        Yes, there is a diyinhk xmos usb to I2S device in there, but the I2C pins on the dac board go directly to the main 9018 IC.

        Resetting the Arduino does nothing. I noticed that If I only connect the ground wire from the Arduino to the I2C ground the dac never gets out of mute / stop functioning . A full power cycle is needed to get it up and running again.

        From day one I suspected a ground loop somewhere, but I can not find it. Why If I connect the ground from the Arduino to the ground pin on the I2c bus the thing go’s banana’s

        The power situation is as follows:

        I have 2 R-core transformers.
        first transformer go’s to the 4x regulator board and makes 12+ 12- for opamp 3.3 for l avcc and r avcc

        second transformer go’s to the second regulator board.
        3.3 for dvcc and 5v for the arduino using the v-in pin and it also powers the lcd. the arduino starts faster this way, don’t know why..

        I was afraid that the arduino boots to fast this way so I powered it using a lm7809 and the lcd from the onboard 5v regulator.

        It’s a subconscious feeling that It’s this whole second transformer and second regulator board is a bad idea.

        Anyway maybe its a defective 9018, but diyinhk is not willing to take a look at it even if I pay for his time. And I’m out of idea’s 😦

        I ordered a bus pirate, its a simple data logger to sniff the I2C lines, but that is as far as I got with this problem.

        Hope you can help.

        Kind Regars


      • BlgGear
        August 13, 2014 at 21:20

        Interesting about the ground connection. I don’t know what is going on.
        If the ES9018 chip does not respond to an Arduino restart, this means at the minimum that the I2C bus is locked up (it could be other things).
        Are you sure the XMOS device you have is NOT the one that allows volume control from the PC side? One of the XMOS devices from diyinhk accesses the I2C bus from the es9018. If you use this device, then two I2C master devices (the XMOS and the Arduino) are trying to access the chip. I don’t know exactly what is the effect of this but it could be a factor

  75. sebastian
    August 14, 2014 at 14:53

    I have this one

    Do you have any idea why I have a blank space in the input selection?

    I’m waiting for the bus pirate to show up and will buy a spdif to ttl shifter . Until then there is nothing I can do. I’m thinking of buying a second board and swap all the parts. Its easier then replacing the ES9018 chip it self I think.

    • BlgGear
      August 15, 2014 at 04:32

      OK, no I2C signals from the XMOS, so there is no I2C bus contention problem.

      Can I see a photo of the whole DAC board?

      If you change the input selection do yo still see blanks?

  76. sebastian
    August 15, 2014 at 10:46

    I have heard that you have to make a input selection first and after that the input shows up. Still waiting for my rotary encoder to show up, I was under the impression that you could use the remote to change settings so I did not order at first.

    The DAC front and back hires

    complete setup out of its case

    Arduino board close up

    Level converter

    connetion to the DAC board

    As you know If I reset the DAC it works, but if I then reset the arduino it mutes the dac again and no data like sample rate shows up,

    • BlgGear
      August 16, 2014 at 16:26

      Everything looks in good order.
      There is code for the remote to only control volume. Other things can be controlled with more code.
      Try not using the Arduino. The DAC should start up with all registers in their default value (which means full volume and you need external volume control or a weak amp). If this works without the Arduino, then the Arduino is causing the problem, if it still needs a reset, then the dac board is the problem

  77. sebastian
    August 16, 2014 at 17:18

    It works! (I’m so happy)

    It has to do with the blank space, you need to make a input selection first if you don’t It will mute the dac. (Doh!)

    I just got my rotary encoder in the mail. It’s the PEC11 4225F S0024 1703829.
    But it doesn’t work very well. Switching from 2 selections for example oversampling on or off is almost impossible. Even pressing the button or a little movement (not a click but just holding the shaft) has effect, and navigating is a hard job.

    Maybe it’s just a bad encoder. This version of the code has hardware debouching right? So no need for caps on the encoder.

    I still have a few questions:

    (1) Can you point me the a encoder on ebay that you would recommend?

    (2) Are you planning a code version that has support for the remote? So I can use it to change settings? The dac looks a lot nicer without a knob on the front I think, and the remote works extremely well!

    (3) How do I change the default volume to 00

    (4) Just a idea. If you ever going to make a new release, can you make a spare pin on the arduino high when the sample rate is higher then 44? It will make a nice HD audio led.

    Again thank you so much for your work and this site, its greatly appreciated

    • BlgGear
      August 18, 2014 at 02:08

      Very Nice. I am glad it works.
      You can try adding the capacitors to make the rotary encoder less noisy. I also have problems with some of the encoders. Sometimes the problem is the type of encoder. You can read more here:
      Encoders are cheap. $1 to $3. order a few suitable ones from different vendors. I think even within a brand you can find good ones and bad ones.
      Regarding the remote, I don’t have plans. Everyone has different desires for the different buttons. So a minimal function (volume) is enabled.
      The default volume can be changed by changing “#define DEFAULTATTNU 0x64” for zero, set to 0.

  78. August 18, 2014 at 20:37

    One thing I was never sure about is the input selection in the code and how it ties into the Arduino hardware (sorry, not a programmer). When selecting an input, does it trigger a +5V on the Arduino headers? How does the logic works. Thanks for the help on this.

    • sebastian
      August 18, 2014 at 20:43

      The software inside arduino writes data into the registers of the es9018, changing the inputs of the chip. It does this using two I2C lines.

  79. August 18, 2014 at 22:33

    ok, so I guess it has no effects on the BII, just the BIII would work with this?

    • BlgGear
      August 19, 2014 at 00:25

      If you use the code for the BII, and you have the option to select I2S or SPDIF through a mechanical switch, you will still need to make the selection in the registers because input selection is set to manual mode.

  80. Derek
    September 21, 2014 at 02:30

    When playing a playlist that includes different sample rate tracks the volume jumps every time a song with a different sample rate to the previous song starts. You have to move the rotary encoder or use the remote to reduce volume. Using the diyinhk K2M.

    Is there a way to prevent this in the code? Maybe set volume to 0 initially so there’s no provision for volume increase?

    It’s similar to the startup issue – which I understand is not solveable in code as the microcontroller starts after the DAC. Although, on startup, I find the music does not reduce in volume unless I move the encoder or the remote. I’d have thought that the muteDAC command should mute the DAC very shortly after.

    • BlgGear
      September 21, 2014 at 23:41

      First congrats on porting the s/w to the Arduino Pro. The problem you’ve reported is very odd. In order for the volume to change, new values have to be written in the registers. It does not matter whether you start with zero volume or other volume level. During start up if the if the microcontroller starts after the DAC, then it can program the registers. If the microcontroller starts before the DAC is ready, then it cannot program the registers because the DAC cannot respond.

      Sometimes this problem happens if your rotary encoder is noisy or it is “stuck” at some state: it may be generating so many interrupts that the microprocessor cannot do anything else. Try disconnecting the rotary encoder to see if it solves the problem

      • Derek
        September 22, 2014 at 12:53

        Thanks for the quick response. Will try disconnecting the rotary encoder (the Alps in your photo) later this evening and let you know. Meanwhile, could it be the diyinhk XMOS board reprogramming the DAC when it gets the change of sample rate from the Alix? Will also try changing some of the mpd.conf device settings in the Alix.

  81. Derek
    September 22, 2014 at 22:56

    No joy with the rotary encoder completely disconnected – still goes to full volume any time the sample rate changes.

    Also tried disabling the mixer in Voyage MPD on the assumption that the USB XMOS board could be writing to the DAC’s volume registers. Did not stop the issue. Which is not to say that the diyinhk board isn’t writing to the volume register on a sample rate change.

    • BlgGear
      September 23, 2014 at 00:42

      So there is a chip reset whenever there is a sample rate change. Let me take a look at the datasheet.
      The board itself cannot program the volume. It is likely a chip-level thing…

      • Derek
        September 24, 2014 at 12:06

        Above my pay grade! Hope you get it sorted soon as I really like this interface – had hours of fun and learnt a lot putting it together. And please let us know the details, it’s great to see a DIY’er making this available to us tinkerers.

      • BlgGear
        September 24, 2014 at 21:08

        Well, I tested my setup and I don’t experience any change in volume when switching sample rates. I’ve tried up to 384K. Also checked the datasheet and I cannot find anything in the register definition that would cause a change/reset in volume. I am using an Amanero for I2S. I think you are using the XMOS. Is this the version with volume control?

  82. Derek
    September 25, 2014 at 01:37

    Yes, it is the version with volume control; part of the ‘kit’ that included the K2M and the reworked XMOS firmware. Must be their volume control firmware doing the chip reset. I tried removing the I2C lines from the XMOS board to the DAC last night, figuring it had to be something linked to the diyinhk USB board but of course that caused other issues.

    If there isn’t a workaround I guess I need to acquire a ‘standard’ XMOS board. What do you suggest?

    • BlgGear
      September 25, 2014 at 18:16

      That is likely the problem. Both the Xmos and the Arduino are bus masters, and the code on either side is not designed to accommodate multiple masters. I would suggest you get an interface that can also handle DSD.

      • Derek
        September 26, 2014 at 16:07

        Thanks, yes, considering the diyinhk isolated version without the firmware mod, says it does DSD and DXD.

        Further my education a little here – how does the K2M ‘know’ it is receiving DSD? I assume that when a file arrives at the USB board in native .dsf or .dff as against DoP the DAC needs to be set for DSD input. Is this automatic on the K2M? The diyinhk site speaks of switching the I2S pins to DSD left, right and clock for DSD signals. How is that achieved?

      • BlgGear
        September 29, 2014 at 17:22

        The good thing about the ESS DACs is that they use the same pins for PCM and DSD, thus there is no need to switch to different input pins when you get DSD. The detection is therefore automatic. One can optionally set the mode to DSD or PCM and force the DAC to behave in one or the other mode. Some other DACs use different pins for PCM (I2S) and DSD forcing you to switch pins when the format changes.

  83. Derek
    September 29, 2014 at 18:45

    Thanks for the explanation – I guess it’s therefore best to leave your interface in the I2S/DSD input mode. I asked diyinhk if they had a solution to the dual master on the bus issue and they essentially said it was possible to have the I2S bus ‘hold’ the other master but it was beyond their scope. They gave me this link – which was interesting reading.

    On to something completely different (to mangle Monty Python) but related to Hifiduino – I have put my name down for one of these DACs –
    Although Soren mentions digital volume control he does not mention remote volume control via something like the aluminum Apple – could your ESS project be ported to his DAC? With the FPGA the filter options might be a moving target but would the basic remote volume control, at least, be doable? Along with the rotary encoder and display?

    • BlgGear
      September 29, 2014 at 19:39

      I am thinking of getting one of those DACs too. How much can it be controlled by a microprocessor, it depends on how much functionality it exposes to the outside.

      Regarding the multimaster issue, both sides need code revision to allow another master in the bus. Even if I add code to handle another master on the bus, the other side will not behave properly resulting in unexpected results.

  84. Derek
    September 30, 2014 at 00:03

    I wonder if it’s worth mentioning a possible interface on his thread? Suspect he won’t be averse to making his registers public but, as you say, it depends on whether he makes access possible. Maybe a query might spur him to bring the pins out.

    Re the multi master, I have asked them if there’s a workaround – due diligence but from my limited understanding I suspect I will just have to bite the wallet and get the isolated, non-modified board – can’t have your work crippled!

    • BlgGear
      September 30, 2014 at 01:41

      Re-reading the thread at diyaudio, it shows the DAC already has a microprocessor, so it can do “many things” like volume control, remote control, etc.

  85. Derek
    September 30, 2014 at 01:50

    Game on, then! A future project – would be quite a package if that DAC lives up to expectations.

  86. September 30, 2014 at 01:58

    Some advice – I use fully differential Class D amps and would like to try a balanced I/V stage with the K2M to output to XLRs. Do you recommend the TPA Legato or Ivy III? Or something else?

  87. November 1, 2014 at 21:29

    Update. Got the Isolated DSD/DXD board from diyinhk. As expected, it solved the loud volume/reset issue – it will now transition from differing sample rates with no issues. However, an odd issue has arisen. After a few minutes the microcontroller seems to freeze. The sample rate display above the volume disappears as does the I2S/PCM readout to the left of the sample rate display. The rotary encoder and remote no longer work. Music continues but there is no volume control possible. A reset brings everything back up but a few minutes later it ‘freezes’ again.

    I removed the SDA, SCL, RESET, DSD On and MUTE pins from the 20-pin USB board as per the diyinhk instructions. The isolated side is powered from the DAC 3.3V pin and there is 5V from the Alix USB output. Curiously, if I remove the ribbon cable from the USB board ( no connection between USB-to-I2S board and the K2M) then the microcontroller does not freeze.

    Power issue? Noise?

    • BlgGear
      November 3, 2014 at 07:06

      Try using individual wires to connect the USB board with the DAC board. There are only 4 wires to worry about: Bitclock, LRclock, DATA and GND.

  88. November 4, 2014 at 13:03

    Tried jumpering LRCK, BCK, Data, GND and the 3v3. That seems to have solved the freezing issue but now DSD files won’t play. The USB board’s LED as well as mPod indicate the DSD file is playing but the microcontroller indicates No Lock.

    Have tried using different GND pins on the DAC without result. Is there some sort of DSD indication required by the K2M?

    • BlgGear
      November 4, 2014 at 17:18

      Should play without any “DSD indication”. Try toggle the input type (“Auto”, “I2s/dsd”) in the controller. But it used to play before with the ribbon cable?

  89. November 6, 2014 at 01:15

    Some progress. Benchmarked it using the older ‘modified for volume control’ USB board with their 20-pin ribbon cable. Worked flawlessly except for the established chip reset/jump in volume on sample rate change issue. DSD played perfectly as did other sample rates and no microprocessor freezing.

    Using the isolated USB board (with the SDA, SCL, Reset, DSD On and Mute pins removed) and the same 20-pin ribbon cable the microprocessor froze regularly and DSD files constantly ‘skipped’ or dropped out momentarily.

    Using jumpers on LRCK, BCK, Data, GND and one of the 3v3 pins the freezing issue is solved but no DSD. All other sample rates play fine. On adding individual jumpers to the adjacent ground pins to LRCK, BCK and the second GND pin next to the Data pins, DSD will play but it suffers the constant dropouts above.

    If, while playing a DSD file, I momentarily do a reset by grounding the Reset pin on the K2M board the dropout issue improves – now it will only skip occasionally, maybe once or twice per song.

    If I disconnect the microcontroller from the K2M then the isolated board/K2M combo functions properly, no dropouts on DSD files. But I don’t wish to use an outboard volume control, I’m hooked on this Hifiduino implementation!!

    A somewhat curious aside – I cut out all but the eight wires described above from a spare 20-pin ribbon cable so it is essentially exactly the same as the 3″ jumper cables but shorter. With this ribbon cable it simply will not play DSD. Everything else functions normally.

    Next I thought of trying a separate 3v3 power supply for the isolated USB board on the assumption that maybe the isolated USB board draws significantly more current than the non-isolated modified-for-volume-control board – which has no issues with DSD files.

    • BlgGear
      November 6, 2014 at 02:17

      Some progress. Benchmarked it using the older ‘modified for volume control’ USB board with their 20-pin ribbon cable. Worked flawlessly except for the established chip reset/jump in volume on sample rate change issue. DSD played perfectly as did other sample rates and no microprocessor freezing.


      Using the isolated USB board (with the SDA, SCL, Reset, DSD On and Mute pins removed) and the same 20-pin ribbon cable the microprocessor froze regularly and DSD files constantly ‘skipped’ or dropped out momentarily.

      Using jumpers on LRCK, BCK, Data, GND and one of the 3v3 pins the freezing issue is solved but no DSD. All other sample rates play fine. On adding individual jumpers to the adjacent ground pins to LRCK, BCK and the second GND pin next to the Data pins, DSD will play but it suffers the constant dropouts above.

      Try this:
      – Move the I2C wires away from the I2S wires
      – Use twisted pairs for all the I2S signal wires (twist with a ground wire)
      – Adjust the dpll size for DSD. Larger size resolves drops. Try using the default values for both PCM and DSD.

      If, while playing a DSD file, I momentarily do a reset by grounding the Reset pin on the K2M board the dropout issue improves – now it will only skip occasionally, maybe once or twice per song.

      See above recommendation

      If I disconnect the microcontroller from the K2M then the isolated board/K2M combo functions properly, no dropouts on DSD files. But I don’t wish to use an outboard volume control, I’m hooked on this Hifiduino implementation!!

      Did you power cycle the DAC when you disconnected the microcontroller? If so, then when the DAC power up without the microcontroller, the registers start with a default value including default values for dpll and full volume.

      A somewhat curious aside – I cut out all but the eight wires described above from a spare 20-pin ribbon cable so it is essentially exactly the same as the 3″ jumper cables but shorter. With this ribbon cable it simply will not play DSD. Everything else functions normally.

      – Check the dpll setting for DSD

      Next I thought of trying a separate 3v3 power supply for the isolated USB board on the assumption that maybe the isolated USB board draws significantly more current than the non-isolated modified-for-volume-control board – which has no issues with DSD files.

      – Good idea…

  90. November 7, 2014 at 00:34

    It was the DSD dpll. Thank you for your help – much appreciated. I had both the PCM and DSD dpll set at 002. As soon as I set the DSD to Default all the dropouts disappeared and DSD files played perfectly. I guess I need to read more about the effects of these settings. All now works fine so long as I use 3″ jumpers between the two boards!!

    It still will not play DSD with any kind of ribbon cable. I made a 1/4″ long 10-pin ribbon cable, I tried the standard 20-pin that diyinhk sell and I tried a 10-pin version of the diyinhk ribbon cable. None will play DSD and all freeze the microcontroller after varying amounts of time. I would love to know why! Only thing I can think of is some sort of break in contact when a ribbon connector is pushed on? I went over all the pin solder joints and all seemed fine.

    I shall continue to mess with different i2s connectors but at least it now works as intended. The isolated diyinhk board is noticeably better than the modified-volume board sound quality-wise.

    Next I shall try coding an analog pin (all I have left) on the Pro Trinket to sink the backlight via a 2222 transistor so as to activate the LCD for a few seconds if the rotary encoder or remote are used – otherwise leaving it with no backlight or off. I shall beg help if I can’t get it done, if I may.

    Then I might try putting the Pascal amp module into standby via the remote and another analog pin. Fun, this microcontroller thing.

    Once again, thanks for all your help.

    • BlgGear
      November 7, 2014 at 17:45

      Good to hear.
      The DPLL is used to “reject jitter”. The smallest number rejects the most jitter, but at some point it will fail to synch to the signal.
      It is a mystery why the cabling would create so many problems. Keep us updated on your findings.
      Good luck!

  91. Anonymous
    February 26, 2015 at 12:28

    Do you have code to use apple remote control like function selector

    • BlgGear
      February 26, 2015 at 15:16

      Not really. The code infrastructure will support all the buttons you add the code to the function whatever that may be. The comments and other reference to the Apple remote will provide all the needed information.

  92. June 23, 2015 at 14:33

    I may end up using one function (see from your code in a commercial project. What do you consider appropriate attribution for this case?

    • BlgGear
      June 23, 2015 at 14:42

      That is good enough.

    • BlgGear
      June 23, 2015 at 15:15

      Actually, I put the cc license because people asked me about using the code. So I used the most permissive cc license I could find. You are the first to ask what is appropriate…

  93. baek47
    September 6, 2015 at 18:03

    Thx for very good work. Im running BIII with code b11f – incl. “smart switching” between is2 and spdif7. Very happy. In the code I have reduced ICHO to 2, put default volume to 0 dB and other small issue. But can you help / clue how to costumize inputformat, ex. so that I can have two spd7 one with jitter bypass and one without. Which section to put it into, and “format” of “statements”.

    • BlgGear
      September 7, 2015 at 02:00

      The way it is designed is that the input choices are all “virtual” so that any input can vary any or none of the available settings (any input can have any arbitrary setting). You can for example define two inputs that are exactly the same except for name, and thus you can have two inputs that are exactly the same except for the jitter bypass setting. Once you make the setting selection, it is saved to eeprom.

  94. baek47
    September 8, 2015 at 19:21

    IT works…great. Thank you so much!

  95. Derek
    May 16, 2016 at 15:18

    I have been happily using your Apple Remote code along with chunks of DimDim’s OLED code to run the DAM1021. After many hours of programming (fun) it runs flawlessly. I was using the old 1.06 IDE for programming, compiling and upload.

    Recently I updated to the 1.6.9 IDE and the code compiles and uploads to the same Arduino as before but the repeat function on the volume up and volume down (case 5 and 6) doesn’t work – you can’t hold down those buttons and have the volume continuously go up or down. All else works as before. Have you come across this?

    I’ve tried substituting your ‘any Apple remote’ code with DimDim’s version (which requires learning the particular remote’s output for each button) and that compiles and runs as it should using 1.6.9. Odd. Any ideas?

    • BlgGear
      July 4, 2016 at 17:42

      Sorry, haven’t had the time to test the code with newer IDE.

  96. WT
    September 4, 2016 at 04:21

    I have been using your Hifiduino code for my buffalo 32s dac for a long time. I would like to move it to nicer box, but that box only accept lcd 1602 size. Is there a version for 16×2 lcd?

  97. September 14, 2016 at 15:13

    tampa search engine optimization

  98. September 14, 2016 at 16:49

    Aspergers Quiz

  99. September 14, 2016 at 17:53

    mega millions winners

  100. September 14, 2016 at 18:47

    harrisburg dui attorney

  101. Elvin Mcfarland
    October 19, 2016 at 15:46

    Helpful ideas . Apropos , if someone wants a CA DMV REG 17 , We encountered a template document here

  102. Bernard
    December 7, 2016 at 21:14

    Does an i2c controler than has been programmed for es9018 has a chance to (partially ?) work with a es9018k2m chip ?

  103. Johan
    December 19, 2017 at 10:36

    What shall I expect on LCD if no I2C/ESS board connected?

    • Johan
      December 19, 2017 at 18:14

      With 1k between LCD pin 1 (GND) and pin 3 (V0) I get good screen. Without I cant see anything.

  104. April 26, 2018 at 05:17

    Truly lots of great knowledge!

  105. April 26, 2018 at 10:04

    You said it perfectly. dating a single mom!

  106. April 27, 2018 at 19:28

    Truly a lot of excellent material single moms .

  107. April 29, 2018 at 14:51

    This is nicely put! single mom dating site!

  108. wchpikus
    May 23, 2018 at 16:29

    I change this code a little to arduino nano.
    Great job!
    Could you tell me, auto setup detecting i2s format also?
    I have board dac from aliexpress with i2s input and i trying setup this es.
    My format i2s ,left or right justified,20bits or 16.
    Did you test this software with i2s line?

    • Calixto E Deveza
      July 11, 2019 at 21:42

      Does anybody have a new code for the buffaloIIIse Pro? I would greatly appreciate it.

  109. Anonymous
    May 26, 2018 at 18:40

    i tested all code for ES9018K2M, i have correct communication (selealogic analizer), but i can not setup any format for cooperate with wt32 bluethooth chip..

    • wchpikus
      May 27, 2018 at 21:37

      Tested pinout, something is wrong with init es chip.
      I have no “lock” but pll shows some value..strange.
      Please tell me how i should setup es to 3 lines i2s?

  110. Calixto E Deveza
    July 10, 2019 at 04:34

    Can someone help, I could not download any old sketch!!

  1. June 3, 2011 at 07:50
  2. June 6, 2011 at 17:02
  3. June 10, 2011 at 00:42
  4. July 20, 2011 at 06:49
  5. August 24, 2011 at 07:18
  6. October 19, 2011 at 19:39
  7. January 9, 2012 at 07:44
  8. November 12, 2012 at 06:29
  9. November 28, 2012 at 06:59
  10. December 14, 2013 at 09:11
  11. June 13, 2014 at 15:57
  12. March 6, 2015 at 07:05

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