[ a n y m a | research – blog ]
news from the lab…
Very nice sensor: MLX90316 Rotary Position Sensor
Categories: Sensors

Today we’ve played around with a new sensor. The Melexis MLX90316 can detect the angular position of a magnet. From it’s datasheet:

In combination with the appropriate signal processing, the magnetic flux density of a small magnet (diametral magnetization) rotating above the IC can be measured in a non-contacting way (Figure 3). The angular information is computed from both vectorial components of the flux density (i.e. BX and BY). MLX90316 produces an output signal proportional to the decoded angle. The output is selectable between Analog, PWM and Serial Protocol.

We’ve ordered the SPI version from distrelec and after having some first troubles to talk to it, I’m really impressed.

Noise free 360° rotational data with 14 bit precision!!

Really cool, this will help a lot to improve reliability of my 3D Joystick, for example….

Caveats

The  MLX90316 uses only one line for MOSI/MISO, and in the datasheet the tell us to do something like this:

When connecting to the gnusb, at first I thought “we’ll only need to listen to the sensor, so I just don’t connect MOSI and forget about the FET and shit…” but this doesn’t work at all, as the sensor wants to hear “0xAA 0xFF” before revealing us its valuable data…

I didn’t have a FET around and replaced it with a simple transistor. I also used the ATMEGA16’s internal pullup instead of R2, and after some fiddling around with byte order and stuff, I was able to get quite nice data, with quite regularly some 0xFFFFs thrown in. But we can safely assume that 0xFFFF is not any useful data, as bit 1 should always be 0, so I just reject these transmissions for the moment. One could do more serious error checking by comparing with the inverted bytes that come afterwards:

A data frame consists of 10 bytes:

• 2 start bytes (AAh followed by FFh)
• 2 data bytes (DATA16 – most significant byte first)
• 2 inverted data bytes (/DATA16 – most significant byte first)
• 4 all-Hi bytes

Here’s some code snippets for reading the MLX90316 with the gnusb:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// // ==============================================================================
// Snippets for MLX90316
// ==============================================================================
 
 
#include <util/delay.h>
 
// ==============================================================================
// Globals
// ------------------------------------------------------------------------------
 
u16             angle;
u08             rx_idx;
u08             rx_buffer[10];
 
// ==============================================================================
// Talk to MLX90316
// ------------------------------------------------------------------------------
u08 spi_transmit_byte(u08 byte) {
    SPDR = byte;
    while (!(SPSR & (1<<SPIF))) {}
    return SPDR;
}
 
 
void checkSPI(void) {
 
    if (rx_idx == 0) {
        PORTB &= ~(1 << 4);     // select angle sensor
        _delay_us(6);
        rx_buffer[rx_idx] = spi_transmit_byte(0xAA);
 
        rx_idx++;
    } else {
        if (rx_idx < 8) {
            rx_buffer[rx_idx] = spi_transmit_byte(0xFF);
            rx_idx++;       
        } else {
            PORTB |= (1 << 4);      // deselect angle sensor
            _delay_ms(1);
            rx_idx = 0;
 
            if (rx_buffer[3] & 1) {     // LSB == 0 means error from MLX90316
                u16 temp;
                temp = (rx_buffer[2] << 8) + rx_buffer[3];
 
                if (temp < 0xffff) {    // angle cannot be 0xffff
                    angle = temp >> 2;  // bits 0..1 of data doesn't mean anything
                }
            }
        }
    }
}
 
 
 
// ==============================================================================
// - main
// ------------------------------------------------------------------------------
int main(void)
{
    // ------------------------- Initialize Hardware
 
    //PORTB: Serial Communication
 
    DDRB = ~(1 << 6);       // 1011 1111 - All outputs except MISO 
    SPCR = (1<<SPE) | (1<<MSTR) | (1<<SPR1)|(0<<SPR0) | (0<<CPOL) | (1<<CPHA);      //  enable SPI in Master Mode, clk = fcpu/16 
    PORTB = (1 << 4);       // deselect angle sensor
    PORTB |= (1 << 6);
 
    // ------------------------- Main Loop
    while(1) {
        checkSPI();
    }
    return 0;
}

5 Comments to “Very nice sensor: MLX90316 Rotary Position Sensor”

  1. Adam Meyer says:

    Can you post a schematic of your setup? I can’t seem to get the sensor to respond, and I assume it is because of my MOSI setup

  2. ZRimas says:

    Did you tried to program sensor’s EEPROM (zero point, angle and so on…)? Melexis gives no information about it, they just offer an adapter for around 1600EUR what is definitely too high… :(

  3. Michael says:

    No I haven’t tried that. But as I usually read out the sensor with an avr microcontroller, it’s easy to do this kind of stuff on the raw data in the firmware of the controller. Might sacrifice some of the precison but that has never been of concern until now…

  4. ZRimas says:

    Ok, clear. The problem is that I can’t use mc to analyze the raw data – I’m limited to have as less as possible elements on the board, so I have to program zero point, angles and s.o. and only after – to use sensor for analog output with preprogrammed settings.

  5. Verstraten says:

    You get sometimes 0xFFFF–> problem with test 0 connected to GND from MCU.

    Don’t connect the test0 and test 1 to GND.
    Leave them not connected-> no more faulty data.
    Had the same problem. Also using the internal pull up resistor ( no fet or extern resistor)

Leave a Reply