Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ The following table the currently supported devices within this project:
| A/D | SPI | | [MCP3008 A/D 10bit converter](src/main/java/com/pi4j/devices/mcp3008/README.md)
| A/D | SPI | | [MCP3208 A/D 12bit converter](src/main/java/com/pi4j/devices/mcp3208/README.md)
| D/A | I2C | | [MCP4725 12 bit DAC](src/main/java/com/pi4j/devices/mcp4725/README.md)
| D/A | I2C | | [MCP4728 12 bit DAC 4-ch](src/main/java/com/pi4j/devices/mcp4728/README.md)
| D/A | SPI | | [MCP4921 12 bit DAC](src/main/java/com/pi4j/devices/mcp4921/README.md)
| D/A | SPI | | [MCP4922 12 bit DAC](src/main/java/com/pi4j/devices/mcp4922/README.md)
| HAT | | | [Raspberry SenseHat](src/main/java/com/pi4j/examples/hat/raspberry/sensehat/)
Expand Down
2 changes: 2 additions & 0 deletions assets/runMcp4728.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env bash
java -classpath ./*:../classes com.pi4j.devices.mcp4728.MCP4728App $@
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
<!-- DEPENDENCIES VERSIONS 2.0.3 -SNAPSHOT -->
<slf4j.version>2.0.17</slf4j.version>
<pi4j.version>4.0.1</pi4j.version>
<!--pi4j.version>5.0.0-SNAPSHOT</pi4j.version-->
<!--pi4j.version>5.0.0-SNAPSHOT</pi4j.version -->

<!-- BUILD PLUGIN VERSIONS -->
<exec-maven-plugin.version>1.6.0</exec-maven-plugin.version>
Expand Down
260 changes: 260 additions & 0 deletions src/main/java/com/pi4j/devices/mcp4728/MCP4728App.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@


package com.pi4j.devices.mcp4728;

import com.pi4j.Pi4J;
import com.pi4j.context.Context;
import com.pi4j.drivers.io.da.mcp472x.Mcp4728Driver;
import com.pi4j.io.i2c.I2C;
import com.pi4j.io.i2c.I2CImplementation;
import com.pi4j.util.Console;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Support MCP4728 DAC.
*<p>
* Support the single channel at a time functions of the chip. Example: you cannot set
* all four channels vref bit in a single call. Rather this would require
* four separate calls to the driver code.
*</p>
* <p>
* The MCP4728 ships with device address 0x60. To set other address the DAC config registers
* must be updated. The update process requires the LDAC pin be toggled at a specific point
* in the I2C command as it is clocked into the chip. This GPIO control within the I2C
* traffic is not possible with Pi4j. To accomplish this would require ordering the chip with
* the address programmed, or use of an MCU.
* </p>
* @see <a href="https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/22187E.pdf">MCP4728</a>
*
*
* The MCP4728 chip contains an EEPROM. When Powered-on or RESET, the EEPROM contents are used to update
* the DAC volatile registers, restoring the configured output voltages. The program arguments that result
* in the EEPROM being updated that code examples include the statement dacChip.setEepromEnabled(true);.
* After this method all subsequent methods will ensure the EEPROM is updated. To stop this behavior the
* examples call dacChip.setEepromEnabled(false);
*
* The example uses the letters A B C D to specify the channel. This conforms to the chips Datasheet documentation.
* Within the driver method signatures and code the channel is specified with an int.
*
*/
public class MCP4728App {

static void main(String[] args) {
System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "INFO");
Logger logger = LoggerFactory.getLogger(MCP4728App.class);
logger.trace(">>> Enter: init");

Context pi4j = Pi4J.newAutoContext();

final Console console = new Console();
console.print("==============================================================");
console.print("startup MCP4728App ");
console.print("==============================================================");



int busNum = 1;
int address = MCP4728_Declares._MCP4728_DEFAULT_ADDRESS;
int channel = 0;
boolean doReset = false;
int registerData = 0;
double vref = 0;
float volts = 0;
int onlyOne = 0; // numerous parms a mutually exclusive
int gainBit = 0;
int vrefBit = 1;
boolean setVrefBit = false;
boolean setGainBit = false;
boolean setOutputDigital = false;
boolean setOutputVotage = false;
boolean persistValues = false;



String helpString = " parms: -b 0x? hex value bus -a 0x?? hex value address \n " +
" -r reset chip -ch channel A B C D -d digital value (0 ... 4095) \n" +
" -v voltage (0 ... vdd) -pu persist values true/false -vdd decimal reference voltage \n" +
" -sv vrefBit 0 or 1 -sg gainBit 0 or 1 \n" +
"-d -v -sv -sg mutually exclusive \n" ;
;
for (int i = 0; i < args.length; i++) {
String o = args[i];
if (o.contentEquals("-b")) { // bus
String a = args[i + 1];
busNum = Integer.parseInt(a.substring(2), 16);
i++;
} else if (o.contentEquals("-a")) { // device address
String a = args[i + 1];
i++;
address = Integer.parseInt(a.substring(2), 16);
} else if (o.contentEquals("-sv")) {
String a = args[i + 1];
vrefBit = Integer.parseInt(a);
setVrefBit = true;
if ( (gainBit <0) || (gainBit > 1) ){
console.println("vrefBit must be in range 0..1");
System.exit(55);
}
i++;
onlyOne ++;
} else if (o.contentEquals("-sg")) {
String a = args[i + 1];
gainBit = Integer.parseInt(a);
setGainBit = true;
if ( (gainBit <0) || (gainBit > 1) ){
console.println("gainBit must be in range 0..1");
System.exit(55);
}
i++;
onlyOne ++;
} else if (o.contentEquals("-ch")) {
String a = args[i + 1];
i++;
if (a.equalsIgnoreCase("A")) {
channel = 0;
} else if (a.equalsIgnoreCase("B")) {
channel = 1;
} else if (a.equalsIgnoreCase("C")) {
channel = 2;
} else if (a.equalsIgnoreCase("D")) {
channel = 3;
} else {
console.println(" -ch invalid ");
System.exit(53);
}
} else if (o.contentEquals("-vdd")) { // reference voltage
String a = args[i + 1];
i++;
vref = Float.parseFloat(a);
} else if (o.contentEquals("-r")) {
doReset = true;
}else if (o.contentEquals("-pv")) {
String a = args[i + 1];
persistValues = Boolean.parseBoolean(a);
i++;
} else if (o.contentEquals("-d")) {
String a = args[i + 1];
i++;
registerData = Integer.parseInt(a);
setOutputDigital = true;
if (registerData < 0 || registerData > 4095) {
console.println("-rde must be in range 0..4095");
System.exit(36);
}
onlyOne ++;
} else if (o.contentEquals("-h")) {
console.println(helpString);
System.exit(39);
} else if (o.contentEquals("-v")) { // eeprom volts
String a = args[i + 1];
i++;
setOutputVotage = true;
volts = Float.parseFloat(a);
onlyOne ++;
} else {
console.println(" !!! Invalid Parm " + o);
console.println(helpString);
System.exit(42);
}
}

if (onlyOne > 1 ) {
console.println(" mutually exclusive parms used.");
console.println(helpString);
System.exit(43);
}

if ( (vref == 0) || (vref < 0) ){
console.println("-vdd is zero or less than zero");
System.exit(50);

}
if ( (volts > vref) || (volts < 0) ) {
console.println("-v greater than -vdd, or less than zero");
System.exit(51);

}

if ( (volts > vref) || (volts < 0) ) {
console.println("-ef greater than -vdd, or less than zero");
System.exit(52);

}

Mcp4728Driver dacChip ;
I2C genCallDevice = null ;


I2C i2cDev = createI2cDevice("MCP4728", busNum, address, I2CImplementation.DIRECT, pi4j) ;
dacChip = new Mcp4728Driver( i2cDev, vref);


if (doReset) {
genCallDevice = createI2cDevice("GenCallReset", busNum,0x00, I2CImplementation.SMBUS, pi4j);
dacChip.resetChip(genCallDevice);
}

logger.info("\nBefore state : \n" + dacChip);

dacChip.setEepromEnabled(persistValues);

if (setGainBit) {
dacChip.setGain(channel,gainBit);
}

if (setVrefBit) {
dacChip.setVref(channel,vrefBit);
}

if (setOutputDigital) {
dacChip.setDigitalValue(channel, registerData);
}

if (setOutputVotage) {
dacChip.setVoltage(channel, volts);
}



logger.info("\nCompletion state : \n" + dacChip);


if (genCallDevice != null) {
genCallDevice.close();
}
if (i2cDev != null) {
i2cDev.close();
}


}



