v B021 (Cleaned Up the code for v B02)   Leave a comment

/***************************************************************************************************
 * HIFIDUINO v. B021
 * 
 * October 15, 2010
 * Arduino code for Buffalo II DAC and other DACs based on the Sabre32 DAC chip. This code is adapted
 * from an earlier version developed for the Wolfson 8741 DAC chip. For more information visit
 * www.hifiduino.wordpress.com or www.hifiduino.blogspot.com
 * 
 * Although this code is based on a confidential data sheet for which I've signed an NDA, I've also
 * requested and have received permission to publish this code.
 * 
 * Change log:
 * v. B01  10/11/10: Volume control, LCD, Rotary Encoder
 * v. B02  10/15/10: Added reading of sample rate
 * v. B021 10/18/10: No new functionality, but cleaned up the code and comments
 ***************************************************************************************************/

// LIBRARIES

#include <LiquidCrystal.h>  // For LCD
// Initialize the library with the numbers of the interface pins
  LiquidCrystal lcd(12, 11, 10, 9, 8, 7);
#include <Wire.h> // For I2C

// CONSTANT DEFINITION

// (The digital volume for Sabre32 is 0 to -127 db in .5 db steps)

#define DEFAULTVOL 0x64 //-50 dB this is 50x2=100 or 0x64
#define MINVOL 0xC6     //-99dB this is 99X2=198 or 0xC6
#define MAXVOL 0x00     //-0 dB
#define DIMVOL 0x3C     //-60dB The volume level when dimming the volume

#define VOLUPPIN 4      // Button to increase  volume or RotEnc A terminal
#define VOLDOWNPIN 2    // Button to decrease volume or RotEnc B terminal

#define INTERVAL 2      // Time interval in seconds for doing something like reading the sample rate

// GLOBAL VARIABLE DECLARATION

byte regVal; // Variable to pass register value
byte regAddr; // Variable to pass register value
byte currVol=DEFAULTVOL; // Variable to hold the current volume value
unsigned long previousMillis = 0; // Stores last recorded time

/* 
 LCD
 
 For the LCD, I am using a "standard" HD44780 20x4 display, and I am using the official Arduino
 LiquidCrystal library that comes with the standard installation. This is as standard as it can be
 and this type of LCD is available everywhere
 
 The pin assignment is different from the example code and it is as follows:
 
 * LCD RS pin to digital pin 12
 * LCD Enable pin to digital pin 11
 * LCD D4 pin to digital pin 10
 * LCD D5 pin to digital pin 9
 * LCD D6 pin to digital pin 8
 * LCD D7 pin to digital pin 7
 */

/*
ROTARY ENCODER
 
 The rotary encoder is connected to pins 2 (A) and pin 4 (B). It does not matter which terminal
 is connected to which pin. The third terminal is connected to GND. At each cycle, the rotary
 encoder will pull the pins LOW and the transition is detected (an interrupt is generated). It is
 then compared with the level in the other pin. The interrupt service routine is specified below.
 
 Debouncing
 For this code to work, the rotary encoder is "debounced" by installing capacitors between the
 signal pins an GND in order to minimize the noise generated by the mechanical switches of the
 rotary encoder. Without this "debouncing", spurious readings will make the volume jump several clicks.
 If an optical rotary encoder or a high quality encoder is used, this modification may not be
 needed. The rotary encoder used here is a low cost model ($1.00) and requires the installation of
 the capacitors.
 
 INTERRUPT SERVICE ROUTINE
 It is used to determines direction. The code displays volume attenuation, so if the value increased,
 there is more attenuation and the volume level goes down. This is counter clockwise motion in the
 rotary encoder. Likewise if the value decreases, there is less attenuation and the volume level goes
 up. This is clockwise direction
 */

volatile boolean attenuUp=false;  // flag to indicate more attenuation or counter clockwise motion
volatile boolean attenuDown=false; // flag to indicate less attenuation or clockwise motion

void rotEncoder()
{
  if (digitalRead(2) == digitalRead(4))
  {
    attenuUp = true;  //if on interrupt the encoder channels are the same, direction is CCW
  }
  else
  {
    attenuDown = true;  //if they are not the same, direction is CW
  }
}

/*
READING THE SAMPLE RATE
 
 The sample rate can be calculated by reading the registers of the 32 bit DPLL value.
 For SPDIF this value is divided by (2^32/Crystal-Frequency). In Buffalo II, the Crystal
 frequency is 80,000,000 Hz.
 
 In Arduino (and other small microprocessors) it is NOT advisable to do floating point math because
 "it is very slow"; therefore we will use interger math to calculate the sample rate.
 
 In order to increase the accuracy of the integer calculation, I did some evaluation of the DPLL
 register values for sample rates ranging from 44.1K to 192K. I noticed that I could multiply the
 value of the DPLL number by up to 400 without overflowing the 32-bits.
 
 The value of 2^32/80000000 is 53.687091 (which is a floating point number). If we use the integer 
 part (53 or 54) we will have an error in the calculation. For example, if we divide the DPLL number
 for a 44.1K sample rate signal by 53, the resultant values would be 44.677K and 43.849K if divided 
 by 54.
 
 If we divide by the actual number 53.687091, then we obtain 44.105K (The 4 Hz deviation from ideal
 is within the SPDIF specification and crystal tolerances of the source signal). Clearly the integer
 math is not very accurate.
 
 However, since we have 32 bit number to work with, we can multiply the DPLL number by 400 and then
 divide by 400X53.687091=21475. If we do this, we obtain 44.105K which is within rounding off error
 of the exact value (the one using floating math)
 */

// Sample rate reading routines

volatile unsigned long DPLLNum; // Variable to hold DPLL value

byte readDPLL(byte regAddr)
{
  Wire.beginTransmission(0x48); // Hard coded the Sabre/Buffalo device  address
  Wire.send(regAddr); // Specify the DPLL register from which to read value
  Wire.endTransmission();
  Wire.requestFrom(0x48,1); // Hard coded to Buffalo, request from address specified with Wire.send()
  while(!Wire.available()) {
  } // Do nothing and wait for the data on the wire -if needed...
  return Wire.receive();
}
unsigned long sampleRate()
{
  DPLLNum=0;
  // Reading the 4 registers of DPLL one byte at a time
  // and stuffing into a single 32-bit number
  DPLLNum|=readDPLL(31);
  DPLLNum<<=8;
  DPLLNum|=readDPLL(30);
  DPLLNum<<=8;
  DPLLNum|=readDPLL(29);
  DPLLNum<<=8;
  DPLLNum|=readDPLL(28);
  // Calculating the sample rate for SPDIF
  DPLLNum*=400;
  DPLLNum/=21475;
  return DPLLNum;
}

/*
CONTROLLING THE DIGITAL ATTENUATION (VOLUME) IN THE DAC
 
 The device address of Sabre DAC Datasheet specifies the address as 0x90 which is an 8-bit value.
 The wire library in Arduino uses 7-bit device addresses and the 8th R/W bit is added automatically
 depending on whether you use the write call [beginTransmission()] or the read call [requestFrom()].
 Therefore, you will use the 7 most significant bits of the 8-bit address.
 In our example, 0x90 becomes 0x48 as follows:
 0x90: 0101000 (we eliminate the rightmost bit)
 0x48: 0010100
 */

