Home > Arduino, Code > New Version of HifiDuino Code for Sabre32 DAC

New Version of HifiDuino Code for Sabre32 DAC

November 28, 2012 Leave a comment Go to comments

Update (11/28/12): I removed version B1.1c because the “optimized” volume control proved to be unreliable. Sometimes coming up at full blast. I reverted to the old volume control in version B1.1d
Sorry about that.

Version B1.1d [link]


I released the first version of the code over two years ago. Along the way, I’ve added features, fixed bugs and optimized the code.  It is good to see Hifiduino code used all over the world and I find satisfaction in that🙂

Luckily (and unlike commercial ventures like Windows :-)), I don’t feel the need to overhaul the code but on the contrary, I think every version, including this one has moved the software to a more mature state in terms of functionality, efficiency and reliability.

Yes, the code can be more “elegant” following a more “professional” style, but I am not a professional coder and getting there takes time and experience. To mitigate that, I’ve extensively commented the code so that anyone can follow how the code works.

Further, the code is not “just code”. As many know, the ESS datasheet is very brief in its information. In certain areas, experimentation was required in order to figure out how to program the registers. Another example is the code for the Apple remote. There is no datasheet you can download; it required experimentation and the charity of a reader who volunteered some critical information unavailable anywhere else.

I feel proud that I’ve accomplished this much, and would like to thank everyone that has been following this blog and using the software. Especial thanks to those that have reported bugs and contributed information. It is no fun just having it for myself🙂



EEPROM writing routine

Thanks to Mr. Corpius, (check out his blog: [link]) I reviewed the writing routine to the EEPROM and changed it to only write if there is a change in the value. This will somewhat help the longevity of the EEPROM. (See below for more information on the EEPROM life)

Sample rate display format

In the last version I changed the sample rate format from an “exact” value (for example “44099”) to a “nominal” value (example, 44.1KHz). But I miss the “exact” value. I’ve added an option to either display the exact sample rate or the nominal sample rate. This option can be selected at anytime just like the other settings and it is saved in EEPROM

Sample rate calculation accuracy

The calculation of the sample rate is based on the formula given in the datasheet on the value of the DPLL number. I had used integer operation in order to speed up and simplified the operation.

In order to verity its accuracy, I have monitored the actual value of the DPLL number for different sample rates, made the calculation “on paper” and compared that with the integer calculation in the code. I found that depending on the sample rate, the integer calculated sample rate is  off between 1 Hz to 4 Hz. This is due to the error in the integer factor and to truncation of remainder in the integer operation. I have added this “correction number” to the code and the resultant sample rate is now closer to the real value.

When you see 44100, you can be assured that the actual frequency seen by the DPLL is indeed 44100 Hz (within the frequency accuracy of the on-board Crystek clock which is used as reference)

Input selection choices

In order to support the “smart wiring” configuration for Buffalo III, I’ve added input choices for SPDIF #3, #7 and #8. I’ve also change the selection of I2S, LJ and RJ choices to match the choices available in the Buffalo III SE DAC namely: I2S (32 bit), LJ (32 bit), RJ (32bit, 24 bit, 20 bit and 16 bit).

New options with Buffalo II:

If you are using Buffalo II, then the new SPDIF selections would not do anything ass these inputs are grounded in the BII implementation. The only choice is to use the “SPd” option which connects to input 1.

Prime DPLL

Up to now, the code would “prime” the DPLL when it first locks to a signal. “Priming” of the DPLL consisted in cycling the DPLL through the different bandwidth settings with the hope of reducing the number of unlocks that are experienced with the narrower values of the DPLL bandwidth.

Experienced has shown that unlocks are due to other factors such as warm-up of the oscillators after power-on, external noise and other factors, and thus this function probably served little or no purpose. For this reason, I’ve removed the use of this function from the code.

User Interface tweaks

Moved the oversampling filter indicator one line lower to give more space for sample rate display. With DSD, the sample rate is now 7 digits.

When entering select mode, you will immediately see the settings for input format and sample rate display format. Upon exiting, the input format display will revert to displaying the actual input format (DSD, PCM, SPD or SP<-, SE<-) indicating the type of data stream received or the input format setting if there is no signal. The sample rate format will reset to displaying the actual sample rate.

Volume adjustment routine

(Update 11/28/12). This “enhancement” proved unreliable. I’ve reverted to the “Before” way of adjusting the volume in version 1.1d. I’ve deleted the version where I “improved” the code.

Rewrote the I2C volume adjustment routine by taking advantage of repeated writes to the 8 volume registers without releasing the bus. This only works in Arduino if the registers are in sequential addressed starting from the first address. Functionally, this is the same, but a bit faster.

