Multiple Slaves with SPI (MLX90333 Sensors and Arduino Micro)

Hey guys, I am still having issues with reading both sensors. I am pretty certain the issue lies within my code because when I check the MISO and MOSI lines of both sensors with an Oscilloscope I get voltage change as the a magnet is brought near. Also, I'm pretty sure I am just reading zeros for the second sensor, because when I apply a magnet to one sensor I will see in the serial monitor a series of non-zeros then a series of zeros then non-zeros then zeros and on and on. This leads me to my next issue, how do I get the two sensors reading to display side by side in the serial monitor?

The Serial protocol ckt that I am using is on page 42 of the following data sheet link:

https://www.melexis.com/-/media/files/.../datasheets/mlx90333-datasheet-melexis.pdf

The method in which I order the SPI system is displayed in the following picture where I used the already labeled slave select pin (pin 17)as my first slave select and pin 2 as my second Slave select pin:

My current code:

#include <SPI.h>
#include <stdint.h>

//*******Arduino MICRO SPI pins******** 

#define SS1 2

byte dataBuffer[8];

void setup() {
  Serial.begin(9600); 
  SPI.begin;
  pinMode(SS1, OUTPUT);
}

void loop() {
  delay(20); //MLX90333 startup takes 16ms
  SPI.beginTransaction(SPISettings(160000, MSBFIRST, SPI_MODE1)); //320000 is about max
  delay(5);
  int j;
  
  for (j=0; j<10; j++){
    digitalWrite(SS, LOW);
    delay(20);  //Short delay necessary here
    int i;
    for (i=0; i<8; i++){ 
      dataBuffer[i] = SPI.transfer(255);  // Must transfer 1's, 0's don't work
      }
    digitalWrite(SS, HIGH);
    
    SPI.endTransaction();
    Serial.print(dataBuffer[2],8); //Print 3rd byte, MSB for Alpha
    Serial.print(" ,");
    Serial.print(dataBuffer[4],8); //Print 5th byte, MSB for Beta
    Serial.println(" ,");
    }

   for (j=0; j<10; j++){
    digitalWrite(SS1, LOW);
    delay(20);  //Short delay necessary here
    int i;
    for (i=0; i<8; i++){ 
      dataBuffer[i] = SPI.transfer(255);  // Must transfer 1's, 0's don't work
      }
    digitalWrite(SS1, HIGH);
    
    SPI.endTransaction();
    Serial.print(dataBuffer[2],8); //Print 3rd byte, MSB for Alpha
    Serial.print(" ,");
    Serial.print(dataBuffer[4],8); //Print 5th byte, MSB for Beta
    Serial.println(" ,");
    }
  }

If anyone can help me with any of this I would greatly appreciate it!

Thanks!

Your code contains a call to SPI.beginTransaction(), a for loop with calls to SPI.transfer() with the SS pin LOW, and a call to SPI.endTransaction(). That part, you say, works.

Then, your code contains a for loop with calls to PI.transfer() with the SS1 pin LOW. That part, you say, doesn't work.

Gee, I wonder if those beginTransaction() and endTransaction() calls just might be important.

The method in which I order the SPI system is displayed in the following picture where I used the already labeled slave select pin (pin 17)as my first slave select and pin 2 as my second Slave select pin:

This a very interesting wiring diagram as the MLX90333 doesn't have separate MISO/MOSI pins, it has only one combined pin (so this interface is not SPI it's just SPI-like). That means you cannot use the hardware SPI interface but must use a software emulation (bit-bang) which changes the MISO/MOSI pin's mode depending on the state.

The datasheet shows a circuit that might work around that. For the Arduino Micro you should use version 2 (5V µCtrl w/o O.D. w/ 3.3V). Using that circuit you could try your code again.

Sorry for the delayed reply, I have been away from the lab for a while!

I changed the ckt to the "5V μCtrl w/o O.D. w/ 3.3V" version and now I get a much more enhanced output for my first sensor but my second sensor still doesn't pick anything up.

Any direction from here?

Any direction from here?

Post a wiring diagram of your actual current setup!

Here is the schematic you requested! Let me know if you have trouble reading any of it so I can clarify or redraw it for you!

The second chip has no MISO connection.

Anyway, the adaption circuit is meant to exist once per microcontroller, not per MLX chip (that's why the circuit is inside the "SPI Master" box in the example circuit). The way you implemented it the resistor values are cut in half which might lead to currents to high for the chip.

That does seem to make sense, but after trying it I am getting all zeros on my serial monitor.

I check all the lines going to the arduino with the 'scope and I am only seeing a reaction when I apply a magnetic field to the first sensor (the sensor using /ss as the slave select.)

This seems to be a ckt issue sort of problem but I have check the ckt a couple of times and I am not seeing any mistakes.

I attached a picture of my new schematic, does it seem alright. If so what direction should I take now?

In the schematics sensor 1 doesn't have Vss connected to GND.

In your code you have to define pin 10 (SS) as an output to put the SPI hardware into master mode.

And put both slave selects to HIGH by default (in setup()).

The ground is there I just forgot to draw it in that schematic!

Here is my updated code:

#include <SPI.h>
#include <stdint.h>

//*******Arduino MICRO SPI pins********
 
#define SS 10
#define SS1 2

byte dataBuffer[16];

void setup() {
  Serial.begin(9600); 
  SPI.begin;
  pinMode(SS1, OUTPUT);

  digitalWrite(SS1, HIGH);
  digitalWrite(SS, HIGH);

}

void loop() {

  //Sensor 1
  delay(20); //MLX90333 startup takes 16ms
  SPI.beginTransaction(SPISettings(160000, MSBFIRST, SPI_MODE1)); //320000 is about max
  delay(5);
  int j;
  
  for (j=0; j<10; j++){
    digitalWrite(SS, LOW);
    delay(20);  //Short delay necessary here
    int i;
    for (i=0; i<8; i++){ 
      dataBuffer[i] = SPI.transfer(65535);  // Must transfer 1's, 0's don't work
      }
    digitalWrite(SS, HIGH);
    digitalWrite(SS1, LOW);
    delay(20);  //Short delay necessary here
    for (i=8; i<16; i++){ 
      dataBuffer[i] = SPI.transfer(65535);  // Must transfer 1's, 0's don't work
      }
    digitalWrite(SS1, HIGH);
    
    SPI.endTransaction();
    Serial.print(dataBuffer[2],16); //Print 3rd byte, MSB for Alpha
    Serial.print(" ,");
    Serial.print(dataBuffer[4],16); //Print 5th byte, MSB for Beta
    Serial.print(" ,");
    Serial.print(dataBuffer[10],16); //Print 3rd byte, MSB for Alpha
    Serial.print(" ,");
    Serial.print(dataBuffer[12],16); //Print 5th byte, MSB for Beta
    Serial.println(" ,");
    }

  }

Let me know if the changes made were the proper changes.

I am still seeing all zeros on the serial plotter. However, when hooking the 'scope up I see a definite voltage fluctuation on the MOSI, MISO, SCK, /SS, and even the Pin 2 (sensor 2's SS line) when the magnet is over the first sensor. When I put the /SS over the second sensor I see a voltage fluctuation in the all the pins as well.

Note that the idle voltage at the SS pin is 2.7mV where the voltage at Pin 2 is 3.9V.

I'm not sure if some of this information is valuable or not I'm trying to relay as much info as possible with out making the message too long!

Let me know what you think!

Excuse me, I was wrong. SS is not D10 on the Micro, it's a separate pin (PB0). But it must be output, otherwise the SPI doesn't work as a master. Remove the definition, the IDE should have the correct value.

So I'm missing a pinMode(SS, OUTPUT);

Like this?

#include <SPI.h>
#include <stdint.h>

//*******Arduino MICRO SPI pins********
 
#define SS1 2

byte dataBuffer[16];

void setup() {
  Serial.begin(9600); 
  SPI.begin;
  pinMode(SS1, OUTPUT);
  pinMode(SS, OUTPUT);

  digitalWrite(SS1, HIGH);
  digitalWrite(SS, HIGH);

}

void loop() {

  //Sensor 1
  delay(20); //MLX90333 startup takes 16ms
  SPI.beginTransaction(SPISettings(160000, MSBFIRST, SPI_MODE1)); //320000 is about max
  delay(5);
  int j;
  
  for (j=0; j<10; j++){
    digitalWrite(SS, LOW);
    delay(20);  //Short delay necessary here
    int i;
    for (i=0; i<8; i++){ 
      dataBuffer[i] = SPI.transfer(65535);  // Must transfer 1's, 0's don't work
      }
    digitalWrite(SS, HIGH);
    digitalWrite(SS1, LOW);
    delay(20);  //Short delay necessary here
    for (i=8; i<16; i++){ 
      dataBuffer[i] = SPI.transfer(65535);  // Must transfer 1's, 0's don't work
      }
    digitalWrite(SS1, HIGH);
    
    SPI.endTransaction();
    Serial.print(dataBuffer[2],16); //Print 3rd byte, MSB for Alpha
    Serial.print(" ,");
    Serial.print(dataBuffer[4],16); //Print 5th byte, MSB for Beta
    Serial.print(" ,");
    Serial.print(dataBuffer[10],16); //Print 3rd byte, MSB for Alpha
    Serial.print(" ,");
    Serial.print(dataBuffer[12],16); //Print 5th byte, MSB for Beta
    Serial.println(" ,");
    }

  }

Like this?

Yes, although I would make two separate SPI transactions for the two devices. That's just to make the code better understandable, it shouldn't change the functionality.

You should call the SPI.begin() after the initialization of the SS pins, I don't think this make a difference but it's the way it should be.

Okay this is the code after those changes and I am still seeing all zeros:

#include <SPI.h>
#include <stdint.h>

//*******Arduino MICRO SPI pins********
 
#define SS1 2

byte dataBuffer[8];

void setup() { 
  
  pinMode(SS1, OUTPUT);
  pinMode(SS, OUTPUT);

  digitalWrite(SS1, HIGH);
  digitalWrite(SS, HIGH);
  Serial.begin(9600); 
  SPI.begin;
}

void loop() {

  //Sensor 1
  delay(20); //MLX90333 startup takes 16ms
  SPI.beginTransaction(SPISettings(160000, MSBFIRST, SPI_MODE1)); //320000 is about max
  delay(5);
  int j;
  
  for (j=0; j<10; j++){
    digitalWrite(SS, LOW);
    delay(20);  //Short delay necessary here
    int i;
    for (i=0; i<8; i++){ 
      dataBuffer[i] = SPI.transfer(255);  // Must transfer 1's, 0's don't work
      }
    digitalWrite(SS, HIGH);

    
    SPI.endTransaction();
    Serial.print(dataBuffer[2],8); //Print 3rd byte, MSB for Alpha
    Serial.print(", ");
    Serial.print(dataBuffer[4],8); //Print 5th byte, MSB for Beta
    Serial.print(", ");
    }

  //Sensor 2
  delay(20); //MLX90333 startup takes 16ms
  SPI.beginTransaction(SPISettings(160000, MSBFIRST, SPI_MODE1)); //320000 is about max
  delay(5);

  
  for (j=0; j<10; j++){
    digitalWrite(SS1, LOW);
    delay(20);  //Short delay necessary here
    int i;
    for (i=0; i<8; i++){ 
      dataBuffer[i] = SPI.transfer(255);  // Must transfer 1's, 0's don't work
      }
    digitalWrite(SS1, HIGH);

    
    SPI.endTransaction();
    Serial.print(dataBuffer[2],8); //Print 3rd byte, MSB for Alpha
    Serial.print(", ");
    Serial.print(dataBuffer[4],8); //Print 5th byte, MSB for Beta
    Serial.print(", ");
    }

  }

My MOSI has a very low voltage and not much reaction to applying a field. Also when I look at the clock (SCLK) I see a voltage change when I apply a field to first sensor but not the second sensor.. shouldn't there be no reaction here?

What type of MOSFET do you use on the MOSI pin? In my interpretation of the example schematic I would say it must be a p-channel MOSFET to deactivate it if MOSI is HIGH.

If you used a n-channel MOSFET I would try to change the value used in SPI.transfer() from 0xFF to 0x00.

It is a P-channel!

Spec Sheet for Mosfet

If I interpret the datasheet correctly, this has a to high saturation voltage. Have you tried to measure the resulting wave with a scope?

Interestingly the MOSFET the datasheet recommends (BS170) is a n-type but it has a considerably lower threshold voltage.

Okay so I attached 3 images of the signal I am seeing. The clock line is yellow and the MISO is the blue. The image labeled nomagnet show two flat lines which I thought was weird because shouldn't the clock always be on, or is there an on-board feature of the MLX90333 that only turns the clock on when a magnet is near?

The other two images (Magnet1 and Magnet2) are both images of the signals when the magnet is near. I can adjust the magnet in a way that I get a smooth output shown in magnet1 but sometime I end up with the mess shown in Magnet2.

I can try using an Nchannel, I don't have that exact model on hand but I do have ZVN2110A on hand

The image labeled nomagnet show two flat lines which I thought was weird because shouldn't the clock always be on, or is there an on-board feature of the MLX90333 that only turns the clock on when a magnet is near?

You should definitely see a clock signal at least when the CS line is low. May I ask you to connect the scope to that line in addition to the clock line and trigger on the falling edge of the CS line?

As the clock is handled by the Arduino the MLX90333 cannot switch that signal on and off.

None of the signals I see on the pictures is from a clear SPI signal. On what event were you triggering?

This might be a dumb question, but which one is the CS line?