void writeVolRegister(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
  Wire.endTransmission();
}

void setSabreVolume(byte regVal)
{
  writeVolRegister(0, regVal); // set up volume in DAC1
  writeVolRegister(1, regVal); // set up volume in DAC2
  writeVolRegister(2, regVal); // set up volume in DAC3
  writeVolRegister(3, regVal); // set up volume in DAC4
  writeVolRegister(4, regVal); // set up volume in DAC5
  writeVolRegister(5, regVal); // set up volume in DAC6
  writeVolRegister(6, regVal); // set up volume in DAC7
  writeVolRegister(7, regVal); // set up volume in DAC8
}

/*
PRINTING (DISPLAYING) THE VAVLUE OF VOLUME "NICELY FORMATTED"
 
 For now, it is hardcoded to print on line 3 (4th line) of the LCD. This routine takes in the actual
 value of the volume level and displays it with proper format in the LDC.
 */

void printVol(byte regVal)
{
  if (regVal==9) // transition between two digit and one digit display
  {
    lcd.setCursor(12,3);
    lcd.print("0 ");  // Add a leading zero
  }
  if (regVal<10) // two digit to one digit transistion, right justification
  {
    lcd.setCursor(13,3);
    lcd.print(regVal, DEC);
  }
  else
  {
    lcd.setCursor(12,3);
    lcd.print(regVal, DEC);
  }
}

/*************************MAIN PROGRAM*************************************************************/

void setup() {

  // Set up the LCD's number of columns and rows: 
  lcd.begin(20, 4);

  // Join the I2C bus as a master
  Wire.begin();

  // Attach Interrupts
  attachInterrupt(0, rotEncoder, CHANGE);  // ISR for rotary encoder

  // Set up the pin modes
  pinMode(VOLUPPIN, INPUT);       // Button or Encoder pin for volume up
  digitalWrite(VOLUPPIN, HIGH);   // Enable pull-up resistor

  pinMode(VOLDOWNPIN, INPUT);     // Button or Encoder pin for volume down
  digitalWrite(VOLDOWNPIN, HIGH); // Enable pull-down resistor    

  // Print the welcome message and other labels to the LCD

  lcd.setCursor(0,1);
  lcd.print("BUFFALO CONTROL v0.2");
  lcd.setCursor(0,2);
  lcd.print("Sample Rate: ");
  lcd.setCursor(0,3);
  lcd.print("   Volume: -   dB");

  // Set the default volume at power up, otherwise the DAC defaults at full volume

  setSabreVolume(DEFAULTVOL);
  printVol(DEFAULTVOL/2);

}

void loop() {

  // Print the sample rate (once every "INTERVAL" time)
  if(millis() - previousMillis > INTERVAL*1000)
  { 
    previousMillis = millis(); // Saving last time we display sample rate
    lcd.setCursor(13,2);
    lcd.print(sampleRate(), DEC);
  }

  // Asjusting the volume down (larger numbers since we are displaying attenuation)
  while(attenuUp==true)         // While there is CCW motion in the rotary encoder
  {
    attenuUp=false;             // Reset the flag
    if (currVol// Check if already at maximum attenuation (minimum Volume)
    {
      currVol=currVol+2;        // Increase 1 dB
      setSabreVolume(currVol);  // Write value into registers
      printVol(currVol/2);      // Divide by 2 to print in whole dBs
    }
  }

  // Adjusting the volume up (smaller numbers since we are displaying attenuation)
  while(attenuDown==true)       // While there is CW motion in rotary encoder
  {
    attenuDown=false;           // reset the flag
    if (currVol>MAXVOL)         // Check if already at max Volume
    {
      currVol=currVol-2;        // Increase 1 dB
      setSabreVolume(currVol);  // Write value into registers
      printVol(currVol/2);      // Divide by 2 to print in whole dBs
    }
  }
}

Posted October 18, 2010 by BlgGear in Code for Buffalo DAC

Code for Buffalo II DAC v B02   1 comment

/*
HIFIDUINO v. B02
 October 15, 2010
 Arduino code for Buffalo II DAC  and other DACs
 based on the Sabre32 DAC chip
 
 This code is adapted from an earlier version developed for
 the Wolfson 8741 DAC chip
 
 For more information visit
 www.hifiduino.wordpress.com
 
 Although this is based on a confidential data sheet for which I've
 signed an NDA, I've also received permission to publish this code.
 
 Change log:
 v. B01 10/11/10: Volume control, LCD, Rotary Encoder
 v. B02 10/15/10: Added reading of sample rate
 */

/* For the LCD, I am using a "standard" HD44780 20x4 display,
 and I am using the official Arduino LiquidCrystal library that
 comes with the standard installation.
 
 The pin assignment is different from the example
 code and it is as follows:
 
 * LCD RS pin to digital pin 12
 * LCD Enable pin to digital pin 11
 * LCD D4 pin to digital pin 10
 * LCD D5 pin to digital pin 9
 * LCD D6 pin to digital pin 8
 * LCD D7 pin to digital pin 7
 */

// LIBRARIES USED IN THIS CODE

// include the  LCD library code:
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 10, 9, 8, 7);

// include the library code for I2C:
#include <Wire.h>

// #DEFINES

// Volume for Sabre32 is 0 to -127 db in .5 db steps

#define DEFAULTVOL 0x64 //-50 dB this is 50x2=100 or 0x64
#define MINVOL 0xC6    //-99dB this is 99X2=198 or 0xC6
#define MAXVOL 0x00     //-0 dB
#define DIMVOL 0x3C    //-60dB The volume level when dimming the volume

#define VOLUPPIN 4      // Button to increase  volume or RotEnc A terminal
#define VOLDOWNPIN 2    // Button to decrease volume or RotEnc B terminal

#define INTERVAL 2000   // Time interval in msec for doing something like reading the sample rate

// VARIABLE DECLARATIOM

byte regVal; // Variable to pass register value
byte regAddr; // Variable to pass register value
byte currVol=DEFAULTVOL; // Varialble to hold the current volume value
unsigned long previousMillis = 0; // Stores last recorded time

/*
ROTARY ENCODER
 
 The rotary encoder is connected to pins 2 (A) and pin 4 (B)
 and GND. It does not matter which terminal you connect to which pin.
 The third terminal is connected to GND. At each cycle, the rotary
 encoder would pull the pins LOW and we detect that transition and
 compare it with the level of the other pin
 
 For this code to work, the rotary encoder is "debounced" by installing capacitors
 between the signal pins an GND in order to minimize the noise generated by the
 mechanical switches of the rotary encoder. If you are using an optical rotary
 encoder or a high quality encoder, you might not need the capacitors, but the model
 I am using is a low cost ~ $1 rotary encoder
 */

// Interrupt service routine for rotary encoder. Determines direction.

volatile byte volUp=0;  // flags for the interrupt routine
volatile byte volDown=0;