// etc...

Improved code:

// etc...

(This "improved" code proved to be unreliable...)

Remote control bug

Fixed a bug that prevented the repeat of keys from the remote. By default, all keys from the remote are treated as non-repeating unless explicitly specified. When you hold down a key in the Apple remote, after the first command byte, the next command byte is a generic “repeat” value. The code recognizes the repeat key only for keys that are specified as “repeat”.

When I changed the control byte from 8 bits to 7 bits, I forgot to change the values to the new values of those keys.

Code and comments clean-up

Minor code clean-up.  Also reviewed the comments and clarified where needed.

Support for other Sabre32 based DACs

No code has been changed, but based on compatibility with BIII as indicated in this post [link], this code can be used in other Sabre32-based DACs.


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.


The eeprom in Arduino is used to store all the DAC settings that are assigned for a particular input. The default configuration of the code has 6 selectable input configuration, each having its own set of DAC parameters (such as FIR setting, DPLL setting, etc). In total, with this default configuration, there are 49 values that are stored in the EEPROM.

The life of the EEPROM for the ATMEL chip in Arduino is specified at 100,000 writes per cell [link].  Keep in mind that the lifetime is per memory cell, so even if writing 49 values, it counts as one “write cycle” because the 49 values are written into different cells. One experiment showed failure after over one million “write cycle” operations [link].

Operation of code

The current version of the code will write all the parameters every time you exit the select mode. In order to make an input selection or to change any parameter, you enter the select mode. Thus every entry into the select mode constitutes one write cycle.

Lets say you are are an audiophile and also enjoy tweaking your system speinding a lot of time listening to sound artifacts.

Lets say on average, during your listening and tweaking sessions, you make say 100 difference parameter adjustments or input selections. For example you may want to test DPLL settings or do an A-B comparison between two sources. Each of these count as one write cycle to the eeprom

