cancel
Showing results for 
Search instead for 
Did you mean: 

Unable to properly initialize lis3mdl via spi and via i2c

mahlet
Associate
Posted on May 13, 2015 at 11:48

I am using the lis3mdl sensor with msp430 microcontroller sensor, the initial plan was to use SPI interface but it turns out the SDI pin was acting like an output pin instead of receiving data from the micro-controller. Then I switched to i2c but  the sensor when connecting  the vdd io and vdd to the vcc of the micro controller the program was unable to debug and gives power supply error. I believe it is hardware error. Does any one has faced similar problems?

Note that all the proper connections were made as shown in the datasheet.

My other question is is there any detailed information on how to initialize the lis3mdl via SPI?  because the data provided on the datasheet and application is not very descriptive.

The last question is when using the I2c mode should I connect the CS pin to ground? what about the int pin should I connect it to GND if I don�t use the pin?

#i2c #lis3mdl #4-wired-spi
3 REPLIES 3
AvaTar
Lead
Posted on May 16, 2015 at 18:05

The last question is when using the I2c mode should I connect the CS pin to ground? what about the int pin should I connect it to GND if I don´t use the pin?

I think not. Section 5, ''Digital Interfaces'', states: ''To select/exploit the I2C interface, the CS line must be tied high (VDD_IO).'' ... but the sensor when connecting the vdd io and vdd to the vcc of the micro controller the program was unable to debug and gives power supply error. I believe it is hardware error. Does any one has faced similar problems? I worked with the MKI137 evaluation board, and did not experience such problems. The schematics of this board might help as guideline for the required hardware. For my ''hobbyist'' projects, I use to avoid handling/soldering such tiny ICs like the LIS3MDL, and rather pay some bucks more ... My other question is is there any detailed information on how to initialize the lis3mdl via SPI? because the data provided on the datasheet and application is not very descriptive. That's true, I struggled several days (... about only 2 hours per day, though) to get it working, mostly by a trial-and-error method. My code is for the STM32F051, a Cortex M0 core, so not usable for you directly. But perhaps it is helpful. SPI Initialisation:

SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStruct.SPI_CRCPolynomial = 0;
SPI_Init (SPI2, &SPI_InitStruct);

Sensor initialisation:

uint32_t initSensor (void)
{
uint16_t wvalue;
uint8_t whoami;
SPI2->CR1 &= SPI_CR1_N_SPE;
SPI_DataSizeConfig (SPI2, SPI_DataSize_16b);
SPI2->CR1 |= SPI_CR1_SPE;
LIS3_SS_Down();
wvalue = (LIS3MDL_WHO_AM_I | SPI_READ | SPI_SINGLE) << 
8
;
wvalue &= 0xFF00;
SPI2->DR = wvalue;
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) != RESET);
wvalue = SPI2->DR;
LIS3_SS_Up ();
whoami = (uint8_t) (wvalue & 0x0FF);
DBG_PRINTF (''WHO_AM_I (16Bit) = %h
X'', whoami);
if (whoami != CFG_REG_WHO_AM_I)
return (1);
/* CTRL_REG1 (Offset 0x20) = 0x7E
* Temp.Sens disable, XY-axis in ultra-hi perf. mode, output rate = 80Hz, FAST_ODR enable, selftest off */
LIS3_SetReg (LIS3MDL_CTRL_REG1, CFG_REG1_VALUE);
/* CTRL_REG2 (Offset 0x21) = 0x04
* Fullscale=4gauss, No-Reboot, SOFT_RST=1 (execute soft-reset) */
LIS3_SetReg (LIS3MDL_CTRL_REG2, CFG_REG2_VALUE);
/* CTRL_REG3 (Offset 0x22) = 0x00
* no LP-mode, 4-wire SPI, MD1,MD0 = Bit1:Bit0 -> continuous conversion
* MD1:MD0 = 0:0 -> continuous conversion mode;
* MD1:MD0 = 0:1 -> single conv. mode, ''has to be used with sampling freq. from 0.625 to 80 Hz'' */
LIS3_SetReg (LIS3MDL_CTRL_REG3, CFG_REG3_VALUE);
/* CTRL_REG4 (Offset 0x23) = 0x0C
* Z axis in ultra-hi perf. mode, Endianess -> data LSB at lower address (xE = data MSB at lower address) */
LIS3_SetReg (LIS3MDL_CTRL_REG4, CFG_REG4_VALUE);
/* CTRL_REG5 (Offset 0x24) = 0x40
* FAST_READ on, BDU = 1 (no update until MSB and LSB are read) */
LIS3_SetReg (LIS3MDL_CTRL_REG5, CFG_REG5_VALUE);
return 0;
}

