1

I have hardwired a MCP3008 IC into the SPI input on a Raspberry Pi3.

MCP3008 is wired as follows:

pin 10 (CS) to Pi GPIO_10 (pin 24) this is CE0

pin 11 (Din) to Pi GPIO_12 (pin 19) this is MOSI

pin 12 (Dout) to Pi GPIO_13 (pin 21) this is MISO

pin 13 (CLK) to Pi GPIO_14 (pin 23) this is SCLK

I am using a single TMP36 wired into channel 0, pin 1 of the MCP3008.

When I measure the voltage of the TMP36 output it is correlating to the measured surface temperature of the board it is mounted to, which is approximately 23 degrees celsius. For those interested, I am using a Fluke 62 MAX+ IR thermometer to take the measurement.

My problem is twofold:

1) I read nothing but zero in my java program, and in a python script I wrote for comparison. Here is the output I get when I make a HTTP GET request to the resource.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<gpioRepresentation>
    <garageDoorFeedbackState>LOW</garageDoorFeedbackState>
    <zoneOneState>LOW</zoneOneState>
    <zoneTwoState>LOW</zoneTwoState>
    <zoneThreeState>LOW</zoneThreeState>
    <garageDoorRelayState>LOW</garageDoorRelayState>
    <panelTemperature>0.0</panelTemperature>
    <zoneOneRelayState>LOW</zoneOneRelayState>
    <zoneThreeRelayState>LOW</zoneThreeRelayState>
    <zoneTwoRelayState>LOW</zoneTwoRelayState>
</gpioRepresentation>

2) Why is both CE0 and CE1 measuring 3.3Vdc?

My understanding of SPI is that the active channel must have its corresponding chip select logic level LOW or 0Vdc. So why is it high? How can I drive it low using the pi4j library or in python?

Here is the class with the code I wrote for this. I have included all imports, fields, and the constructor. I have omitted getters and setters as they take too much space and aren't relevant to this.

...

import com.pi4j.gpio.extension.base.AdcGpioProvider;
import com.pi4j.gpio.extension.mcp.MCP3008GpioProvider;
import com.pi4j.gpio.extension.mcp.MCP3008Pin;
import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.GpioPinAnalogInput;
import com.pi4j.io.gpio.GpioPinDigitalInput;
import com.pi4j.io.gpio.GpioPinDigitalOutput;
import com.pi4j.io.gpio.PinPullResistance;
import com.pi4j.io.gpio.PinState;
import com.pi4j.io.gpio.RaspiPin;
import com.pi4j.io.gpio.event.GpioPinAnalogValueChangeEvent;
import com.pi4j.io.gpio.event.GpioPinDigitalStateChangeEvent;
import com.pi4j.io.gpio.event.GpioPinListenerAnalog;
import com.pi4j.io.gpio.event.GpioPinListenerDigital;
import com.pi4j.io.spi.SpiChannel;
import com.pi4j.io.spi.SpiMode;

...

/**
 * Class that models the physical Raspberry Pi resources and represents them in XML.
 * Access methods to read and write physical I/O state are synchronized to 
 * maintain consistent state of the GPIO when multiple users are accessing
 * the controls.
 * Only one object of this class is to ever exist, as it is a representation
 * of this physical real world device that it resides on.
 */
@XmlRootElement
public class GpioRepresentation implements GpioSubject, EventSubject 
{
    private static GpioRepresentation gpioRepresentation = null;
    private GpioObserver observingResource;
    private EventObserver eventObserver;
    private final GpioController gpio;
    ...
    private final AdcGpioProvider provider;
    private final GpioPinAnalogInput rawInput;

    ...

    @XmlTransient
    private double panelTemperature;

    private GpioRepresentation() throws IOException
    {
        //get instance of gpio factory object
        gpio = GpioFactory.getInstance();

        ...

        // Create custom MCP3008 analog gpio provider
        provider = new MCP3008GpioProvider(SpiChannel.CS0, SpiMode.MODE_0);

        // Provision gpio analog input pins for all channels of the MCP3008.
        rawInput= gpio.provisionAnalogInputPin(provider, MCP3008Pin.CH0, "MyAnalogInput-CH0");

        // Define the amount that the ADC input conversion value must change before
        // a 'GpioPinAnalogValueChangeEvent' is raised.  This is used to prevent unnecessary
        // event dispatching for an analog input that may have an acceptable or expected
        // range of value drift.
        provider.setEventThreshold(100, rawInput);

        // Set the background monitoring interval timer for the underlying framework to
        // interrogate the ADC chip for input conversion values.  
        provider.setMonitorInterval(250);

        // Create an analog pin value change listener
        GpioPinListenerAnalog aDClistener = new GpioPinListenerAnalog()
        {
            public void handleGpioPinAnalogValueChangeEvent(GpioPinAnalogValueChangeEvent event)
            {
                // get RAW value
                double value = event.getValue();

                //calculate the temperature
                calculateTemperature(value);

            }
        };

        // Register the gpio analog input listener for input
        gpio.addListener(aDClistener, rawInput);

    }

    public void calculateTemperature(double raw)
    {
        double millivolts = raw * ( 3300.0 / 1023.0 );
        panelTemperature = ((millivolts - 500.0) / 10.0);
    }

    @XmlElement
    public synchronized double getPanelTemperature()
    {
        return panelTemperature;
    }

    ... (other methods omitted)
}

As an FYI, SPI has been configured/enabled on my Pi. I am using Ubuntu Mate as my OS.

