0
\$\begingroup\$

(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:
    # MLX90393 address, 0x0C(12)
    # 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
    data = bus.read_byte(0x0C)

    # MLX90393 address, 0x0C(12)
    # 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
    data = bus.read_byte(0x0C)
    #FROM HERE
    # MLX90393 address, 0x0C(12)
    # Start single meaurement mode, X, Y, Z-Axis enabled
    bus.write_byte(0x0C, 0x3E)

    # Read data back, 1 byte
    # Status byte
    data = bus.read_byte(0x0C)

    time.sleep(0.096)

    # MLX90393 address, 0x0C(12)
    # Read data back from 0x4E(78), 7 bytes
    # Status, xMag msb, xMag lsb, yMag msb, yMag lsb, zMag msb, zMag lsb
    data = bus.read_i2c_block_data(0x0C, 0x4E, 7)

    # 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

enter image description here

\$\endgroup\$
0
\$\begingroup\$

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

Here is the format of the Write Register command: Write Register command format

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:

Gain and HALLCONF settings

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 Address;
uint8_t DataLow;
uint8_t Datahigh;
}configdata;

// then a declaration

    configdata config;

//    and then fill it with:

    config.Address = <address>;
    config.DataLow = <data low>;
    config.Datahigh = <data high>;

That should get you going.

\$\endgroup\$
  • \$\begingroup\$ I understood the WR part, GAIN_SEL defining part(only the 3 binaries part) and the 0x3[tzyxt] part, thanks! I really appreciate the quick response and the help! I'm really confused about High and Low byte part. The snippet pic you've attached showing 0x7 and 0x5C with binary part is where I'm confused. 0x5C translates to 0b01011100 and I think what you're saying is something related to overwriting of bytes(pardon my programming French) and even if we consider 0x7 doing something to the D8:D0 part(?) it doesn't gather well. An example might help. Thanks again! \$\endgroup\$ – BLOODHOUND Sep 4 at 12:22
  • \$\begingroup\$ 0b01010111 = 0x57 so why is it in the place of 0x5C, have we used any operators or something to combine bytes like that? That's what I can gather from separation instructions in your answer. \$\endgroup\$ – BLOODHOUND Sep 4 at 12:33
  • \$\begingroup\$ Are you suggesting that I decide the configuration values first and get their binary values (For example, GAIN_SEL = 5 = 101 in binary) take the binary and place it in the 7 bit according to memory map and in the command space and use the grand binary's hex (grand binary = 01110000 for D0:D8 so grand binary's hex = 0x70) and place the hex in the place for data low? That would make sense. \$\endgroup\$ – BLOODHOUND Sep 4 at 14:15
  • \$\begingroup\$ I have updated the graphic for the data load (silly of me). The answer has been updated to reflect the fact that the original author used hard coded constants. \$\endgroup\$ – Peter Smith Sep 4 at 14:29
  • \$\begingroup\$ I understand you emphasizing on the significance of hard coded constants but how is it different than that? I mean in the end it's the same thing except for convenience, right? or am I missing something? Also, I would like your feedback on my previous comments on your answer. Thanks! I'm definitely getting somewhere tho just need confirmations. \$\endgroup\$ – BLOODHOUND Sep 4 at 15:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.