Search code examples
raspberry-pipi4j

Pi4J v2 SPI w/ GPIO Pin


I'm trying to use Pi4J to talk to an SPI device where the CS pin is a GPIO pin (GPIO 5) and not one of the mapped CS pins. I don't see how to configure it this way in any of the examples or javadocs. I think it would be somewhere on my SpiConfig line.

        // Initialize Pi4J with an auto context
        // An auto context includes AUTO-DETECT BINDINGS enabled
        // which will load all detected Pi4J extension libraries
        // (Platforms and Providers) in the class path
        var pi4j = Pi4J.newAutoContext();

        // create SPI config
        SpiConfig config = Spi.newConfigBuilder(pi4j).id("thermocouple-1")
                        .name("Thermocouple 1").bus(SpiBus.BUS_1)
                        .chipSelect(SpiChipSelect.CS_0).build();

        // get a SPI I/O provider from the Pi4J context
        SpiProvider spiProvider = pi4j.provider("pigpio-spi");

        // use try-with-resources to auto-close SPI when complete
        try (Spi spi = spiProvider.create(config)) {
                byte data[] = new byte[]{0, 0, 0, 0};

It looks like this is possible with v1 of the library, but it's not the same in v2.


Solution

  • I ended up posting on the pi4j project on GitHub and through those conversations worked out what I needed. Here is a cross post from there.

    Well looking at the DAC8552 example was the key. Here is a working version that asks the device for it's ID (register 0xD0) and gives the correct answer for BME280 (0x60). Thanks for the assist. Here is the working code (needs to be cleaned up, but it's a basic start).

    package com.pi4j.example.spi;
    
    import com.pi4j.Pi4J;
    import com.pi4j.context.Context;
    import com.pi4j.io.gpio.digital.DigitalOutput;
    import com.pi4j.io.gpio.digital.DigitalState;
    import com.pi4j.io.spi.Spi;
    import com.pi4j.io.spi.SpiBus;
    import com.pi4j.io.spi.SpiChipSelect;
    import com.pi4j.io.spi.SpiMode;
    import com.pi4j.util.Console;
    import com.pi4j.util.StringUtil;
    
    public class BmeTest {
    
        private static final SpiBus spiBus = SpiBus.BUS_0;
    
        public static void main(String[] args) throws Exception {
            final var console = new Console();
    
            // print program title/header
            console.title("<-- The Pi4J Project -->",
                    "Basic SPI Communications Example");
    
            Context pi4j = Pi4J.newAutoContext();
            var spiConfig = Spi.newConfigBuilder(pi4j)
                    .id("SPI" + spiBus + "_BME280")
                    .name("BME280")
                    .bus(spiBus)
                    .chipSelect(SpiChipSelect.CS_0) // not used
                    .mode(SpiMode.MODE_0)
                    .provider("pigpio-spi")
                    .build();
    
            // required all configs
            var outputConfig = DigitalOutput.newConfigBuilder(pi4j)
                    .id("CS_GPIO5")
                    .name("CS GPIO5")
                    .address(5)
                    .shutdown(DigitalState.HIGH)
                    .initial(DigitalState.HIGH)
                    .provider("pigpio-digital-output");
    
            DigitalOutput csGpio = null;
            try {
                csGpio = pi4j.create(outputConfig);
            } catch (Exception e) {
                e.printStackTrace();
                console.println("create DigOut DRDY failed");
                System.exit(202);
            }
    
            // use try-with-resources to auto-close SPI when complete
            try (var spi = pi4j.create(spiConfig)) {
                byte data[] = new byte[] { (byte) (0x80 | 0xD0), (byte) 0x00 };
    
                csGpio.high();
                csGpio.low();
                spi.transfer(data, data);
                csGpio.high();
    
                // take a breath to allow time for the SPI
                // data to get updated in the SPI device
                Thread.sleep(100);
    
                // read data back from the SPI channel
                console.println("--------------------------------------");
                console.println("SPI [READ] :");
                console.println("  [BYTES]  0x" + StringUtil.toHexString(data));
                console.println("  [STRING] " + new String(data));
                console.println("--------------------------------------");
            }
    
            // shutdown Pi4J
            console.println("ATTEMPTING TO SHUTDOWN/TERMINATE THIS PROGRAM");
            pi4j.shutdown();
        }
    }
    

    With the following output:

    [main] INFO com.pi4j.util.Console - ************************************************************
    [main] INFO com.pi4j.util.Console - ************************************************************
    [main] INFO com.pi4j.util.Console -
    [main] INFO com.pi4j.util.Console - <-- The Pi4J Project -->
    [main] INFO com.pi4j.util.Console - Basic SPI Communications Example
    [main] INFO com.pi4j.util.Console -
    [main] INFO com.pi4j.util.Console - ************************************************************
    [main] INFO com.pi4j.util.Console - ************************************************************
    [main] INFO com.pi4j.util.Console -
    [main] INFO com.pi4j.Pi4J - New auto context
    [main] INFO com.pi4j.Pi4J - New context builder
    [main] INFO com.pi4j.platform.impl.DefaultRuntimePlatforms - adding platform to managed platform map [id=raspberrypi; name=RaspberryPi Platform; priority=5; class=com.pi4j.plugin.raspberrypi.platform.RaspberryPiPlatform]
    [main] INFO com.pi4j.util.Console - --------------------------------------
    [main] INFO com.pi4j.util.Console - SPI [READ] :
    [main] INFO com.pi4j.util.Console - [BYTES] 0xFF 60
    [main] INFO com.pi4j.util.Console - [STRING] �`
    [main] INFO com.pi4j.util.Console - --------------------------------------
    [main] INFO com.pi4j.util.Console - ATTEMPTING TO SHUTDOWN/TERMINATE THIS PROGRAM