MLX90129 - SPI protocol

Hi, I don’t know if someone has already worked with the MLX90129. Right now, I’m trying to establish the SPI protocol between MLX90129 and an Arduino. I’m using the example that it is showed in the datasheet respecting the SPI protocol where I send a write command, the address targeted, and the 2-byte data to write and then wait the required time for data writing. So, I’m sending 0xABCD (hexadecimal) to the slave(MLX90129), and then it is supposed to read in the same wrote address and getting back 0xABCD. It happens that I don’t get the desired 0xABCD on the MISO line, and all I get is 0xFF. Here’s the code:

#include <avr/io.h>
#include <util/delay.h>
/*-------- SPI -------------
SS => PB2 => OUTPUT
MOSI => PB3 => OUTPUT
MISO => PB4 => INPUT
SCK => PB5 => OUTPUT
---------------------------- */
#define PORTSPI PORTB
#define SS      PB2
#define MOSI    PB3
#define MISO    PB4
#define SCK     PB5

#define SS_H   PORTB=(1<<SS) // SS line with high level output
#define SS_L   PORTB=(0<<SS) // SS line with low level output

#define DDR_SPI    DDRB // set the pins of PORTB as Input or Output
#define DD_SS      DDB2 // set the pin PB2 as Input or Output
#define DD_MOSI    DDB3 // set the pin PB3 as Input or Output
#define DD_MISO    DDB4 // set the pin PB4 as Input or Output
#define DD_SCK     DDB5 // set the pin PB5 as Input or Output


void setup() {
  Serial.begin(9600);
  SPI_MasterInit();
 
}

void loop() {
  SS_H;
  SPI_MLX90129_write(); // write 0xABCD in EERPOM #11
  SPI_MLX90129_update();// update register file
  SPI_MLX90129_read(); // read in Register #11
  Serial.println("-");
}
/*--------------------SPI_MasterInit---------------------*/
void SPI_MasterInit(void)
{

/* Set SS, MOSI and SCK output, MISO input */
DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);
/* Enable SPI, Master, set clock rate fck/16 = 1MHz */
SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
//SPSR = (0<<SPI2X);
}
/*-------------------------------------------------------*/

/*-------------------SPI_MasterTransmit------------------*/
char SPI_MasterTransmit(char cData)
{
/* Start transmission */
SPDR = cData;
/* Wait for transmission complete */
while(!(SPSR & (1<<SPIF)));
/* Return Data Register */
Serial.println(SPDR, HEX);
return SPDR;
}
/*-------------------------------------------------------*/

/*-------------------SPI_MLX90129_write------------------*/
void SPI_MLX90129_write(void)
{
 
char write_command;
char address;
char data_MSB;
char data_LSB;
// Write EEPROM at address 0x11 with data 0xABCD
write_command=0x0E;
address=0x11;
data_MSB=0xAB;
data_LSB=0xCD;
SS_L; // SS low selects the slave for the communication
//_delay_us(0.6);
//_delay_us(1500); // delay only when MLX90129 is in sleep mode
SPI_MasterTransmit(write_command);
SPI_MasterTransmit(address);
SPI_MasterTransmit(data_MSB);
SPI_MasterTransmit(data_LSB);
//_delay_us(0.5);
SS_H; //SS high deselects the slave and end the communication
_delay_ms(17); // delay to write EEPROM
//_delay_ms(11); // delay to write EELAtch
//_delay_us(0.5);
}
/*-------------------------------------------------------*/

/*-------------------SPI_MLX90129_read-------------------*/
void SPI_MLX90129_read(void)
{
char read_command;
char address;
char data_MSB;
char data_LSB;
// Read Register at address 0x11
read_command=0x0F;
address=0x11;
data_MSB=0xFF;
data_LSB=0xFF;
SS_L; // SS low selects the slave for the communication
//_delay_us(1500); // delay only when MLX90129 is in sleep mode
// send read command and targeted address
SPI_MasterTransmit(read_command);
SPI_MasterTransmit(address);
//_delay_us(50); // delay to read EEPROM
_delay_us(2); // delay to read Register file
//_delay_us(2); // delay to read EELAtch
//_delay_us(430); // minimum delay to read ADC output
// send 0x00 (or other random data) to generate SPI clock
// and get the slave answer
data_MSB=SPI_MasterTransmit(0x00);
data_LSB=SPI_MasterTransmit(0x00);
SS_H; // SS high deselects the slave and end the communication
Serial.println(data_MSB, HEX);
Serial.println(data_LSB, HEX);
}
/*-------------------------------------------------------*/

/*------------------SPI_MLX90129_update------------------*/
void SPI_MLX90129_update(void)
{
char update_command;
// Update command =0x1C
update_command=0x1C;
SS_L; // SS low selects the slave for the communication
//_delay_us(0.6);
// send the update command
SPI_MasterTransmit(update_command);
SS_H; // SS high deselects the slave and end the communication
_delay_us(1500); // delay for the update of the registers
}
/*-------------------------------------------------------*/

