Reading 2 SPI devices with Arduino Pro Micro

Hello. I’m working on a project where I need to read two MLX90316 angle readers via SPI. I’m going to use this library/code: Lab3 - Laboratory for Experimental Computer Science (modifying it to my needs).

I have not done any SPI projects yet, so I’m not sure if I got it right: I need to connect all MOSI, clocks, VCC and GND together in the 3 devices (the two angle readers and the arduino) and then the SS of each MLX to a different pin in the arduino that I’ll define in the code, right? or does it also need to go to the SS pin in the Arduino? and in that case, how will Arduino differentiate the two?

Thanks

On the Arduino, SS is the designated/suggested slave control pin that gets used by the SPI library as the default. However, any GPIO pin can be used for this purpose. What you might do, is to connect the first device to the default 'SS' pin and the remaining two on two additional GPIO pins. Or you can use any 3 pins of your choosing. The SS pin on the MLX should connect to only one GPIO pin on the Arduino. Make sure that the GPIO pins being used are all set OUTPUT and level HIGH and then drive each one, one at a time only, LOW to enable communication with the connected specific device and start the transmission. It needs to be raised it HIGH again when transmission has finished. Possibly, the library you are using will do this automatically anyway. Only one device should be allowed to talk on the bus at any given time.

Also the MISO pins.

2 Likes

The sensor is actually a pre-built system, it's not a build from scratch project. It's in a flight sim throttle that uses these sensors for the throttles and I gutted the electronics and wanted to replace them with a Pro Micro. I'm just using the enclosure, buttons and sensors.

Very much like in the link I posted in my original message, this sensor only has 5 wires coming out of it, and I matched them with the 5 outputs of the schematic in the link, which are vcc, gnd, mosi, clock and ss. No miso in there.

I'll try to test reading them later today

Ok, tested it and it didn’t work. I researched a bit more and came accross this:

Mine is a BCG chip, which probably means SPI isn’t going to work. I need to dig a bit more to see if I can figure out how to read a “standard” chip.

The datasheet also has this, so I guess I need to add some mosfet and resistors before the Arduino:

But honestly, this goes a bit beyond my knowledge, I’m not educated enough to be able to read the datasheet and come out with a plan. I believe if it was a BDG chip it would be easier to just use the code from link in the first post, so I’m considering replacing the chips, which is something I do feel confortable doing.

Before I go down that route, anyone kind enough to help me with what would I need to do to use the existing BCG chip?

Thank you

Nevermind, I made a rookie mistake. Due to soldering wires from the non-labeled side of the nano, I accidentally wired VCC and GND to the opposite side of the board. I did change it and now I can properly read the chip. At least one of them, I haven’t tested reading two of them yet, but I don’t think it should be a problem.

Ok, it’s not working with 2 devices. It does work with 1 device and the pins in the code below:

/* MLX90316 Rotary Position Sensor
 * KHM 2010 /  Martin Nawrath
 * Kunsthochschule fuer Medien Koeln
 * Academy of Media Arts Cologne
 */
#include "Metro.h"     //Include Metro library
#include "MLX90316.h"  // Include MLX90316 library

int pinSS = 5;
int pinSCK = 3;
int pinMOSI = 4;
int ii;
Metro mlxMetro = Metro(5);
MLX90316 mlx_1  = MLX90316();
void setup(){
  Serial.begin(115200);
  mlx_1.attach(pinSS,pinSCK, pinMOSI );
  Serial.println(" MLX90316 Rotary Position Sensor");
}

void loop() {
  if (mlxMetro.check() == 1) {
    ii = mlx_1.readAngle();
    Serial.print(ii);
    Serial.println("");
  }
}

I am testing with a nano for now. Why are those pins working if those are not the nano’s MOSI, SCK and SS pins?

I modified the code for the two devices like this:

/* MLX90316 Rotary Position Sensor
   KHM 2010 /  Martin Nawrath
   Kunsthochschule fuer Medien Koeln
   Academy of Media Arts Cologne
*/
#include "Metro.h"     //Include Metro library
#include "MLX90316.h"  // Include MLX90316 library

int pinSS1 = 6;
int pinSS2 = 5;
int pinSCK = 3;
int pinMOSI = 4;
int ii;
Metro mlxMetro1 = Metro(5);
Metro mlxMetro2 = Metro(6);
MLX90316 mlx_1  = MLX90316();
MLX90316 mlx_2  = MLX90316();
void setup() {
  Serial.begin(115200);
  mlx_1.attach(pinSS1, pinSCK, pinMOSI );
  mlx_2.attach(pinSS2, pinSCK, pinMOSI );
  Serial.println(" MLX90316 Rotary Position Sensor");
}

void loop() {
  if (mlxMetro1.check() == 1) {
    ii = mlx_1.readAngle();
    Serial.print(ii);
    //Serial.println("");
  }
  Serial.print(" - ");
  if (mlxMetro2.check() == 1) {
    ii = mlx_2.readAngle();
    Serial.print(ii);
    Serial.println("");
  }
}

