SPI Communication issues with E-Series/Electron

Hello. I am currently trying to communicate with a pH sensor using SPI communication with the ADC built into the sensor. (The sensor is a Microsens MSFET 3332 and the ADC on the sensor is a ADC121S021.

Currently, I am confident with the wiring:

The E-Series is the “master” outputting the Chip Select from pin D5, the CLK from D4, and inputting the data from the sensor (MISO) in pin D3. I have all the ground wires to a common GND and I am sending 9V power to the sensor.

Below is the code (adapted from which was an Arduino code from the company, Microsens). The code is supposed to take 2 bytes (1 at a time), and merge them (the sensor outputs data 12 bits) to get the “result”. The void loop takes that data, averages the result from 5 responses, and calculates the pH from mV. Every time I run this code, I am receiving 0’s on my end. I have probed the bits coming out of “SPI.transfer(0x00)” and am still getting zeros from the code/sensor.

#include <Particle.h>

SYSTEM_MODE(MANUAL);

const int cs = D5;

void setup() {
  Cellular.off();
  Serial.begin(9600); 
  SPI1.begin();
  SPI1.setClockSpeed(20, MHZ);   //Clockspeed will be 20MHz 
  SPI1.setBitOrder(MSBFIRST);    // MSBFIRST = most-significant bit first (based on MSFET3332)
  SPI1.setDataMode(SPI_MODE0); 
}

//Read from ADC:
unsigned int readADC() {
  byte inByte = 0;     // incoming byte from the SPI
  unsigned int result = 0;  // result to return

  SPI1.beginTransaction(); 
  digitalWrite(cs, LOW); 
  
  // send a value of 0 to read the first byte returned:
  result = SPI1.transfer(0x00); 
 
  // shift the first byte left, then get the second byte:
  result = result << 8;
  inByte = SPI1.transfer(0x00);
  
  // combine the byte receieved w/ the previous one:
  result = result | inByte;
  result = result >> 0;
  result = result & 0b0000111111111111;
  
  digitalWrite(cs, HIGH);
  SPI1.endTransaction();

  // return the result:
  return (result);
}

void loop() {
  //define variable
  double avg_pH = 0;  
  double Data_pH;
  for(int a=0;a<5;a++) {
        Data_pH = readADC();  
        avg_pH = avg_pH + Data_pH;
        delay(10);
   }
  double pH_mV = avg_pH/5*5000/4095;                    
  
  //display data to serial monitor
  Serial.print("pH:  ");  Serial.println(pH_mV);
  delay(100);
}


Let me know if you have any advice or need more information,
Thanks! Any input is appreciated.

@GarrettSSchmid, a few things to note:

  • SPI1 has a reference clock of 30MHz (unlike 60MHz for SPI). With the minimum clock divider of DIV2, the highest SPI1 clock speed is 15MHz. Your 20MHz setting will not work.

  • You may want to review the documentation for SPI1.beginTransaction(). This command is designed to allow multiple SPI devices with dissimilar protocols (speed, bitorder, etc.) to coexist on the SPI bus. The beginTransaction() function is called with defined SPISettings. You have no arguments! In your case I suggest the following:

void setup() {
  Cellular.off();
  Serial.begin(9600); 
  SPI1.begin();
}

//Read from ADC:
unsigned int readADC() {
  byte inByte = 0;     // incoming byte from the SPI
  unsigned int result = 0;  // result to return

  SPI1.beginTransaction(__SPISetting(15*MHZ, MSBFIRST, SPI_MODE0)); 
  digitalWrite(cs, LOW); 
  ...

Thank you for your response. I changed both the clock maximum frequency to 15 MHz and added arguments within the SPI.begintransaction() command. Unfortunately the response from the sensor is still 0. Below I tried to simplify the code as much as possible to get at the root of the output bits but it still does not seem to work.

Am I possibly missing any commands needed to communicate with SPI? And if possible, could you verify I have defined my variables correctly?

I am thinking it may be a problem with the sensor because I can’t seem to find an issue with the code.

#include <Particle.h>
SYSTEM_MODE(MANUAL);

// Chip select is pin D5
const int CS = D5;

void setup() {
  Cellular.off();
  Serial.begin(9600);              
  SPI1.begin(SPI_MODE_MASTER, CS);
}

// Read from ADC:
double readADC() {
  byte inByte = 0;       // incoming byte from the SPI
  unsigned int result = 0;     // result to return
                                      
  SPI1.beginTransaction(__SPISettings(15*MHZ, MSBFIRST, SPI_MODE0));      
  digitalWrite(CS, LOW);       // chip select to LOW  
  result = SPI1.transfer(0x00);   
      Serial.print("Probe 1:  "); Serial.println(result);
  result = result << 8;     
  result |= SPI1.transfer(0x00);                   
  result = result | inByte;
  digitalWrite(CS, HIGH);
  SPI1.endTransaction();
  return (result);
}

void loop() {
  //display data to serial monitor
  Serial.print("output = ");
  Serial.println(readADC());
  delay(1000); 
}

@GarrettSSchmid, looking at the datasheet for the sensor and it seems to output 5V logic levels though it is alarmingly unclear. The Particle devices use 3.3v SPI bus levels and though the Photon and Electron SPI are tolerant to 5V input, they only put out 3.3v when HIGH. It is not clear if the sensor will operate correctly under those conditions. You need to consider:

  • Make sure the GND from the power supply for the sensor is connected to the GND of the Particle device.
  • You should use a level shifter (5v to 3.3v) for the SDD signal coming from the sensor. You could also use a level shifter (3.3v to 5v) for the CS line as well though may not be necessary.

image

Thank you for the response. I have just purchased a bi-directional logic level converter from 3.3v to 5v and hopefully this will solve the problem.

Will keep you updated,
Garrett

1 Like