void rotEncoder()
{
  if (digitalRead(2) == digitalRead(4))
  {
    volUp = 1;  //if on interrupt the encoder channels are the same, direction is clockwise
  }
  else
  {
    volDown = 1;  //if they are not the same, direction is ccw
  }
}

/*
Reading the Sample Rate in the Buffalo II DAC
 The sample rate can be calculated by reading the registers of the 32 bit DPLL value. For SPDIF
 this value is divided by 2^32/Crystal-Frequency. In Buffalo II, the Crystal frequency is
 80,000,000 Hz. To read the DPLL value we need to read 4 bytes because it is a 32-bit (4 bytes) number
 
 In Arduino (and other small microprocessors) it is NOT advisible to do floating point math because
 "it is very slow"; therefor we will use interger math.
 
 In order to increase the accuracy of the integer calculation, I did some evaluation of the DPLL
 register values for sample rates ranging from 44.1K to 192K. I noticed that I could multiply the value
 of the DPLL number by up to 400X without overflowing the 32-bits.
 
 The value of 2^32/80000000 is 53.687091 (which is a floating point number). If we use the integer part 
 (53 or 54) we will have an error in the calculation. For example, if we divide the DPLL number for a 44.1K
 sample rate signal by 53, the resultant values would be 44.677K and 43.849K if divided by 54. 
 If we divide by the actual number 53.687091, then we obtain 44.105K (The 4 Hz deviation from ideal is within
 the SPDIF specification and crystal tolerances of the source signal). Clearly the integer math is not very
 accurate.
 
 However, since we have 32 bit number to work with, we can multiply the DPLL number by 400 and then device
 by 400X53.687091=21475. If we do this, we obtain 44.105K which is within rounding off value of the exact
 result (the one using floating math)
 */

// Sample rate reading routines

volatile unsigned long DPLLNum; // Variable to hold DPLL value

byte readDPLL(byte regAddr)
{
  Wire.beginTransmission(0x48); // Hard coded the Sabre/Buffalo device  address
  Wire.send(regAddr); // Specify the DPLL register from which to read value
  Wire.endTransmission();
  Wire.requestFrom(0x48,1); // Hard coded to Buffalo, request from address specified with Wire.send()
  while(!Wire.available()) {
  } // Wait for the data on the wire -if needed...
  return Wire.receive();
}
unsigned long sampleRate()
{
  DPLLNum=0;
  // Reading the 4 registers of DPLL and stuffing into a single 32-bit number
  DPLLNum|=readDPLL(31);
  DPLLNum<<=8;
  DPLLNum|=readDPLL(30);
  DPLLNum<<=8;
  DPLLNum|=readDPLL(29);
  DPLLNum<<=8;
  DPLLNum|=readDPLL(28);
  // Calculating the sample rate for SPDIF
  DPLLNum=DPLLNum*400;
  DPLLNum=DPLLNum/21475;
  return DPLLNum;
}

/*
Buffalo volume setting routine
 
 The device address of Sabre DAC Datasheet specifies the address as 0x90 which is an 8-bit value.
 The wire library in Arduino uses 7-bit device addresses and the 8th R/W bit is added automatically
 depending on whether you use the write call [beginTransmission()] or the read call [requestFrom()].
 Therefore, you will use the 7 most significant bits of the 8-bit address.
 In our example, 0.x90 becomes 0x48 as follows
 0x90: 0101000 (we eliminate the rightmost bit)
 0x48: 0010100
 */

void setSabreVolume(byte regVal)
{
  Wire.beginTransmission(0x48); //hard coded the Sabre/Buffalo device  address
  Wire.send(0x00); // Specifying the vol register of  DAC 1
  Wire.send(regVal); // Writing volume value into register
  Wire.endTransmission();

  Wire.beginTransmission(0x48); //hard coded the Sabre/Buffalo device  address
  Wire.send(0x01); // Specifying the vol register of  DAC 1
  Wire.send(regVal); // Writing volume value into register
  Wire.endTransmission();

  Wire.beginTransmission(0x48); //hard coded the Sabre/Buffalo device  address
  Wire.send(0x02); // Specifying the vol register of  DAC 2
  Wire.send(regVal); // Writing volume value into register
  Wire.endTransmission();

  Wire.beginTransmission(0x48); //hard coded the Sabre/Buffalo device  address
  Wire.send(0x03); // Specifying the vol register of  DAC 3
  Wire.send(regVal); // Writing volume value into register
  Wire.endTransmission();

  Wire.beginTransmission(0x48); //hard coded the Sabre/Buffalo device  address
  Wire.send(0x04); // Specifying the vol register of  DAC 4
  Wire.send(regVal); // Writing volume value into register
  Wire.endTransmission();

  Wire.beginTransmission(0x48); //hard coded the Sabre/Buffalo device  address
  Wire.send(0x05); // Specifying the vol register of  DAC 5
  Wire.send(regVal); // Writing volume value into register
  Wire.endTransmission();

  Wire.beginTransmission(0x48); //hard coded the Sabre/Buffalo device  address
  Wire.send(0x06); // Specifying the vol register of  DAC 6
  Wire.send(regVal); // Writing volume value into register
  Wire.endTransmission();

  Wire.beginTransmission(0x48); //hard coded the Sabre/Buffalo device  address
  Wire.send(0x07); // Specifying the vol register of  DAC 7
  Wire.send(regVal); // Writing volume value into register
  Wire.endTransmission();
}

/*
A little print routine...
 hardcoded to print on line 3 (4th line) of LCD
 Takes in the volume value in whole dB increment
 This means dividing the volumen register value by 2 first
 */

void printVol(byte regVal)
{
  if (regVal==9) // transition between two digit and one digit display
  {
    lcd.setCursor(12,3);
    lcd.print("0 ");  // Add a leading zero
  }
  if (regVal<10) // two digit to one digit transistion, right justification
  {
    lcd.setCursor(13,3);
    lcd.print(regVal, DEC);
  }
  else
  {
    lcd.setCursor(12,3);
    lcd.print(regVal, DEC);
  }
}

void setup() {
  // set up the LCD's number of columns and rows: 
  lcd.begin(20, 4);

  // Join the I2C bus as a master
  Wire.begin();

  // Attach Interrupts
  attachInterrupt(0, rotEncoder, CHANGE);  // ISR for rotary encoder

  // Set up the pin modes
  pinMode(VOLUPPIN, INPUT);       // Button or Encoder pin for volume up
  digitalWrite(VOLUPPIN, HIGH);   // Enable pull-up resistor

  pinMode(VOLDOWNPIN, INPUT);     // Button or Encoder pin for volume down
  digitalWrite(VOLDOWNPIN, HIGH); // Enable pull-down resistor    

  // Print the welcome message to the LCD.
  // And volume indicator

  lcd.setCursor(0,1);
  lcd.print("BUFFALO CONTROL v0.2");
  lcd.setCursor(0,3);
  lcd.print("   Volume: -   dB");

  // Set the default volume at power up

  setSabreVolume(DEFAULTVOL);
  printVol(DEFAULTVOL/2);

}