but it doesn’t work. None of the two devices work, it just reads nonsense.

I think the reason it doesn't use the Nano's SPI pins is because it isn't using SPI. In real SPI, data goes out to the sensor on MOSI, and comes in from the sensor on MISO. But your device uses the same line for both, so it isn't using the Nano's SPI peripheral. I think that means the libraries you're using are doing all the communication for you. If it all works properly for one sensor, then you would need to look into the library code to see if it will allow for two devices. If it won't, perhaps it will be possible to alternate between sensors - use one, then shut it down, then use the other one. Do you have links to the two libraries?

Edit: Figure 14 of the datasheet shows using two devices. So the question is whether the libraries support that, and how.

The MLX one is this one: https://interface.khm.de/wp-content/uploads/2010/05/Mlx90316.zip

The Metro one I had to google it to find it, it’s not in that same page: GitHub - nusolar/Metro: Metro library for Arduino or Wiring

I don't see anything in the libraries suggesting that two sensors can be used. But this is really above my pay grade. Perhaps someone else can see something useful. Actually, it may be possible to modify the library to provide for two devices. The MLX library is quite short.

I'm checking the metro library and I think the Metro(5) doesn't relate to pin 5, but instead 5ms, so it looks like the metro variables and declarations don't need to be duplicated. That may have been creating issues. I'll try a new code without that

You can use a lot of sensors on a SPI network, if properly implemented. Each device must have its own CS\ chip select. You also need to configure MOSI and MISO properly. SPI is basically a pair of shift registers configured so when you shift data in, you also get data out. You cannot get data out unless you input data. What you input is entirely depending on the devices you are using. You have have to have the clock polarity and phase set up for the configuration you are using.

This will explain it to you, start with this: Basics of the SPI Communication Protocol followed by this: https://www.circuitbasics.com/basics-of-the-spi-communication-protocol/

Thanks, but I don't think this device is actually using SPI for communication. If you look at my posts above, the one I have is not the SPI version, but the standard. I haven't had a look at the mlx library, but I have a gut feeling it's reading a pwm signal. Hence why it's working to read one, even if mosi and clk are not in the actual arduino mosi and clock pins

Here's the "SPI" code from the library. It looks like bit banging to me:

//*************************************************************
// send and receive SPI byte  to/from MLX90316 Chip
uint8_t  MLX90316::_spiByte(uint8_t  tx) {
  byte rxb=0;

  for (int ix = 0; ix < 8; ix++){  // receive/transmit 8 SPI bits

    digitalWrite(_pinMOSI,0);   // turn port internal pullup resistor off
    pinMode(_pinMOSI,OUTPUT);   // switch MOSI pin to output

    // write SPI transmit bit to sensor
    if ((tx & 1) != 0) digitalWrite(_pinMOSI,1); 
    else digitalWrite(_pinMOSI,0);
    tx= ( tx >> 1);

    digitalWrite(_pinSCK,1);    // clocksignal positive slope

    digitalWrite(_pinSCK,0);   // clocksignal negative slope

    pinMode(_pinMOSI,INPUT);    // switch MOSI pin to input
    digitalWrite(_pinMOSI,1);   // turn port internal pullup resistor on

    rxb = ( rxb << 1);           // shift received byte left
    if (digitalRead(_pinMOSI) ==1) rxb = rxb | 1; // read respose bit from sensor

    digitalWrite(_pinMOSI,0);   // turn port internal pullup resistor off
    pinMode(_pinMOSI,OUTPUT);   // switch MOSI pin to output
  }
  return(rxb);
}

Feels like the library is calling it SPI, but it's basically reading a byte (which I believe it's essentially what SPI communication does, I believe)

Yes, but it is a very good idea to make one of those 3 pins to be the Arduino SS pin. The reason is that this pin acts as the CS input pin when the AtTmega chip is acting as an SPI slave device.

In this application, you would want the ATmega to act as the SPI master device, and to ensure that, you need to set the SS pin to be OUTPUT.

If you don't use the SS pin and leave it as a floating input pin, unwanted, unexpected and random things can happen!

This advice applies when using the hardware SPI on ATmega and other chips. Reading the more recent posts, it now seems that hardware SPI isn't being used after all in this project.

So considering I’m going to need 2 SS pins to read the two devices, for the nano, your suggestion would be that one of those pins should be pin 10? and it doesn’t matter what the other one is?

Only if you are using the Nano's hardware SPI. But reading the more recent posts, it seems like you are not.

I’m not, and it seemed to be working fine with one device. I still need to figure out how to do it for two. And if hooking one of the SS to the actual arduino’s SS pin is the best way to go, I can still do that

If you are not using hardware SPI, you can use any pins you want. Hardware SPI would be much faster, but that may not be important here because only small amounts of data are being sent over the bus.