/*
Sets the MCP4728 DAC address to a new value by using the LDAC pin
Adjust the pins you will use for the SDA and SCL bus
Adjust the IO line you will use for the LDAC signal
Just run this once on the DAC you want to remap the address of.
Or include in a larger project and call as required...
*/
uint8_t SCLpin = 19;
uint8_t SDApin = 18;
uint8_t LDACpin = 14; // pulled LOW on PCB so drive when needed Hi
uint8_t LEDpin = 13; // Teensy LED (Hi logic = lit)
uint8_t I2C_OldAddress = 0; // normally 0
uint8_t I2C_NewAddress = 7; // any value 0-7
int qflash = 50; // 50ms
int sflash = 250; // 250ms
int LEDhold = 1000; // 1s
int I2Cdelay = 1; // 1ms
int FailByte = 0; // which byte we failed at (if we failed)
int Success;
void setup() {
uint8_t flish;
uint8_t outchar;
uint8_t tmpchar;
Serial.begin(115200); // initialize serial interface for print()
Success = 0; // until it works
// initialize the digital pins as an output
pinMode(SCLpin, OUTPUT);
pinMode(SDApin, OUTPUT);
pinMode(LDACpin, OUTPUT);
pinMode(LEDpin, OUTPUT);
digitalWrite(SCLpin, HIGH); // SCL + SDA high to start
digitalWrite(SDApin, HIGH); // SCL + SDA high to start
digitalWrite(LDACpin, LOW); // LDAC Low to start
// Inform the operation to be done...
Serial.println("Setting DAC Address as follows:");
Serial.print("Existing DAC Address = ");
Serial.println(I2C_OldAddress, DEC);
Serial.print("New DAC Address = ");
Serial.println(I2C_NewAddress, DEC);
Serial.println("");
// Flash LED number of times for new address (double flash then 0 to 7 flashes)
for(flish = 0; flish<2; flish++){
digitalWrite(LEDpin, HIGH);
delay(qflash);
digitalWrite(LEDpin, LOW);
delay(qflash);
}
delay(LEDhold);
for(flish = 0; flish<I2C_NewAddress; flish++){
digitalWrite(LEDpin, HIGH);
delay(sflash);
digitalWrite(LEDpin, LOW);
delay(sflash);
}
delay(LEDhold);
// set LDAC Hi
digitalWrite(LDACpin, HIGH); // LDAC Low to start
delay(I2Cdelay);
// send a start condition
digitalWrite(SDApin, LOW);
delay(I2Cdelay);
digitalWrite(SCLpin, LOW);
delay(I2Cdelay);
// byte 1
outchar = I2C_OldAddress;
outchar <<= 1; // shift L by 1
outchar |= 0xc0; // or in 0x60 to address bits
tmpchar = I2CwriteByte(outchar); // write byte 1 (expect slave to ACK and returns 1 if it does, 0 of not)
FailByte = 1;
if (tmpchar == 1) { // success
// byte 2
outchar = I2C_OldAddress;
outchar <<= 2; // shift L by 2
outchar |= 0x61; // or in 0x61 to set the address change command
tmpchar = LDACwriteByte(outchar); // funky write byte 2 which sets LDAC low after the 8th clock (expect slave to ACK and returns 1 if it does, 0 of not)
FailByte = 2;
if (tmpchar == 1) { // success
// byte 3
outchar = I2C_NewAddress;
outchar <<= 2; // shift L by 2
outchar |= 0x62; // or in 0x62 to set the address change command and signify byte 3 (b1 set, b0 clear)
tmpchar = I2CwriteByte(outchar); // write byte 3 (expect slave to ACK only if written correctly)
FailByte = 3;
if (tmpchar == 1) { // success
// byte 4
outchar = I2C_NewAddress;
outchar <<= 2; // shift L by 2
outchar |= 0x63; // or in 0x63 to set the address change command and signify byte 4 (b1 set, b1 set)
tmpchar = I2CwriteByte(outchar); // write byte 4 (expect slave to ACK)
FailByte = 4;
if (tmpchar == 1) { // success
Success = 1;
FailByte = 0;
}
}
}
}
// send a stop condition
// SCL will be Low
digitalWrite(SDApin, LOW); // SDA low in case it's Hi
delay(I2Cdelay);
digitalWrite(SCLpin, HIGH);
delay(I2Cdelay);
digitalWrite(SDApin, HIGH); // SCL Hi
delay(I2Cdelay);
// now set the LDAC low in case it is still high (failed on byte 1)
digitalWrite(LDACpin, LOW); // LDAC Low
// now announce the status...
if (Success == 1) {
Serial.println("DAC Address succesfully set to new value.");
}
else {
Serial.print("DAC Address Set procedure FAILED!! I2C ACK was missing at Byte number ");
Serial.println(FailByte, DEC);
}
}
uint8_t I2CwriteByte(uint8_t outchar){
// Enters with SCL LOW, SDA undefined Hi or Low
// SDA set to output
//
// Leaves with SCL LOW, SDA HIGH
// SDA set to output
//
// returns 1 if acked OK, 0 if not
int shuffle;
uint8_t MyAck;
int tempint;
shuffle = 9; // 8 data bits
while (--shuffle) {
if (outchar & 0x80)
digitalWrite(SDApin, HIGH);
else
digitalWrite(SDApin, LOW);
delay(I2Cdelay);
digitalWrite(SCLpin, HIGH);
delay(I2Cdelay);
outchar <<= 1; // shift up data for bext bit
digitalWrite(SCLpin, LOW);
delay(I2Cdelay);
}
// Completed sending byte, now allow slave to ACK
pinMode(SDApin, INPUT); // turn SDA to input for ACK
digitalWrite(SCLpin, HIGH);
delay(I2Cdelay);
// ACK received here with a bit of luck (we may test some day)
// read input line
tempint = digitalRead(SDApin);
if (tempint == 0) { // acked OK
MyAck = 1;
}
else { // failed
MyAck = 0;
}
digitalWrite(SCLpin, LOW);
delay(I2Cdelay);
digitalWrite(SDApin, HIGH); // set output register high before shanging DDR
pinMode(SDApin, OUTPUT); // turn SDA back to an output
digitalWrite(SDApin, HIGH); // set output high to exit
delay(I2Cdelay);
return MyAck;
}
uint8_t LDACwriteByte(uint8_t outchar){
// Enters with SCL LOW, SDA undefined Hi or Low, LDAC High
// SDA set to output
//
// Leaves with SCL LOW, SDA HIGH, LDAC Low
// SDA set to output
//
// returns 1 if acked OK, 0 if not
int shuffle;
uint8_t MyAck;
int tempint;
shuffle = 9; // 8 clocks
while (--shuffle) {
if (outchar & 0x80)
digitalWrite(SDApin, HIGH);
else
digitalWrite(SDApin, LOW);
delay(I2Cdelay);
digitalWrite(SCLpin, HIGH);
delay(I2Cdelay);
outchar <<= 1; // shift up data for bext bit
digitalWrite(SCLpin, LOW);
delay(I2Cdelay);
}
// Now we drop the LDAC pin to initiate the EEPROM command
digitalWrite(LDACpin, LOW); // LDAC Low
delay(I2Cdelay);
// Completed sending byte, now allow slave to ACK
pinMode(SDApin, INPUT); // turn SDA to input for ACK
digitalWrite(SCLpin, HIGH);
// ACK received here with a bit of luck (we may test some day)
// read input line
tempint = digitalRead(SDApin);
if (tempint == 0) { // acked OK
MyAck = 1;
}
else { // failed
MyAck = 0;
}
delay(I2Cdelay);
digitalWrite(SCLpin, LOW);
delay(I2Cdelay);
digitalWrite(SDApin, HIGH); // set output register high before shanging DDR
pinMode(SDApin, OUTPUT); // turn SDA back to an output
digitalWrite(SDApin, HIGH); // set output high to exit
delay(I2Cdelay);
return MyAck;
}
void loop() {
// continually announce the status...
if (Success == 1) {
Serial.println("DAC Address succesfully set to new value.");
}
else {
Serial.print("DAC Address Set procedure FAILED!! I2C ACK was missing at Byte number ");
Serial.println(FailByte, DEC);
}
delay(3000); // wait for a few seconds
// Our work is done. Power cycle and programme another
}