/**
*
* @param chipType String Part numer
* @param bus INT
* @param address INT
* @param pi4j Context
* @return I2C device
*/
static I2C createI2cDevice( String chipType, int bus, int address, I2CImplementation impType, Context pi4j) {
String id = String.format("0X%02x: ", bus);
String name = String.format("0X%02x: ", address);
var i2cDeviceConfig = I2C.newConfigBuilder(pi4j)
.bus(bus)
.device(address)
.id(chipType + id + " " + name)
.name(name)
.i2cImplementation(impType)
.build();

return pi4j.create(i2cDeviceConfig);


}

}

69 changes: 69 additions & 0 deletions src/main/java/com/pi4j/devices/mcp4728/MCP4728_Declares.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@


package com.pi4j.devices.mcp4728;



public class MCP4728_Declares {
public static final int _MCP4728_DEFAULT_ADDRESS = 0x60;

public static final int _MCP4728_SET_EEPROM_SIZE = 0x06;
public static final int _MCP4728_SET_FAST_SIZE = 0x04;
public static final int _MCP4728_CHIP_READ_SIZE = 0x05;

// Table 5.1
public static final byte _MCP4728_WRITE_CMD_FAST = 0b00000000;
public static final byte _MCP4728_WRITE_CMD_MULTI_DAC_EEPROM = 0b01000000;
public static final byte _MCP4728_WRITE_CMD_SNGL_DAC_EEPROM = 0b01011000;

public static final byte _MCP4728_WRITE_CMD_I2C_ADDR = 0b01100000;


public static final byte _MCP4728_WRITE_CMD_SEQ_DAC_EEPROM = 0b01010000;

public static final byte _MCP4728_WRITE_CMD_VREF_SLCT_DAC = (byte) 0b10000000;
public static final byte _MCP4728_WRITE_CMD_GAIN_SLCT_DAC = (byte) 0b11000000;
public static final byte _MCP4728_WRITE_CMD_PD_BITS_DAC = (byte) 0b10100000;







public static final byte _MCP4728_PD_MODE_NORMAL = 0b00000000;
public static final byte _MCP4728_PD_MODE_INOPT = 0b00000110;

public static final byte _MCP4728_DAC_PD0_MODE_MASK = 0b00000010;
public static final byte _MCP4728_DAC_PD1_MODE_MASK = 0b00000100;

public static final int _MCP4728_EEPROM_PD1_MODE_MASK = 0b10000000;
public static final byte _MCP4728_EEPROM_PD0_MODE_MASK = 0b01000000;

// Indicate EEPROM write/update status
public static final byte _MCP4728_READ_CMD_RDY_BSY_MSK = (byte) 0b10000000;
public static final byte _MCP4728_READ_CMD_IS_COMPLT = (byte) 0b10000000;
public static final byte _MCP4728_READ_CMD_IS_NOT_COMPLT = (byte) 0b00000000;

// POR device load EEPROM
public static final byte _MCP4728_GEN_CALL_RESET_CMD = (byte) 0b00000110;

// POR device PD1 and PD0 set to 0 for normal operation
public static final byte _MCP4728_GEN_CALL_WAKEUP_CMD = (byte) 0b00001001;


// Write
// C2=0 C1=1 C0=0 DAC only
// C2=0 C1=1 C0=1 DAC and EEPROM
// byte1 byte2 byte3 byte4
// address r/w C2 C1 C0 x x PD1 PD0 X D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0 X X X X

// Read DAC
// byte1 byte2 byte3 byte4
// address r/w RDY/BSY C1 C0 x x PD1 PD0 X D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0 X X X X

// EEPROM
// byte5 byte6
// X PD1 PD0 X D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0

}
Loading
Loading