void loop() {

  // Print the sample rate (once every "INTERVAL" time)
  if(millis() - previousMillis > INTERVAL)
  { 
    previousMillis = millis(); // Saving last time we display sample rate
    lcd.setCursor(0,2);
    lcd.print("Sample Rate: ");
    lcd.print(sampleRate(), DEC);
  }

  // The following is to adjust the volume down (larger number)

  while(volUp==1)  // While there is CW motion in the rotary encoder
  {
    volUp=0;  // Reset the flag
    if (currVol// Check if already at min numerical Volume
    {
      currVol=currVol+2;         // Increase 1 dB
      setSabreVolume(currVol);   // Write value into registers
      printVol(currVol/2);
    }
  }

  // The following is to adjust the volume up (smaller numbers)

  while(volDown==1)  // While there is CCW motion in rotary encoder
  {
    volDown=0;  // clear the flag
    if (currVol>MAXVOL)   // Check if already at max Volume
    {
      currVol=currVol-2;         // Increase 1 dB
      setSabreVolume(currVol);   // Write value into registers
      printVol(currVol/2);
    }
  }
}

Posted October 15, 2010 by BlgGear in Code for Buffalo DAC

Code for Buffalo II DAC v B01   1 comment

/*
HIFIDUINO v. B01
 October 11, 2010
 Arduino code for Buffalo II DAC  and other DACs
 based on the Sabre32 DAC chip
 
 This code is adapted from an earlier version developed for
 the Wolfson 8741 DAC chip
 
 For more information visit
 www.hifiduino.wordpress.com
 
 Although this is based on a confidential data sheet for which I've
 sigend an NDA, I've also received permission to publish this code.
 */

/* For the LCD, I am using a "standard" HD44780 20x4 display,
 and I am using the official Arduino LiquidCrystal library that
 comes with the standard installation.
 
 The pin assignment is different from the example
 code and it is as follows:
 
 * LCD RS pin to digital pin 12
 * LCD Enable pin to digital pin 11
 * LCD D4 pin to digital pin 10
 * LCD D5 pin to digital pin 9
 * LCD D6 pin to digital pin 8
 * LCD D7 pin to digital pin 7
 */

// LIBRARIES USED IN THIS CODE

// include the  LCD library code:
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 10, 9, 8, 7);

// include the library code for I2C:
#include <Wire.h>


// #DEFINES

// Volume for Sabre32 is 0 to -127 db in .5 db steps

#define DEFAULTVOL 0x64 //-50 dB this is 50x2=100 or 0x64
#define MINVOL 0xC6    //-99dB this is 99X2=198 or 0xC6
#define MAXVOL 0x00     //-0 dB
#define DIMVOL 0x3C    //-60dB The volume level when dimming the volume

#define VOLUPPIN 4      // Button to increase  volume or RotEnc A terminal
#define VOLDOWNPIN 2    // Button to decrease volume or RotEnc B terminal

// VARIABLE DECLARATIOM

byte regVal; // variable to pass register value
byte currVol=DEFAULTVOL; // varialble to hold the current volume value

/*
ROTARY ENCODER
 
 The rotary encoder is connected to pins 2 (A) and pin 4 (B)
 and GND. It does not matter which terminal you connect to which pin.
 The third terminal is connected to GND. At each cycle, the rotary
 encoder would pull the pins LOW and we detect that transition and
 compare it with the level of the other pin
 
 For this code to work, the rotary encoder is "debounced" by installing capacitors
 between the signal pins an GND in order to minimize the noise generated by the
 mechanical switches of the rotary encoder. If you are using an optical rotary
 encoder or a high quality encoder, you might not need the capacitors, but the model
 I am using is a low cost ~ $1 rotary encoder
 */

// Interrupt service routine for rotary encoder. Determines direction.

volatile byte volUp=0;  // flags for the interrupt routine
volatile byte volDown=0;

void rotEncoder()
{
  if (digitalRead(2) == digitalRead(4))
  {
    volUp = 1;  //if on interrupt the encoder channels are the same, direction is clockwise
  }
  else
  {
    volDown = 1;  //if they are not the same, direction is ccw
  }
}


/*
Buffalo volume setting routine
 
 The device address of Sabre DAC Datasheet specifies the address as 0x90 which is an 8-bit value.
 The wire library in Arduino uses 7-bit device addresses and the 8th R/W bit is added automatically
 depending on whether you use the write call [beginTransmission()] or the read call [requestFrom()].
 Therefore, you will use the 7 most significant bits of the 8-bit address.
 In our example, 0.x90 becomes 0x48 as follows
 0x90: 0101000 (we eliminate the rightmost bit)
 0x48: 0010100
 */

void setSabreVolume(byte regVal)
{
  Wire.beginTransmission(0x48); //hard coded the Sabre/Buffalo device  address
  Wire.send(0x00); // Specifying the vol register of  DAC 1
  Wire.send(regVal); // Writing volume value into register
  Wire.endTransmission();

  Wire.beginTransmission(0x48); //hard coded the Sabre/Buffalo device  address
  Wire.send(0x01); // Specifying the vol register of  DAC 1
  Wire.send(regVal); // Writing volume value into register
  Wire.endTransmission();

  Wire.beginTransmission(0x48); //hard coded the Sabre/Buffalo device  address
  Wire.send(0x02); // Specifying the vol register of  DAC 2
  Wire.send(regVal); // Writing volume value into register
  Wire.endTransmission();

  Wire.beginTransmission(0x48); //hard coded the Sabre/Buffalo device  address
  Wire.send(0x03); // Specifying the vol register of  DAC 3
  Wire.send(regVal); // Writing volume value into register
  Wire.endTransmission();

  Wire.beginTransmission(0x48); //hard coded the Sabre/Buffalo device  address
  Wire.send(0x04); // Specifying the vol register of  DAC 4
  Wire.send(regVal); // Writing volume value into register
  Wire.endTransmission();

  Wire.beginTransmission(0x48); //hard coded the Sabre/Buffalo device  address
  Wire.send(0x05); // Specifying the vol register of  DAC 5
  Wire.send(regVal); // Writing volume value into register
  Wire.endTransmission();

  Wire.beginTransmission(0x48); //hard coded the Sabre/Buffalo device  address
  Wire.send(0x06); // Specifying the vol register of  DAC 6
  Wire.send(regVal); // Writing volume value into register
  Wire.endTransmission();

  Wire.beginTransmission(0x48); //hard coded the Sabre/Buffalo device  address
  Wire.send(0x07); // Specifying the vol register of  DAC 7
  Wire.send(regVal); // Writing volume value into register
  Wire.endTransmission();
}

/*
A little print routine...
 hardcoded to print on line 3 (4th line) of LCD
 Takes in the volume value in whole dB increment
 This means dividing the volumen register value by 2 first
 */

void printVol(byte regVal)
{
  if (regVal==9) // transition between two digit and one digit display
  {
    lcd.setCursor(12,3);
    lcd.print("0 ");  // Add a leading zero
  }
  if (regVal<10) // two digit to one digit transistion, right justification
  {
    lcd.setCursor(13,3);
    lcd.print(regVal, DEC);
  }
  else
  {
    lcd.setCursor(12,3);
    lcd.print(regVal, DEC);
  }
}


