# Help with understanding the Memory Map of MLX90393

(Using a Raspberry Pi 3 Model B+ and python)

I needed some assistance in understanding the memory map of MLX90393 I've attached the memory map here and you could also find it in the datasheet.

I'm a newbie especially for data processing. The information provided in the datasheet is a problem to me. I've spent last 7 days trying to understand it with nothing solid to work with. The sample code from the product page works very well and gives intended output. So far I've been just able to change just GAIN_SEL property because it's already in the sample code and has a variable for it to be changed and done a lot of trial and errors with non-sensible output. I know Bitwise conversions and I've worked with them before but I can't understand how exactly the host specifies the address register and the values for it in reference to the memory map. I've gone through all of the tutorials on Sparkfun and Adafruit and some other websites to understand I2C again. I know how I2C works about sending bytes and waiting for the responses and then reading data blocks but I simply don't know how to configure the sensor. (For example, how am I supposed to set DIG_FILT (digital property)?, How do I start it in burst mode?)

It really seems like a stupid question to me as well but I just don't know what I'm doing wrong.

If you guys can help me understand it or point me to link which will be useful that'll be great!

Here is the sample code for your reference :

# Distributed with a free-will license.
# Use it any way you want, profit or free, provided it fits in the licenses of its associated works.
# MLX90393
# This code is designed to work with the MLX90393_I2CS I2C Mini Module available from ControlEverything.com.
# https://www.controleverything.com/products

import smbus
import time

# Get I2C bus
bus = smbus.SMBus(1)

while True:
# Select write register command, 0x60(96)
# AH = 0x00, AL = 0x5C, GAIN_SEL = 5, Address register (0x00 << 2)
config = [0x00, 0x5C, 0x07]
bus.write_i2c_block_data(0x0C, 0x60, config)

# Read data back, 1 byte
# Status byte

# Select write register command, 0x60(96)
# AH = 0x02, AL = 0xB4, RES for magnetic measurement = 0, Address register (0x02 << 2)
config = [0x02, 0xB4, 0x08]
bus.write_i2c_block_data(0x0C, 0x60, config)

# Read data back, 1 byte
# Status byte
#FROM HERE
# Start single meaurement mode, X, Y, Z-Axis enabled
bus.write_byte(0x0C, 0x3E)

# Read data back, 1 byte
# Status byte

time.sleep(0.096)

# Read data back from 0x4E(78), 7 bytes
# Status, xMag msb, xMag lsb, yMag msb, yMag lsb, zMag msb, zMag lsb

# Convert the data
xMag = data[1] * 256 + data[2]
# if xMag > 32767 :
#   xMag -= 65536

yMag = data[3] * 256 + data[4]
# if yMag > 32767 :
#   yMag -= 65536

zMag = data[5] * 256 + data[6]
# if zMag > 32767 :
#   zMag -= 65536

# Output data to screen
print "Magnetic Field in X-Axis : %d" %xMag
print "Magnetic Field in Y-Axis : %d" %yMag
print "Magnetic Field in Z-Axis : %d" %zMag


This datasheet can be a bit confusing, but I have figured this out.

Here is the format of the Write Register command:

The actual command is 0x60 (bits abc zero as recommended in the datasheet)

From page 18:

The argument for the volatile memory access commands (RR/WR) «abc» should be set to 0x0h, in order to get normal read-out and write of the memory.

Looking at the code for the first write, we have:

config = [0x00, 0x5C, 0x07]

bus.write_i2c_block_data(0x0C, 0x60, config)

The bus_write_i2c_block() specifies the device address (0x12), the command (0x60) and the config block.

The config structure is ordered as Register Address, Data Low, Data High (Look back at the format and you will see that the last command item is the register address; as it is first in this list it is reasonable to see it as in reverse reading order)

The data to be loaded where I have expanded only the least significant byte:

So the gain field has been set to 0x05

So to use the block write function, look at the register you need, set up the bitfields from the memory map as required and separate to high and low byte then use the config this way:

config = [register address, low byte, high byte]

The bitfields are described in section 15.1

The command

bus.write_byte(0x0C, 0x3E)

is command 0x3[zyxt] with the zyxt (Z axis, Y axis, X axis, Temperature) bits set to 1110; measurements will be done on the Z,Y and X axis and the temperature measurements will not be done as the bits enable the first 3 items and not the last.

Note that the address shift left operation (as required by the address field) appears to be implemented in the write function.

The call

config = [0x02, 0xB4, 0x08]

bus.write_i2c_block_data(0x0C, 0x60, config)

Which sets the RES fields has 2 as the register argument, and the actual register with those fields in indeed register address 2.

With devices like this, you need to map the bitfields for each piece of functonality in a given 16 bit word (by using a template and seeing what the final result is).

In this example, the author has used hard coded constants.

You could use something like this (C syntax) for a more generic approach:

typedef struct
{
uint8_t DataLow;
uint8_t Datahigh;
}configdata;


// then a declaration

    configdata config;

//    and then fill it with: