SPI and force sensor

Hello!

I'm asking for help in using SPI to obtain measurements of a microforce sensor:
(Datasheet) https://www.farnell.com/datasheets/3676773.pdf
I'm using the 5N one that uses SPI.
Details on that specific sensor communication attached.

I'm struggling with the code. My code aims to read the sent value (for me to use it later to calculate force in Newtons). The sensor does not receive data therefore a MOSI is not required.

I'm using Seeeduino XIAO for this project and I've connected the sensor as shown (pardon my soldering):


My code:

#include <SPI.h>
//Using XIAO's D3/A3 pin for the SS/CS of the sensor
const int slaveAPin = 3;

// set up the speed, data order and data mode
// the speed was selected using the datasheet, I'm not so sure about which  SPI_MODE to use
//I've tried all SPI_MODEX options and no luck
SPISettings settingsA(100000, MSBFIRST, SPI_MODE0);

void setup() {
  // set the Slave Select Pins as outputs:
  pinMode (slaveAPin, OUTPUT);
  // initialize SPI:
  SPI.begin();

 // start serial port at 9600 bps, I would like to see the value received from the sensor for //debugging
  Serial.begin(9600);
}
//Variable where I'll store value sent by sensor
float val1; //Or shall I use byte?

void loop() {
//Set spi using the settings
  SPI.beginTransaction(settingsA);
//As I understood in the pic attached, the sensor works with a falling edge
  digitalWrite (slaveAPin, LOW);
  // I don't know what value to use in SPI.transfer() function, as the sensor does not receive data
  val1 = SPI.transfer(0); //receive sensor data and store in val1

//Finish communication
  digitalWrite (slaveAPin, HIGH);
  SPI.endTransaction();

    Serial.println(val1);

}

I'm pretty sure you need both MOSI and MISO - esp. since data comes back from the force sensor.

Curiously this sensor doesn't have a MOSI pin. This is the pinout:
Screenshot 2023-08-30 141452
(Ignore the I2C column)

So it's read-only; there's nothing to send to it.

Yes, my problem is that I don't know how to read the data from the sensor , any reccommendations/corrections to my code are welcomed :slight_smile: I'm new at using SPI communication

No, you don't.

If the sensor doesn't receive anything from the Master, there's no need for a MOSI.

Should be exactly the same as any other SPI device - just leave the MOSI disconnected.

EDIT

As it says, "SPI transfer is based on a simultaneous send and receive" - so, even though this sensor doesn't use MOSI, your code will have to send some dummy data just to get the process working. That dummy data won't go anywhere (you're not connecting anything to MOSI), but is needed just to keep things happy.

Yup I have nothing connected at the MOSI pin. I've read through the Arduino SPI reference and followed other tutorials/examples. My code above is the furthest I've gotten but I get 0.00 on the serial output, so either I'm not reading the sensor data, I'm not reading and storing it on the correct variable type or something else, I've tried many things and haven't found a solution. Therefore if anyone has any pointers on what to change in my code i'd really appreciate it.

I've tried that with this line. I'm sending 0 in order to store what the sensor is sending in val1.

val1 = SPI.transfer(0);

So far no luck, serial shows "0.00"

Does it change if you apply force to the sensor?

ie, is the sensor actually reading zero?

Nope, which makes me think that something in my code is not working (i.e. I'm not reading the value the sensor is sending via SPI or not handling it properly afterwards, sadly I don't know how to fix it :frowning: )

@manupau7

looking at the spec + code I think

  1. The SPISettings should be SPI_MODE1 as the databits should be read on the rising edge.
    https://docs.arduino.cc/learn/communication/spi

  2. you need to read four bytes (just all of them)

  3. Make val1 an uint32_t

  4. Begin SPI transaction after the select.


include <SPI.h>

//  Using XIAO's D3/A3 pin for the SS/CS of the sensor
const int slaveAPin = 3;

//  set up the speed, data order and data mode
//  the speed was selected using the datasheet, I'm not so sure about which  SPI_MODE to use
//  I've tried all SPI_MODEX options and no luck
SPISettings settingsA(100000, MSBFIRST, SPI_MODE1);

uint32_t val1;

void setup() 
{
  //  set the Slave Select Pins as outputs:
  pinMode (slaveAPin, OUTPUT);

  //  initialize SPI:
  SPI.begin();

 //  start serial port at 9600 bps, I would like to see the value received from the sensor for 
 //  debugging
  Serial.begin(9600);
}


void loop() 
{
  //  the sensor selection works with SS/CS LOW
  digitalWrite (slaveAPin, LOW);

  //  Set SPI using the settings
  SPI.beginTransaction(settingsA);

  // I don't know what value to use in SPI.transfer() function, as the sensor does not receive data
  val1 = SPI.transfer(0); //receive sensor data and store in val1
  val1 *= 256;
  val1 += SPI.transfer(0);
  val1 *= 256;
  val1 += SPI.transfer(0); //receive sensor data and store in val1
  val1 *= 256;
  val1 += SPI.transfer(0); //receive sensor data and store in val1

  SPI.endTransaction();

  //  Finish communication
  digitalWrite (slaveAPin, HIGH);

    Serial.println(val1, HEX);
}

Please give it a try

The extract posted in the OP says that the 3rd & 4th bytes are optional. it also shows reading just a single byte.

@manupau7 Where did that extract come from? please post a link to the full document.

Although it's equivalent, It would be more descriptive to write this as a shift - as that is what's happening:

val1 = val1 << 8;  // Shift-up 8 bits, ready for the next 8 bits to come into the low byte

Here's the link :wink:

1 Like

Agree, shift 8 is equivalent.
Goal is to get all bytes the sensor provides.

reading 1 bytes just gives the status bits (0, 0 ==> normal operation,
and the 6 MSB bits, which can be 0 when no or low force is applied.

I've tried the code including awneil's modification, still no luck :frowning: I've checked sensor connections to the board with my multimeter just in case and everything is fine.

Here's the code I tried:

#include <SPI.h>

//  Using XIAO's D3/A3 pin for the SS/CS of the sensor
const int slaveAPin = 3;

//  set up the speed, data order and data mode
//  the speed was selected using the datasheet, I'm not so sure about which  SPI_MODE to use
//  I've tried all SPI_MODEX options and no luck
SPISettings settingsA(100000, MSBFIRST, SPI_MODE1);

uint32_t val1;

void setup() 
{
  //  set the Slave Select Pins as outputs:
  pinMode (slaveAPin, OUTPUT);

  //  initialize SPI:
  SPI.begin();

 //  start serial port at 9600 bps, I would like to see the value received from the sensor for 
 //  debugging
  Serial.begin(9600);
}


void loop() 
{
  //  the sensor selection works with SS/CS LOW
  digitalWrite (slaveAPin, LOW);

  //  Set SPI using the settings
  SPI.beginTransaction(settingsA);

  
val1 = val1 << 8;  // Shift-up 8 bits, ready for the next 8 bits to come into the low byte

  SPI.endTransaction();

  //  Finish communication
  digitalWrite (slaveAPin, HIGH);

    Serial.println(val1, HEX);
}

You did not run the code as I provided. (reading 4 bytes!)
There is nothing read from the SPI bus

I copied and pasted your code as you provided it, but it didn't work. I also modified

val1 = val1 << 8; 

to

val1 = val1 << 4; 

for 4 bits but also didn't work.

Please run this sketch and post the output

include <SPI.h>

//  Using XIAO's D3/A3 pin for the SS/CS of the sensor
const int slaveAPin = 3;

//  set up the speed, data order and data mode
//  the speed was selected using the datasheet, I'm not so sure about which  SPI_MODE to use
//  I've tried all SPI_MODEX options and no luck
SPISettings settingsA(100000, MSBFIRST, SPI_MODE1);

uint32_t val1;

void setup() 
{
  //  set the Slave Select Pins as outputs:
  pinMode (slaveAPin, OUTPUT);

  //  initialize SPI:
  SPI.begin();

 //  start serial port at 9600 bps, I would like to see the value received from the sensor for 
 //  debugging
  Serial.begin(9600);
}


void loop() 
{
  //  the sensor selection works with SS/CS LOW
  digitalWrite (slaveAPin, LOW);

  //  Set SPI using the settings
  SPI.beginTransaction(settingsA);

  //  transfer 4 bytes from SPI
  val1 = SPI.transfer(0); // transfer byte 1 
  val1 *= 256;
  val1 += SPI.transfer(0); // transfer byte 2
  val1 *= 256;
  val1 += SPI.transfer(0); // transfer byte 3 
  val1 *= 256;
  val1 += SPI.transfer(0); // transfer byte 4

  SPI.endTransaction();

  //  Finish communication
  digitalWrite (slaveAPin, HIGH);

    Serial.println(val1, HEX);
}

(updated comments)

@manupau7
Your original code only has two mistakes.
Val1 should be a byte
You need to do a second transfer for another byte Val2