void setup() {
  // set up the LCD's number of columns and rows: 
  lcd.begin(20, 4);

  // Join the I2C bus as a master
  Wire.begin();

  // Attach Interrupts
  attachInterrupt(0, rotEncoder, CHANGE);  // ISR for rotary encoder

  // Set up the pin modes
  pinMode(VOLUPPIN, INPUT);       // Button or Encoder pin for volume up
  digitalWrite(VOLUPPIN, HIGH);   // Enable pull-up resistor

  pinMode(VOLDOWNPIN, INPUT);     // Button or Encoder pin for volume down
  digitalWrite(VOLDOWNPIN, HIGH); // Enable pull-down resistor

  // Print the welcome message to the LCD.
  // And volume indicator

  lcd.setCursor(0,1); 
  lcd.print("BUFFALO II DAC v0.1");
  lcd.setCursor(0,3);
  lcd.print("   Volume: -   dB");

  // Set the default volume at power up

  setSabreVolume(DEFAULTVOL);
  printVol(DEFAULTVOL/2);

}

void loop() {

  // The following is to adjust the volume down (larger number)

  while(volUp==1)  // While there is CW motion in the rotary encoder
  {
    volUp=0;  // Reset the flag
    if (currVol<MINVOL) // Check if already at min numerical Volume
    {
      currVol=currVol+2;         // Increase 1 dB
      setSabreVolume(currVol);   // Write value into registers
      printVol(currVol/2);
    }
  }

  // The following is to adjust the volume up (smaller numbers)

  while(volDown==1)  // While there is CCW motion in rotary encoder
  {
    volDown=0;  // clear the flag
    if (currVol>MAXVOL)   // Check if already at max Volume
    {
      currVol=currVol-2;         // Increase 1 dB
      setSabreVolume(currVol);   // Write value into registers
      printVol(currVol/2);
    }
  }
}

Posted October 12, 2010 by BlgGear in Code for Buffalo DAC

Code v 0.7a   8 comments

/*
Hifiduino v 0.7a
May 19, 2011: Minor update and bug fixes to the version 0.7 of June 21, 2009

---------------------------------------------------------------------------
IMPORTANT:
This code requires LCD12cW.h for i2c LCD from Web4robot LCD and macros.h
for defining the large characters. Download library from:
http://www.arduino.cc/playground/Code/LCDAPI and select "LCD12cW".
After downloading copy the folder "LCDi2cW" to the "libraries" folder in
the Arduino folder. "macros.h" is inside one of the examples in the examples
folder. Move it out of that folder into the LCDi2cW folder
----------------------------------------------------------------------------

In this release:
- Support for Web4robot LCD: http://www.arduino.cc/playground/Code/LCDAPI
- Large number display for filter selection and volume
- Digital Filter Selection: Filter 1 to Filter 5.
- Rotary encoder.
- Volume Control. Now -99 db to 0db in 1db increment.
- Volume "dimmer". Volume dims to -60 dB when pushing rotary encoder
- Changed the default delay in the LCD library to (0,0) See below note.
- Select input sample rate (low, med, high) for future use.
- Adjust brightness and contrast of display with remote
- Remember brightness and contrast settings in eeprom
- New fonts for large number display
*/

/*
Additional notes:
- The default delay for the web4robot LCD is (50,4)
 It can be changed with setDelay(Cmd,Char).
 In fact setDelay(0,0) works with the web4robot display
 at least in this code, making it fairly fast
*/

#include <Wire.h>
#include "macros.h" // Used for defining custom characters
// library for i2c LCD from Web4robot LCD
// Download library from http://www.arduino.cc/playground/Code/LCDAPI
// and select "LCD12cW". After downloading copy the folder "LCDi2cW"
// to the "libraries" folder in the Arduino folder
#include <LCDi2cW.h>
LCDi2cW lcd = LCDi2cW(4,20,0x4C,0); // Initialized the library

// We will use the eeprom to store values
#include <EEPROM.h>
#define BRIADDR 0  // The address to store brightness value
#define CONADDR 1  // The address to store contrast value

// Define register values, etc to facilitate programming
// Note: Reg address is address plus R/W bit
// This is why the address here is different from the
// address in the data sheet

#define REG9 0x12     // Register 9 address (Reset)
#define RESET 0x00    // Write anything to reset the DAC

#define REG7 0x0E     // Register 7 address (PCM vs DSD)
#define PCMHIGH 0x40  // Value for reg7 for PCM, High Sample rate for filter
#define PCMMED 0x20  // Value for reg7 for PCM, Medium Sample rate for filter
#define PCMLOW 0x00  // Value for reg7 for PCM, Low Sample rate for filter

#define REG6 0x0C     // Register 6 address (filters)
#define FILTER1 0x00  // PCM Filter response 1
#define FILTER2 0x01  // PCM Filter response 2
#define FILTER3 0x02  // PCM Filter response 3
#define FILTER4 0x03  // PCM Filter response 4
#define FILTER5 0x04  // PCM Filter response 5

#define REG0 0x00     // Register 0 address (Volume Adjustment)
#define REG1 0x02     // Register 1 address (Volume Adjustment)
#define REG2 0x04     // Register 2 address (Volume Adjustment)
#define REG3 0x06     // Register 3 address (Volume Adjustment)
#define REG4 0x08     // Register 4 address (Volume Control)

// The following to be used in Reg4
//#define VOLCNTR 0x07 // VolRight=VolLeft, AntiClip, Vol Ramping is on (a)
#define VOLCNTR 0x05  // VolRight=VolLeft, No AntiClip, Vol Ramping is on (b)
//#define MUTE 0x0F // Mute and (a) above
#define MUTE 0x0D     // Mute and (b) above

#define DEFAULTVOL 0x190 //-50 dB this is 50x8=400
#define MINVOL 0x318    //-99dB this is 99X8=792. -Dac adjustment is .125 db
#define MAXVOL 0x00     //-0 dB - Min attenuation
#define DIMVOL 0x1E0    //-60dB The volume level when dimming the volume

#define FILTERPIN 6     // Button to select Filter
#define VOLDIMPIN 5     // Button for volume dimming feature
#define VOLUPPIN 4      // Button to increase volume
#define VOLDOWNPIN 2    // Button to decrease volume

#define IRPIN 3         // The pin for the remote sensor

#define KEY1 128           // The value when pressing the 1 key in remote
#define KEY2 129           // The value when pressing the 2 key in remote
#define KEY3 130           // The value when pressing the 3 key in remote
#define KEY4 131           // The value when pressing the 4 key in remote
#define KEY5 132           // The value when pressing the 5 key in remote
#define KEY7 134           // The value when pressing the 7 key in remote
#define KEY8 135           // The value when pressing the 8 key in remote
#define KEY9 136           // The value when pressing the 9 key in remote
#define KEYVOLUP 147       // The value when pressing volume up key in remote
#define KEYVOLDOWN 146     // The value when pressing volume down key in remote
#define KEYDISPLAY 186     // The value when pressing display key in remote
#define KEYPICTUREUP 152   // The value when pressing picture + key in remote
#define KEYPICTUREDOWN 153 // The value when pressing picture - key in remote

