New Version of HifiDuino Code for Sabre32 DAC
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.
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.
Wire.beginTransmission(); Wire.write(); Wire.write(); Wire.endTransmission(); Wire.beginTransmission(); Wire.write(); Wire.write(); Wire.endTransmission(); Wire.beginTransmission(); Wire.write(); Wire.write(); Wire.endTransmission(); // etc...
Improved code: Wire.beginTransmission(); Wire.write(); Wire.write(); Wire.write(); Wire.write(); // etc... Wire.endTransmission(); (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:
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.
KILLING THE ARDUINO EEPROM?
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.