I’m reading the value from the serial monitor, and I get slightly different values when I change the baud rate. Can that be the problem? Should I use a display to see the data coming out from the MISO line? Can the MLX90129 be damaged? I don’t think the problem is the code because that code is made available by the chip producers.

MLX90129’s SPI lines only support 3.3V (is what the datasheet respecting SPI says), and as I was using an Arduino with an operating voltage of 5V with a level shifter, I thought that was the problem. But I also tested with an Arduino DUE, which has an operating voltage of 3.3V, and I wasn’t successful. I can’t figure out where the problem is.

On Due the SPI pins are:

(3.3V level)
MOSI SPI-4
MOSI SPI-1
SCK SPI-3
SS (master) 4, 10 or 52

Assuming you have connected everything correctly and the chip is undamaged,please try the following code if you can. (I've adapted the sample code provide in the datasheet to be arduino IDE friendly! :wink: ):

Compiles, not tested!

#include <SPI.h>

#define SS 10

/*-------------------SPI_MLX90129_write------------------*/
void SPI_MLX90129_write(void) {
  uint8_t write_command;
  uint8_t address;
  uint8_t data_MSB;
  uint8_t data_LSB;

  // Write EEPROM at address 0x11 with data 0xABCD

  write_command = 0x0E;
  address = 0x11;
  data_MSB = 0xAB;
  data_LSB = 0xCD;

  Serial.print(F("Value written to EEPROM: "));
  Serial.print(data_MSB, HEX);
  Serial.println(data_LSB, HEX);

  digitalWrite(SS, LOW); // SS low selects the slave for the communication
  //delayMicroseconds(1500); // delay only when MLX90129 is in sleep mode

  SPI.transfer(write_command);
  SPI.transfer(address);
  SPI.transfer(data_MSB);
  SPI.transfer(data_LSB);

  digitalWrite(SS, HIGH); //SS high deselects the slave and end the communication

  delay(17);  // delay to write EEPROM
  //delay(11); // delay to write EELAtch

}
/*-------------------------------------------------------*/

/*------------------SPI_MLX90129_update------------------*/
void SPI_MLX90129_update(void) {
  uint8_t update_command;

  // Update command =0x1C
  update_command = 0x1C;

  digitalWrite(SS, LOW); // SS low selects the slave for the communication

  // send the update command
  SPI.transfer(update_command);

  digitalWrite(SS, HIGH);  // SS high deselects the slave and end the communication
  delayMicroseconds(1500); // delay for the update of the registers

}
/*-------------------------------------------------------*/

/*-------------------SPI_MLX90129_read-------------------*/
void SPI_MLX90129_read(void) {
  uint8_t read_command;
  uint8_t address;
  uint8_t data_MSB;
  uint8_t data_LSB;

  // Read Register at address 0x11
  read_command = 0x0F;
  address = 0x11;

  digitalWrite(SS, LOW); // SS low selects the slave for the communication
  //delayMicroseconds(1500); // delay only when MLX90129 is in sleep mode

  // send read command and targeted address
  SPI.transfer(read_command);
  SPI.transfer(address);

  //delay(50);    // delay to read EEPROM
  delayMicroseconds(2);   // delay to read Register file
  //delayMicroseconds(2);  // delay to read EELAtch
  //delayMicroseconds(430); // minimum delay to read ADC output

  // send 0x00 (or other random data) to generate SPI clock    // and get the slave answer
  data_MSB = SPI.transfer(0x00);
  data_LSB = SPI.transfer(0x00);

  digitalWrite(SS, HIGH); // SS high deselects the slave and end the communication

  Serial.print(F("Read back Value: "));
  Serial.print(data_MSB, HEX);
  Serial.println(data_LSB, HEX);
}
/*-------------------------------------------------------*/

void setup() {
  // put your setup code here, to run once:

  //Initialise Serial Monitor Comms
  Serial.begin (115200);

  //SPI initialisation
  SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE1)); // set the clk frequency 1MHz; take the MSB first;
  //mode1 for CPOL=0 and CPHA=1 (SPI_MODE1)
  pinMode(SS, OUTPUT);
  digitalWrite(SS, HIGH);

  Serial.println(F("//****MLX90129 Read/Write Demo****\\"));

  SPI_MLX90129_write(); // write 0xABCD in EERPOM #11
  SPI_MLX90129_update();// update register file
  SPI_MLX90129_read();  // read in Register #11
}

void loop() {
  // put your main code here, to run repeatedly:
}

Hope that helps....

Thanks for the reply. I had to add a SPI.begin() to your code in order to work and I’ve changed the SPI mode to 0. I’ve tested and it doesn’t work (the result is the same).

I’ve attached the MLX90129 datasheet. Right now a have MISO, MOSI, CS and SCK connected to the arduino DUE. I’m not sure if I have to connect the VBAT and VSS (ground) as well. However, when I connect them, the values sent to the MLX90129 (that are 0xE11ABCD1CF11) don’t show up at the console and are replaced by F’s.

MLX90129-Datasheet-Melexis.pdf (1.53 MB)