With the following defines:

#define SPI_READ 0x80
#define SPI_WRITE 0x00
#define SPI_AUTOINC 0x40
#define SPI_SINGLE 0x00
#define LIS3MDL_WHO_AM_I 0x0F
#define LIS3MDL_CTRL_REG1 0x20
#define LIS3MDL_CTRL_REG2 0x21
#define LIS3MDL_CTRL_REG3 0x22
#define LIS3MDL_CTRL_REG4 0x23
#define LIS3MDL_CTRL_REG5 0x24

The actual values you need may vary. The write function is as follows:

static void LIS3_SetReg (uint8_t regaddr, uint8_t value)
{
uint16_t wValue;
/* set ''Write'' and ''No-Increment'' bits */
regaddr |= (SPI_WRITE | SPI_SINGLE);
wValue = (regaddr << 
8
) + value;
LIS3_SS_Down ();
SPI2->DR = wValue;
/* wait until write is finished */
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) != RESET);
LIS3_SS_Up ();
}

SS_Down() and SS_Up() are inline functions to assert/deassert the SlaveSelect line (connected to CS of the magnetometer). I'm using a software-controlled SS mode, hardware mode did not work for me. The SPI transaction happens as soon as I write to SPI1->DR, which is the input/output register in the SPI peripheral. My read function for a 8-bit register (of the LIS3MDL) is as follows:

static uint8_t readBReg (int8_t regAddr)
{
int16_t readVal, writeVal;
uint8_t result;
SPI2->CR1 &= SPI_CR1_N_SPE;
SPI_DataSizeConfig (SPI2, SPI_DataSize_16b);
SPI2->CR1 |= SPI_CR1_SPE;
LIS3_SS_Down ();
/* register address */
writeVal = (((regAddr | SPI_READ | SPI_SINGLE) << 
8
) & 0xFF00);
SPI2->DR = writeVal;
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) != RESET);
readVal = SPI2->DR;
LIS3_SS_Up ();
result = (uint8_t) (readVal & 0x00FF);
return (result);
}

Note that this is a 16-bit SPI transaction. First, the register address (including mode bits) are written, then (with the second, ''dummy'' byte in the write register), the requested value is read back. That is described in the datasheet, albeit in a quite opaque language. Note that you need to wait for the transfer to finish before reading the received value from the SPI input register. With some effort, that should be portable to your MSP4
mahlet
Associate
Posted on May 17, 2015 at 20:36

Hi, Thank you for the reply, I have been working on this for a while and I changed sensors a couple of times but the SPI problem is still present. I still have a couple of questions how did you set the clock inactive state? did you use any delays after resetting the Lis3mdl and power up? 

was the who am I register value correct?

Thanks for the help. Cheers 🙂

AvaTar
Lead
Posted on May 18, 2015 at 12:59

did you use any delays after resetting the Lis3mdl and power up?

Yes, because I had startup issues with other sensors. One of the 'M' in MEMS means 'mechanical', and mechanical system might need some longer initialisation times. I use 50ms, which worked for me, and I did not experiment with this time yet. was the who am I register value correct? Yes (but not from the beginning ...). If reading this register returns the correct value, you know your SPI routines are correct. As mentioned, this took me some days. how did you set the clock inactive state? You probably mean this settings:

SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;

This means: SCLK idle state is LOW, capture on falling edge of SCLK. I have been working on this for a while and I changed sensors a couple of times but the SPI problem is still present. If you did not experiment with the wiring (supply voltage/polarity) changes are great your sensors are alive. As said, it took me some time to get it working, and until then, I received no valid response from the sensor (WHO_AM_I was not 0x3D). The SPI settings (polarity, edge, slave_select) must be correct for the sensor to answer. Make sure your wiring is not too long, or reduce clock frequency at the beginning. And, as always with serial busses, a scope is very helpful (I had used one).