Here are some pictures of the physical connections. Breakoutboard connections

MCP3008 Connections

Please note that on the MCP3008 connections, Pin 10 is correctly grounded, and that pins 11, 12, 13, and 14 are connected to the Pi.

Here is the schematic for the MCP3008 connections. Ignore the pin numbers, I need to update this.

MCP3008 schematic

And here is the CAD drawing showing the interconnections. Please note I have redlined the prints I am working for and need to update this drawing to show that I already swapped the white and black wire on the breakout board for MOSI and MISO.

CAD Drawing

9
  • Just a quick comment on your code. To demonstrate you problem, you should have pared down the code to just what is needed to demonstrate your question. Anything more than what is necessary and sufficient to show us just hides the problem.
    – NomadMaker
    Jul 12, 2018 at 16:38
  • A clear photo showing the connections will be useful (clear in the sense that we can trace wires end to end and identify the pin numbers).
    – joan
    Jul 12, 2018 at 17:37
  • I'd also get it working with Python first. You only need ten lines of code or so to just take a reading. Any PI4J problems are probably best asked on the PI4J site.
    – joan
    Jul 12, 2018 at 17:42
  • All -> I have trimmed back the code block for easier reading...though I have left all of the import statements for pi4j. I have included the best pictures I can get for now, and included a couple screenshot from my drawing set....note this are not 'as - builts' and I still need to make final edits. Lastly, I would like to keep the focus on the code being Java and the pi4j library. I only used python for quick and dirty testing, but the project must work with Java. Thanks, Mike
    – mike
    Jul 12, 2018 at 18:35
  • I would approach this differently. Simplify the wiring and code to a minimum. Get that working. You can then proceed with confidence to complicate the wiring and code as much as you want as you know you have a working baseline. At the moment you have no idea where the problem lies.
    – joan
    Jul 12, 2018 at 20:16

2 Answers 2

1

When using the SPI peripheral, rather than bitbanging it, you have to follow the documentation.

On the Raspberry Pi 3, there is one SPI bus, with two (and only two) connections. The pins needed are:

  • MOSI - pin 19(Master Out Slave In) used to transfer data TO the Raspberry Pi
  • MISO - pin 21 used to transfer data FROM the Raspberry Pi
  • SCLK - pin 23 the SPI clock

Of course you also need ground and power. And you also need one of the chip enable (sometimes called "Chip select" pins, CE0 pin 24 or CE0 pin 26.) In documentation these pins are written with a bar over the CE part indicating that they use a logical low for selection an a logic high for a non-selection.

The CE pins will only be driven low when for the duration of a transfer (well, really a few cycles before and after).

These pins are built into the peripheral. Changing these is not a good thing. You need to follow the directions that are in the Raspberry Pi SPI Documentation. Once you've gone through these directions, then feel free to experiment further. I suggest taking one step at a time. Add only one new thing and test it before going on to something else.

Adding other Chip Enables is undefined. The CE pins are part of the SPI peripheral. I'm sure that it is possible to push it a little. I did this on a different chip a long time ago, but that was well before the Raspberry PI came out.

And I really think that you need to remove the extra boards because it's difficult to say where the problem is. Once you have simplified everything, then it should be a lot easier to debug, as @joan strongly suggested.

I really hope that your project goes well. I think that you went too far before you tested things. One suggestion is to keep a Raspberry Pi for testing purposes. I would install Raspian on this machine to make it as compatible as possible. I would also keep it clean of any additional hardware. That way you can test a new something new and know that no other hardware is causing that problem. Once you've gotten the code to work on that piece, then slowly add hardware until you've moved to where you want to be, adding new programming as you need to.

4
  • Remember that all the Pis with the 40 pin expansion header expose two SPI buses. The main SPI has two chip selects, the auxiliary SPI has three chip selects. E.g. see abyz.me.uk/rpi/pigpio/python.html#spi_open
    – joan
    Jul 13, 2018 at 7:54
  • Alright, back from my weekend vacation.
    – mike
    Jul 17, 2018 at 15:35
  • Wiring is correct. This is a software/OS issue. I have performed a loopback test (C spidev_test), and it was unsuccessful on the first several attempts. I then powered off the pi, and restarted. After restarting, I ran the loopback test, and for what ever reason it was successful. Please note that when I enabled SPI in the first place, I only performed a reboot, and did not cycle power.....this was what the documentation said to do.
    – mike
    Jul 17, 2018 at 16:07
  • When I reconnected the MCP3008, I WAS reading a panel temperature. However, after restarting the service (my application), or rebooting, I can not get the application to read a temperature.....but what changed??? At the moment I do not know. I can not seem to replicate the problem. What I have noted is when I run the CLI command 'gpio readall', MOSI, MISO, SCLK are set to Mode 'ALT0' (which is correct for SPI comms), but CEO is set to 'OUT'. Why? Should it not be ALT0 as well? If I manually set this to ALT0, and reboot, it reverts back to 'OUT'.
    – mike
    Jul 17, 2018 at 16:07
1

This isn't really an answer, but what I did to get SPI to work. I reformatted my uSD card with a clean installation of Ubuntu Mate 16.04.5, installed wiringPi, the pi4j libraries, and Oracle Java. I tested SPI using the spidevtest.c and the example programs supplied with pi4j and SPI work flawlessly.

1
  • No wiring changes were required either.
    – mike
    Jul 20, 2018 at 16:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.