I2C: Reading inputs from max7311

47 views
Skip to first unread message

Clemens Fuchs

unread,
Feb 23, 2020, 9:17:14 AM2/23/20
to Pi4J
Hi,

I'm trying to control an i2C IO-board with a Pi2. The board contains a max7311 IC, where 8 IOs are used as outputs and 8 as inputs. I managed to control the outputs and switch the connected relays on and off.
However, I'm struggling with the inputs. Whatever method I use to read from the input register seems to corrupt the bus and throws an exception. Below is the code I use for reading and writing.

When removing the read(); from the init(); method, the test() works fine and triggers all 8 outputs sequentially. Read always works once but then the bus seems corrupted.
Does anyone have an idea?

thx!


package i2c.max7311;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.pi4j.io.i2c.I2CBus;
import com.pi4j.io.i2c.I2CDevice;

import i2c.Util;

public class Max7311 {
    private static final Logger logger = LoggerFactory.getLogger(Max7311.class);
    private static final long MAX_RETRY_TIME = 3000l;

    interface ThrowingTask {
        void run() throws Exception;
    }

    /*
     * Max7311 registers.
     */
    private static final int InL = 0x0;
    private static final int InH = 0x1;
    private static final int OutL = 0x2;
    private static final int OutH = 0x3;
    private static final int PolInvL = 0x4;
    private static final int PolInvH = 0x5;
    private static final int DDR_L = 0x6;
    private static final int DDR_H = 0x7;
    private static final int TO_Reg = 0x8;

    private I2CDevice device;
    private byte address = -1;

    private List<OutPin> output = new ArrayList<OutPin>();
    private List<InPin> input = new ArrayList<InPin>();

    public void init(I2CBus bus, byte address) throws Exception {
        this.address = address;
        for (byte i = 0; i < 8; i++) {
            output.add(new OutPin(address, i));
            input.add(new InPin(address, i));
        }
        device = bus.getDevice(address);

        // low byte as output
        device.write(DDR_L, (byte) 0x00);
        Thread.sleep(100);
        // high byte as input
        device.write(DDR_H, (byte) 0xFF);

        // in order to init inputs correctly, first read operation is needed
        write();
        read();

        logger.debug("device at address {} initialized", device.getAddress());
    }

    private boolean runWithRetries(ThrowingTask t) throws Exception {
        long start = System.currentTimeMillis();
        while (true) {
            try {
                t.run();
                Thread.sleep(10);
                return true;
            } catch (Exception e) {
                if (System.currentTimeMillis() - start > MAX_RETRY_TIME) {
                    throw e;
                }
            }
        }
    }

    /**
     * Reads input pins and returns Pins where values changed.
     *
     *
     * @return
     * @throws IOException
     */
    public List<InPin> read() throws IOException {
        List<InPin> changes = new ArrayList<InPin>();

        int in = device.read((byte) InH);
        logger.debug("read: {}", in);

        if (in > 0) {
            byte data = (byte) ~in;

            for (InPin pin : input) {
                if (pin.update(data)) {
                    changes.add(pin);
                }
            }
        }
        return changes;
    }

    /**
     * Writes output pins
     *
     * @param data
     * @throws IOException
     */
    public void write() throws Exception {
        byte data = 0;
        for (OutPin pin : output) {
            if (pin.isSet()) {
                data |= pin.getMask();
                logger.debug("pin {} is set, mask={} data is now {}", pin.index, Util.toHex(pin.mask),
                        Util.toHex(data));
            }
        }
        write(data);
    }

    private void write(byte data) throws Exception {
        logger.debug("writing {} to {}", Util.toHex(data), Util.toHex(address));
        runWithRetries(() -> {
            device.write(OutL, data);
        });
    }

    public byte getAddress() {
        return address;
    }

    /**
     * tests outputs
     *
     * @throws IOException
     */
    public void test() throws Exception {
        for (int i = 0; i < 8; i++) {
            write((byte) (1 << i % 8));
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
            }
        }
        write((byte) 0);
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Max7311) {
            return ((Max7311) obj).address == address;
        }
        return false;
    }

    @Override
    public String toString() {
        return String.format("Max7311: %02X", address);
    }

    public InPin getInputPin(byte index) {
        if (index >= 0 && index < input.size()) {
            return input.get(index);
        }
        return null;
    }

    public OutPin getOutputPin(byte index) {
        if (index >= 0 && index < output.size()) {
            return output.get(index);
        }
        return null;
    }

    public List<OutPin> getOutputPins() {
        return new ArrayList<>(output);
    }
}



Clemens Fuchs

unread,
Feb 23, 2020, 10:16:47 AM2/23/20
to Pi4J
Got it working with simply using wiringPi.
However, as this library is deprecated, it would still be interesting to get it working with pi4j.

public class I2CWiringTest {
    private static final Logger logger = LoggerFactory.getLogger(I2CTest.class);

    /*
     * Max7311 registers.
     */
    private static final int InL = 0x0;
    private static final int InH = 0x1;
    private static final int OutL = 0x2;
    private static final int OutH = 0x3;
    private static final int PolInvL = 0x4;
    private static final int PolInvH = 0x5;
    private static final int DDR_L = 0x6;
    private static final int DDR_H = 0x7;
    private static final int TO_Reg = 0x8;

    public static void main(String[] args) throws Exception {
        int device = I2C.wiringPiI2CSetup(0x2b);
        if (device < 0) {
            logger.error("ERROR: {}", device);
        } else {
            logger.info("Initialized device {}", device);
            I2C.wiringPiI2CWriteReg8(device, DDR_L, 0x00);
            I2C.wiringPiI2CWriteReg8(device, DDR_H, 0xFF);

            test(device);

            while (true) {
                read(device);
                Thread.sleep(100);
            }

        }

    }

    private static void test(int device) throws Exception {
        for (int i = 0; i < 8; i++) {
            I2C.wiringPiI2CWriteReg8(device, OutL, (byte) (1 << i % 8));
            Thread.sleep(500);
        }
        I2C.wiringPiI2CWriteReg8(device, OutL, 0);
    }

    private static void read(int device) throws Exception {
        int data = I2C.wiringPiI2CReadReg8(device, InH);
        if (data > 0) {
            logger.info("data {}", Util.toHex((byte) ~data));
        }
    }

}


Frank Delporte

unread,
Feb 24, 2020, 6:15:00 AM2/24/20
to Pi4J
Hi

An alternative approach is using terminal commands from within Java with
Process p = Runtime.getRuntime().exec(cmd);


Frank
Reply all
Reply to author
Forward
0 new messages