I’m trying to use multiple LPS331 sensors (pololu.com/catalog/product/2126) with a single Arduino Uno. In order to do this, I need to use SPI instead of I2C. I’m having some trouble with this, however, and can’t determine what’s wrong.
The main problem is that when I try to read data from the sensor, the MISO line will go from high to low, and then to high again, and then won’t be able to go back low when it’s supposed to. Examples:
My first example, named “AveragingQueryIncorrect” shows the clock, chip select, MISO, and MOSI at the sensor pins, and the MOSI and clock at the arduino (I’m looking at both places because the wires are long and could contribute to the problem. Note the difference in the clock between the two. I don’t think this is the problem though because it doesn’t seem to get in the way in other situations). I’m reading the value of the RES_CONF registry, which I previously set to 00000010. The MISO line should read 00000010, but instead it outputs 00000011.
In the second example, “WhoAmIQueryIncorrect”, shows the same information with me reading the value of the WHO_AM_I registry, which should always read 10111011. However, instead the sensor is outputting 10111111. I know that the actual stored value is indeed 10111011, because the single sensor works just fine with I2C. That also leads me to believe that the sensor isn’t fundamentally broken or getting incorrect measurements.
This comes up in a few other places as well. In general it seems like the MISO line will go from HIGH to Low, and then HIGH again, but never back down to low.
There are a few other weird things I encounter that may contribute, but don’t seem to me to be the main problem. The difference between the clock at the sensor and the arduino, which you can see in my first example, could be a problem, although you don’t see it as much in the second example. In addition, sometimes there will be some weird spikes in the MOSI line at the sensor that don’t come from the arduino (see my third example) but as far as I can tell the sensor still interprets these correctly.
In addition, The wires I’m using for the clock, MOSI, power and ground are quite long (~2ft) although at the moment the chip select and MISO wires are much shorter (~8in). Since the shorter wire is what seems to be having the problem, I think it has more to do with the chip than with the wires, but I could be wrong.
What should I do at this point? Would it help to add pull-up or pull-down somewhere? Is the chip irreversibly broken in some way that only affects SPI and not I2C? Is there some way I could get 5 sensors working on a single Arduino board using I2c instead?
Thank you!
Here’s the code that I’m using:
//this is the SPI library- its functions are SPI.xxx
#include <SPI.h>
//enumerate chip select pins, of which there will be 5
const int chipSelectPin0 = 7; //connect sensor0 to Arduino 7
void setup() { //this loop happens once for setup
Serial.begin(9600); //enable reading out on serial monitor
SPI.begin(); //start SPI
//Send each bit with the most significant bit first, so
//if you send the byte 0b11010000, the sensor will see
//the 1 first and decide that that is bit 0, the next 1
//is bit 1,and the 0 after that is bit 2, etc.
//Each bit of each register is explained on the data sheet.
SPI.setBitOrder(MSBFIRST);
//Set the clock speed. Speed is the board speed divided by the number input into the function.
SPI.setClockDivider(64);
//Set the clock phase and polarity
SPI.setDataMode(SPI_MODE3);
//make all chip select pins outputs so we can control them
pinMode(chipSelectPin0, OUTPUT);
//Power down the sensor
digitalWrite(chipSelectPin0, LOW);
SPI.transfer(0b00100000);
delay(10);
SPI.transfer(0b00000000);
digitalWrite(chipSelectPin0, HIGH);
//average 16 data points in RES_CONF
digitalWrite(chipSelectPin0, LOW);
//register location is 0x10, written in bits 2-7 with MSb first
SPI.transfer(0b00010000); //write to register 0x10
delay(10);
SPI.transfer(0b00000010); //tell to average 16 data points
digitalWrite(chipSelectPin0, HIGH);
delay(100);
//query RES_CONF to make sure it worked
digitalWrite(chipSelectPin0, LOW);
SPI.transfer(0b10010000); //read from register 0x10
delay(10);
byte avg = SPI.transfer(0xFF); //read back result into variable
Serial.print("Averaging register ");
Serial.println(avg, BIN);
digitalWrite(chipSelectPin0, HIGH);
delay(100);
//This block puts sensor in active mode, sets speed to 25Hz
digitalWrite(chipSelectPin0, LOW); //turn on SPI for sensor 0
//Register address is 0x20 (20 in hex), or 100000 in binary.
//The first byte is telling whether to read/write, and address.
//The first two numbers are 00 for write, the address follows.
SPI.transfer(0b00100000); //write to address 0b100000 (0x20)
//The next byte is the data to be transferred, with bit 0 first.
//This next byte sets bits 0-3 high on the register CTRL_REG_1,
//which puts the sensor in active mode and sets speed to 25 Hz
delay(10);
SPI.transfer(0b00000000);
delay(10);
SPI.transfer(0b11000000); //put sensor in active mode, 25Hz
digitalWrite(chipSelectPin0, HIGH); //turn off SPI for sensor 0
delay(100);
//query WHO_AM_I
//This register should read out 0b10111011 if sensor is active.
digitalWrite(chipSelectPin0, LOW); //turn on SPI for sensor 0
//register location is 0x0F, or 001111 in binary
//the 10 in front means we're reading the register
SPI.transfer(0b10001111); //read from register 0x0F
delay(10);
byte who = SPI.transfer(0xFF); //read back result into variable
Serial.print("Who am I? "); //println is print + enter key
Serial.println(who, BIN); //print the variable in binary, return
digitalWrite(chipSelectPin0, HIGH); //turn off SPI for sensor 0
delay(100);
//query CTRL_REG_1
digitalWrite(chipSelectPin0, LOW);
SPI.transfer(0b10100000); //read from register 0x20
delay(10);
byte ctrl = SPI.transfer(0xFF); //read back result into variable
Serial.print("CTRL_REG_1 ");
Serial.println(ctrl, BIN);
digitalWrite(chipSelectPin0, HIGH);
delay(100);
}