#define IRFILSELDELAY 300  // Delay when selecting filter with remote to preven multiple selection

#define ONEPULSE 1000      // Microsecond threshold for value 1 in remote putlse

#define B 0xFF             // The character for a completely filled box
#define A 0x20             // The character for blank

// The routine to create the custom characters in the LCD
void DefineLargeChar()
{
  // A 1 in the binary representation of the character means it is filled in
  // characters are 5 pixels wide by 8 pixels tall

  // We need 7 custom characters for the OPUS DAC display.
  // (Custom character 0 doesn't work in the Web4Robot LCD)

  // Define Custom Characters

  uint8_t cc1[8] = {     // Custom Character 1
    B8(11100),
    B8(11110),
    B8(11111),
    B8(11111),
    B8(11111),
    B8(11111),
    B8(11111),
    B8(11111)
  };

  uint8_t cc2[8] = {    // Custom Character 2
    B8(11111),
    B8(11111),
    B8(11111),
    B8(11111),
    B8(11111),
    B8(00000),
    B8(00000),
    B8(00000)
  };

  uint8_t cc3[8] = {    // Custom Character 3
    B8(00000),
    B8(00000),
    B8(00000),
    B8(11111),
    B8(11111),
    B8(11111),
    B8(11111),
    B8(11111)
  };

  uint8_t cc4[8] = {   // Custom Character 4
    B8(11111),
    B8(11111),
    B8(11111),
    B8(11111),
    B8(11111),
    B8(11111),
    B8(01111),
    B8(00111)
  };

  uint8_t cc5[8] = {    // Custom Character 5
    B8(11111),
    B8(11111),
    B8(11111),
    B8(11111),
    B8(11111),
    B8(11111),
    B8(00000),
    B8(00000)
  };

  uint8_t cc6[8] = {    // Custom Character 6
    B8(00000),
    B8(11111),
    B8(11111),
    B8(11111),
    B8(11111),
    B8(11111),
    B8(00000),
    B8(00000)
  };

  uint8_t cc7[8] = {     // Custom Character 7
    B8(00000),
    B8(11100),
    B8(11110),
    B8(11111),
    B8(11111),
    B8(11111),
    B8(11111),
    B8(11111)
  };

  // send custom characters to the display
  lcd.load_custom_character(1,cc1);
  lcd.load_custom_character(2,cc2);
  lcd.load_custom_character(3,cc3);
  lcd.load_custom_character(4,cc4);
  lcd.load_custom_character(5,cc5);
  lcd.load_custom_character(6,cc6);
  lcd.load_custom_character(7,cc7);

}

// Array index into parts of big numbers. Numbers consist of 9 custom characters in 3 lines
// 0 1 2 3 4 5 6 7 8 9 
char bn1[]={B,2,1, 2,1,A, 2,2,1, 2,2,1, 3,A,B, B,2,2, B,2,2, 2,2,B, B,2,1, B,2,1};
char bn2[]={B,A,B, A,B,A ,3,2,2, A,6,1, 5,6,B, 5,6,7, B,6,7, A,3,2, B,6,B, 5,6,B};
char bn3[]={4,3,B, 3,B,3, B,3,3, 3,3,B, A,A,B, 3,3,B, 4,3,B, A,B,A, 4,3,B, A,A,B};

void printOneNumber(uint8_t digit)
{
  // Print position is hardcoded

  // Line 1 of the one digit number
  lcd.setCursor(1,0);
  lcd.write(bn1[digit*3]);
  lcd.write(bn1[digit*3+1]);
  lcd.write(bn1[digit*3+2]);

  // Line 2 of the one-digit number
  lcd.setCursor(2,0);
  lcd.write(bn2[digit*3]);
  lcd.write(bn2[digit*3+1]);
  lcd.write(bn2[digit*3+2]);

  // Line 3 of the one-digit number
  lcd.setCursor(3,0);
  lcd.write(bn3[digit*3]);
  lcd.write(bn3[digit*3+1]);
  lcd.write(bn3[digit*3+2]);
}

void printTwoNumber(uint8_t number)
{
  // Print position is hardcoded
  int digit0;  // To represent the ones
  int digit1;  // To represent the tens
  digit0=number%10;
  digit1=number/10;

  // Line 1 of the two-digit number
  lcd.setCursor(1,13);
  lcd.write(bn1[digit1*3]);
  lcd.write(bn1[digit1*3+1]);
  lcd.write(bn1[digit1*3+2]);
  lcd.write(A); // Blank
  lcd.write(bn1[digit0*3]);
  lcd.write(bn1[digit0*3+1]);
  lcd.write(bn1[digit0*3+2]);

  // Line 2 of the two-digit number
  lcd.setCursor(2,13);
  lcd.write(bn2[digit1*3]);
  lcd.write(bn2[digit1*3+1]);
  lcd.write(bn2[digit1*3+2]);
  lcd.write(A); // Blank
  lcd.write(bn2[digit0*3]);
  lcd.write(bn2[digit0*3+1]);
  lcd.write(bn2[digit0*3+2]);

  // Line 3 of the two-digit number
  lcd.setCursor(3,13);
  lcd.write(bn3[digit1*3]);
  lcd.write(bn3[digit1*3+1]);
  lcd.write(bn3[digit1*3+2]);
  lcd.write(A); // Blank
  lcd.write(bn3[digit0*3]);
  lcd.write(bn3[digit0*3+1]);
  lcd.write(bn3[digit0*3+2]);
}

// The write to WM8741 DAC routine
void opuswritereg(uint8_t regaddr,uint8_t regval)
{
  Wire.beginTransmission(0x1B);
  Wire.send(regaddr);
  Wire.send(regval);
  Wire.endTransmission();
}

// Interrupt service routine for rotary encoder. Determines direction.

volatile byte volUp=0;  // flags for the interrupt routine
volatile byte volDown=0;

void decoder()
{
  if (digitalRead(2) == digitalRead(4))
  {
    volUp = 1;  //if on interrupt the encoder channels are the same, direction is clockwise
  }
  else
  {
    volDown = 1;  //if they are not the same, direction is ccw
  }
}

// interrupt service routine for remote

volatile byte remoteOn = 0;  // 1 means remote has been pressed

void remoting()
{
  remoteOn=1;
}

// Routines for LCD Adjustment

// For LCD backlight adjustment
void BackLight(uint8_t bright)
{
  Wire.beginTransmission(0x4C);
  Wire.send(0xFE);
  Wire.send(0x03);
  Wire.send(bright);
  Wire.endTransmission();
  delay(25);
}

// For LCD contrast adjustment
void Contrast(uint8_t cont)
{
  Wire.beginTransmission(0x4C);
  Wire.send(0xFE);
  Wire.send(0x04);
  Wire.send(cont);
  Wire.endTransmission();
  delay(25);
}