In such situation the EEPROM will “last” 100,000/100=1000 days. If you do this every other day, then effectively you have a minimum life span of 5.5 years. Even if you do this every day, the minimum life is 2.7 years based on the datasheet value. If we use experimental data, the life span can be as long as 10x the specified value.

  1. David Quayle
    November 28, 2012 at 09:14

    I have no idea where you get all the time and energy to do all this, you are a legend. I have trouble just keeping up.
    Many thanks

    • BlgGear
      November 28, 2012 at 17:01

      You are welcome. I can code while listening to music🙂

  2. Martin
    November 29, 2012 at 03:23

    Hey BG,

    I took a look at the code… Wondered if you’d thought of hosting it on GitHub or such, and canvassed for others to contribute?

    Great work – I’m looking forward to trying it out in the near future.

    • BlgGear
      November 29, 2012 at 08:19

      No, I didn’t think of hosting it. Others are already taking a version and customizing it to their own needs.

  3. K Y Chan
    November 29, 2012 at 13:03

    Thanks a lot for your effort and contribution, you are a real DIY GURU

  4. November 29, 2012 at 14:53

    Great work! It’s all trial and error. I know exactly what you mean when you say it takes time and experience🙂 I’m also not a programmer by trade, but when you’re persevering you can achieve a lot. You proved that already!

    I prefer the use nominal sample rate. I can’t read it anyway from my sofa, but imo it’s a lot clearer than the exact sample rates.
    At the moment I’m busy writing some code to change the input names by using the remote. My old Linn pre-amp also has this feature which I like to have for my DAC as well.

    • BlgGear
      November 29, 2012 at 19:43

      Hi Corpius. I guessed WordPress learned that you are not a spammer🙂. I actually prefer the actual sample rate. (So I guess even here there is individual preferences :-))

      I see you like “learning code”. That could take a lot of code. How big is your compiled size now? My original goal was to fit in the Atmel 168, but I just blew that.

      • November 30, 2012 at 07:03

        The code for changing the input names doesn’t take that much programming space. Each character corresponds with a byte, so you only have to keep track of the 6 characters of each input. I`m have 6 inputs, so the code keeps track of 36 bytes. The code for it are just a few lines.

        To answer your question: my code size is almost 29 kb, but still growing. This is without the ir learn function. This function alone takes almost 28 kb ( including the library). I`ll add this later on as I not fully satisfied with it

      • BlgGear
        November 30, 2012 at 21:40

        Hmmm, you are right. “learning code” is just displaying the letters one at a time and then remember the selected one. Regarding the size of your code, it is getting close to the limit of the size of the 328 chip. If you add the remote code then you will need a Mega class Arduino.

  5. Anonymous
    November 29, 2012 at 19:00

    s this code works fine for bii 80mhrz dac?. Thanks for your effort, you are the best!

    • BlgGear
      November 29, 2012 at 19:44

      Yes, especially for the BII-80 because that is what I use to test it.🙂

  6. December 1, 2012 at 01:20

    For my controller protype I’m using a ATmega644. This has double the programming space of a 328. I know it’s a very large chip, but my smd skills have to get some more developed.
    The pin spacinging of the ATmega644 is 2.54mm, so no problems with soldering it.. 🙂

    I’d love to use a more advanced microchip, but when this proves to be enough for me and what my dac needs, why bothering to get any better. Not to forget, your code already gives access to the most important settings.

  7. wktk_smile
    December 19, 2012 at 10:39

    Minor bug on b11d.

    else {
    bitSet (reg17L,5);
    #ifdef DUALMONO
    bitSet (reg17R,5);
    bitClear(reg17L,5); // “reg17L” should be “reg17R” here.
    writeSabreLeftReg(0x11,reg17L); // “Left” should be “Right”, “reg17L” should be “reg17R”
    #endif DUALMONO

    • BlgGear
      December 19, 2012 at 16:55

      Hi, thank you so much… Will revise in the next version. Don’t have dual mono to test, but should have done code review in the first place…

  8. Anonymous
    January 12, 2013 at 08:47

    I just upload new code but on my boot screen still show B.1.1c.
    When I play DSD on my screen shows UNKNOWN sample rate in NOMINALmode and in EXACT mode shows 2257920. Is that OK?

    • BlgGear
      January 12, 2013 at 16:49

      I forgot to change the version number🙂
      The frequency of DSD is off. It should be near 44.1×64 or 2.8224 MHz. This is why in “nominal” it says unknown because it is “not close” to what is supposed to be. Now, I don’t know why your frequency is so off the mark. What are you using to play DSD?

  9. Anonymous
    January 12, 2013 at 16:55

    I’m using Amanero with foobar2000, PC with Winows 7.

    • BlgGear
      January 12, 2013 at 17:58

      Adjust the code for 100 MHz operation. Look at the code page or the code itself for how to do it. The code default is 80 MHz because that is the version I have to test🙂

  10. Anonymous
    January 12, 2013 at 18:33

    That was a problem😉
    Now it works!

  11. Anonymous
    February 16, 2013 at 08:32

    It will be great to implement this solution in future new code:
    It allows you to have both a SPDIF and I2S source connected and using Arduino we can switch between them using the on-board IP_S pins.

  12. February 17, 2013 at 08:48

    Anonymous :
    It will be great to implement this solution in future new code:
    It allows you to have both a SPDIF and I2S source connected and using Arduino we can switch between them using the on-board IP_S pins.

    I’m offering this option too in my code. Only need to set the code once for the BIIISE in the configuration section of the code. This will automatically activate all parts of the code used for switching between S/PDIF and I2S by pulling IP_S low or high. Here is is:

    • BlgGear
      February 17, 2013 at 22:02

      Good to know guys, thanks…

  13. David Quayle
    March 5, 2013 at 21:13

    I’ve read the answer somewhere but for the life of me I cannot find it. Do you know what the DIP (on the actual board) switches should be set to if using an external controller, I am using the BIIISE.

  14. March 5, 2013 at 21:34

    It doesn’t matter how you set them. Just make sure to remove the firmware chip. When the chip is removed the DIP switches have no function anymore🙂

    • BlgGear
      March 7, 2013 at 19:01

      Yeah, the switches can only be understood by the on-board microprocessor. I think the switches connect to an I/O expander and the I/O expander connect to some input pins in the on-board microprocessor. If you use external micro, then it will not know the existence of the switches since the only connection to the board are the two I2C lines.

  15. David Quayle
    March 5, 2013 at 23:49

    Thanks will do, I was sure I read somewhere they had to be switch to one side or the other, I must have misunderstood.

  16. September 14, 2016 at 16:18

    como divulgar loja virtual

  17. September 14, 2016 at 17:16

    sterling silver jewellery

  18. September 14, 2016 at 17:20

    top cubans

  19. September 14, 2016 at 18:46

    Fani na facebooku

  20. September 14, 2016 at 18:55

    electrician orange county ca

  21. September 14, 2016 at 19:17

    Shaahin Cheyene

  1. No trackbacks yet.

Leave a Reply

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

WordPress.com Logo

You are commenting using your WordPress.com 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 )

Google+ photo

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

Connecting to %s