// Declaring some more variables

int currVol=DEFAULTVOL; // this needs to be at least 10 bits
byte filter=0;          // variable for current filter
byte reg0val=0;         // variable for volume lower bits
byte reg1val=0;         // variable for volume upper bits
byte volDimState=0;     // State for volume dimmer. =1 is dimmed
byte BC=0;              // State for selecting contrast or brightness
                        // BC=0, no adjustment, BC=1" Brighness
                        // BC=2: contrast
int brightness=0;
int contrast=0;

int irCode=0;           // The code returned by the remote IR pulses

void setup() {
  lcd.init();     // Initializing the LCD, clears the display
  lcd.setDelay(0,0); // Change de delay in the LCD library 
  DefineLargeChar();  // Define large characters

  Wire.begin();   // Joining the I2C bus as master

  pinMode(FILTERPIN, INPUT);      // Button to select Input fiter
  digitalWrite(FILTERPIN, HIGH);  // Enable pull-up resistor

  pinMode(VOLUPPIN, INPUT);       // Button or Encoder pin for volume up
  digitalWrite(VOLUPPIN, HIGH);   // Enable pull-up resistor

  pinMode(VOLDOWNPIN, INPUT);     // Button or Encoder pin for volume down
  digitalWrite(VOLDOWNPIN, HIGH); // Enable pull-down resistor

  pinMode(VOLDIMPIN, INPUT);      // Button or switch for volume dimmer
  digitalWrite(VOLDIMPIN, HIGH);  // Enable pull-up resistor

  pinMode(IRPIN, INPUT);          // Pin for IR Receiver
  digitalWrite(IRPIN, HIGH);      // Enable high as specified by datasheet

  for(int i=0;i<4;i++) // Wait for DAC to power up, just in case
    {
      lcd.setCursor(i,1);
      lcd.print("H I F I D U I N O");
      delay(800);
    }
  for(int i=0;i<4;i++) // Wait a bit more
    {
      lcd.setCursor(i,1);
      lcd.print(" ");
      delay(800);
    }

  opuswritereg(REG9,RESET);   // Resetting the DAC just in case
  opuswritereg(REG4,MUTE);    // MUTE (and vol setup) 

  // The following 4 lines is to set up the default volume
  // To set up the volume you need to write to at least 2 registers

  reg0val=(DEFAULTVOL & 0x1F);     // The lower 5 bits goes to reg 0
  opuswritereg(REG0,reg0val);      // Writing to reg 0
  reg1val=((DEFAULTVOL>>5)| 0x20); // The upper 5 bits goes to reg 1
  opuswritereg(REG1,reg1val);      // Writing to reg 1

  opuswritereg(REG6,FILTER1);  // I'm setting the default filter at power on
  opuswritereg(REG7,PCMHIGH);  // Setting up for PCM and high sampling rate because I have 
                               // a reclocker and the output is 192K to the DAC 
  opuswritereg(REG4,VOLCNTR);  // Setting up volume control. Unmute

  attachInterrupt(0, decoder, CHANGE);  // ISR for rotary encoder
  attachInterrupt(1, remoting, RISING); // ISR for remote IR sensor

  lcd.setCursor(0,0);
  // print header for digital filter and current filter 
  lcd.print("LnS");
  printOneNumber(1);

  // print header for volume and volume
  lcd.setCursor(0,13);
  lcd.print("-dB VOL");
  printTwoNumber(currVol/8);

  // Print the rest of the display
  lcd.setCursor(2 ,4);
  lcd.print("INPT");
  lcd.write(0xA5);
  lcd.print("PCM");
  lcd.setCursor(1,4);
  lcd.print("RATE");
  lcd.write(0xA5);
  lcd.print("192");

}

void loop()
{
  // The following code will select the next filter if the button is pushed
  // and it is repeated for the remote because I'm lazy :-)

  if (digitalRead(FILTERPIN)==0)  // When the filter button is pushed
  {
    filter++;
    filter=filter%5;
    lcd.setCursor(0,8);
    switch(filter){
      case 0:
      opuswritereg(REG6,FILTER1);
      lcd.print("RESPONSE #1");
      break;
      case 1:
      opuswritereg(REG6,FILTER2);
      lcd.print("RESPONSE #2");
      break;
      case 2:
      opuswritereg(REG6,FILTER3);
      lcd.print("RESPONSE #3");
      break;
      case 3:
      opuswritereg(REG6,FILTER4);
      lcd.print("RESPONSE #4");
      break;
      case 4:
      opuswritereg(REG6,FILTER5);
      lcd.print("RESPONSE #5");
      break;
    }
    delay(300);  // Used to avoid reading the button more than one during the click
  }

  // The following is to adjust the volume down (larger number)

  while(volDown==1)  // While there is CCW motion in the rotary encoder
                     // This means decrease volume -increase attenuation
  {
    volDown=0;  // Reset the flag
    if (currVol<MINVOL) // If current volume is not at MIN (attn < maxAttn)
                        // then decrease volume (increase attenuation)
    {
      currVol=currVol+8;                    // Increase attenuation 1 dB
      reg0val=(((byte)currVol) & 0x1F);     // Calculate value for reg0
      opuswritereg(REG0,reg0val);           // Write to reg0
      reg1val=(((byte)(currVol>>5))| 0x20); // Calculate value for reg1
      opuswritereg(REG1,reg1val);           // Write to reg1

      printTwoNumber(currVol/8);

      if (volDimState==1)                // If in dim state, reset state value
      {
        volDimState=0;
        lcd.setCursor(0,17);
        lcd.print("VOL");
      }
    }
  }

  // The following is to adjust the volume up (smaller numbers)

  while(volUp==1)  // While there is cw motion in rotary encoder
  {
    volUp=0;  // clear the flag
    if (currVol>MAXVOL)   // If current volume not at MAX (attn>minAttn)
                          // increase volume (reduce attennuation)
    {
      currVol=currVol-8;                // Decrease attenuation 1 dB
      reg0val=(((byte)currVol) & 0x1F); // Calculate value for reg0
      opuswritereg(REG0,reg0val);       // Write to reg0
      reg1val=((currVol>>5)| 0x20);     // Calculate value for reg1
      opuswritereg(REG1,reg1val);       // Write to reg1

      printTwoNumber(currVol/8);

      if (volDimState==1)               // If in dim state, reset state value
      {
        volDimState=0;
        lcd.setCursor(0,17);
        lcd.print("VOL");
      }
    }
  }

  // The following is for the volume dimming feature

  if (digitalRead(VOLDIMPIN)==0) // When pressing the volume dim button
  {
    if (volDimState==0)  //if not dimmed, then dim the volume to min vol
    {
      reg0val=(((byte)DIMVOL) & 0x1F);
      opuswritereg(REG0,reg0val);
      reg1val=(((byte)(DIMVOL>>5))| 0x20);
      opuswritereg(REG1,reg1val);
      printTwoNumber(DIMVOL/8);
      volDimState=1;     // set state to dimmed
      lcd.setCursor(0,17);
      lcd.print("DIM");
    }
    else                 // if dimmed, then return to current volume
    {
      reg0val=(((byte)currVol) & 0x1F);
      opuswritereg(REG0,reg0val);
      reg1val=(((byte)(currVol>>5))| 0x20); // Calculate value for reg1
      opuswritereg(REG1,reg1val);
      printTwoNumber(currVol/8);
      volDimState=0;    // set state to undimmed.
      lcd.setCursor(0,17);
      lcd.print("VOL");
    }
    delay(300); // Used to avoid reading the button more than one during the click
  }

  // The following code is for the remote.

  while (remoteOn==1)
  {
    irCode = getIRKey();		    //Fetch the key
    //lcd.setCursor(0,4); // Used to find out remote keys value
    //lcd.print(irCode);

    switch(irCode){
      // The following for filter sel ection
      case KEY1:
      lcd.setCursor(0,0);
      lcd.print("LnS");
      opuswritereg(REG6,FILTER1);
      printOneNumber(1);
      delay(IRFILSELDELAY);
      break;
      case KEY2:
      lcd.setCursor(0,0);
      lcd.print("MnS");
      opuswritereg(REG6,FILTER2);
      printOneNumber(2);
      delay(IRFILSELDELAY);
      break;
      case KEY3:
      lcd.setCursor(0,0);
      lcd.print("BrK");
      opuswritereg(REG6,FILTER3);
      printOneNumber(3);
      delay(IRFILSELDELAY);
      break;
      case KEY4:
      lcd.setCursor(0,0);
      lcd.print("MnA");
      opuswritereg(REG6,FILTER4);
      printOneNumber(4);
      delay(IRFILSELDELAY);
      break;
      case KEY5:
      lcd.setCursor(0,0);
      lcd.print("LnA");
      opuswritereg(REG6,FILTER5);
      printOneNumber(5);
      delay(IRFILSELDELAY);
      break;

      // The following is for the input sample rate
      case KEY7:
      opuswritereg(REG7,PCMLOW);
      lcd.setCursor(1,9);
      lcd.print("48K");
      delay(IRFILSELDELAY);
      break;
      case KEY8:
      opuswritereg(REG7,PCMMED);
      lcd.setCursor(1,9);
      lcd.print("96K");
      delay(IRFILSELDELAY);
      break;
      case KEY9:
      opuswritereg(REG7,PCMHIGH);
      lcd.setCursor(1,9);
      lcd.print("192");
      delay(IRFILSELDELAY);
      break;

      // The following for volume
      case KEYVOLDOWN:
      if (currVol<MINVOL)  // If not at min volume, then can decrease volume
        {                  // volume is decreased by increasing the attenuation value
        currVol=currVol+8;                    // Increase attenuation 1 dB
        reg0val=(((byte)currVol) & 0x1F);     // Calculate value for reg0
        opuswritereg(REG0,reg0val);           // Write to reg0
        reg1val=(((byte)(currVol>>5))| 0x20); // Calculate value for reg1
        opuswritereg(REG1,reg1val);           // Write to reg1

        printTwoNumber(currVol/8);

        if (volDimState==1)                // If in dim state, reset state value
        {
          volDimState=0;
          lcd.setCursor(0,17);
          lcd.print("VOL");
        }
      }
      break;

      case KEYVOLUP:
      if (currVol>MAXVOL) // If volume not at max vol, then increse vol
                          // volume is increased by decreasing the attenuation value
        {
        currVol=currVol-8;                // Decrease attenuation 1 dB
        reg0val=(((byte)currVol) & 0x1F); // Calculate value for reg0
        opuswritereg(REG0,reg0val);       // Write to reg0
        reg1val=((currVol>>5)| 0x20);     // Calculate value for reg1
        opuswritereg(REG1,reg1val);       // Write to reg1

        printTwoNumber(currVol/8);

        if (volDimState==1)               // If in dim state, reset state value
        {
          volDimState=0;
          lcd.setCursor(0,17);
          lcd.print("VOL");
        }
      }
      break;

      // The following is for brightness and constrast control

      case KEYDISPLAY:
      BC++;
      if (BC%3==0){
        lcd.setCursor(0,4);
        lcd.print(" ");
        EEPROM.write(BRIADDR,brightness); // Save value
        EEPROM.write(CONADDR,contrast);  // Save Value
      }
      if (BC%3==1){
        lcd.setCursor(0,4);
        lcd.print("BRI ");
        brightness=EEPROM.read(BRIADDR); // Read value
        lcd.print(brightness);
      }
      if (BC%3==2 ){
        lcd.setCursor(0,4);
        lcd.print("CON ");
        contrast=EEPROM.read(CONADDR);  // Read value
        lcd.setCursor(8,0);
        lcd.print(contrast);
      }
      delay(IRFILSELDELAY);
      break;

      case KEYPICTUREUP:
      if (BC==1){
        brightness++;
        BackLight(brightness);
        lcd.setCursor(0,8);
        lcd.print(brightness);
        //lcd.print(" ");
      }
      if (BC==2){
        contrast++;
        Contrast(contrast);
        lcd.setCursor(0,8);
        lcd.print(contrast);
        //lcd.print(" ");
      }

      // delay(IRFILSELDELAY);
      break;

      case KEYPICTUREDOWN:
      if (BC==1){
        brightness--;
        BackLight(brightness);
        lcd.setCursor(0,8);
        lcd.print(brightness);
        lcd.print(" ");
      }
      if (BC==2){
        contrast--;
        Contrast(contrast);
        lcd.setCursor(0,8);
        lcd.print(contrast);
        lcd.print(" ");
      }

      // delay(IRFILSELDELAY);
      break;

    }

    remoteOn=0;  //reset flag
  }

}  

// This is the main decoding code for the remote.

int getIRKey() {
  int duration=1;
  int result=0;
  while((duration=pulseIn(IRPIN, LOW, 50000)) < 2200 && duration!=0)
  {
    //do nothing waiting for start pulse
  }

  int mask = 1;				    // set mask to bit 0
  for (int idx = 0; idx < 12; idx++)	    // get all 12 bits
  {
    duration = pulseIn(IRPIN, LOW, 2000);   // measure the bit pulse
    if (duration > ONEPULSE)		    // 1 bit?
	result |= mask;			    // yes, update ir code
    mask <<= 1;                             // shift mask to next bit
  }
  return result;
}

Posted June 22, 2009 by BlgGear in Code for OPUS DAC

Code for Large Numbers   Leave a comment

// [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
// []
// []       Large number example
// []      May 24, 2009
// []       For HIFIDUINO
// []       www.hifiduino.blogspot.com
// []
// [] NOTE: A simpler code (without requiring macro.h) can be
// [] found in the Buffalo DAC code
// []
// [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]

Read the rest of this entry »

Posted May 25, 2009 by BlgGear in General Code

Code for HIFIDUINO v 05   Leave a comment

hifiduinov05

Posted April 26, 2009 by BlgGear in Code for OPUS DAC

Code to adjust LCD   Leave a comment

adjustLCDv01

Posted April 19, 2009 by BlgGear in General Code