This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C1294NCPDT: TivaWare Sensor Library LSM303DLHC Magnetometer issue

Part Number: TM4C1294NCPDT

Howdy,

I have a custom board that is supposed to talk to the LSM303DLHC over I2C with the TM4C1294NCPDT micro controller. I have previously used the peripheral driver to succesfully use UART as well as GPIO functionalities. I have been reading through the I2C peripheral library, the I2C master driver in the sensor library and the LSM303DLHC driver in the sensor library and I did my best to set it up to just read in a loop but I am not getting anything on the SCL or SDA lines (looking with logic analyzer, both are being held high)). I copied my code below and commented on the important things. I have some functions from other parts of my projects in there but they are not being used at all. Any help is appreciated!!

#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "inc/hw_gpio.h"
#include "piconfig.h" //setting up pins
#include "inc/hw_i2c.h" //used in i2c
#include "inc/hw_timer.h"
#include "driverlib/sysctl.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom_map.h"
#include "driverlib/gpio.h"
#include "driverlib/timer.h"
#include "driverlib/fpu.h"
#include "driverlib/uart.h"
#include "driverlib/i2c.h" //used in i2c
#include "sensorlib/i2cm_drv.c" //used in i2c
#include "sensorlib/i2cm_drv.h" //used in i2c
#include "sensorlib/lsm303dlhc_mag.c"//used in i2c
#include "sensorlib/lsm303dlhc_mag.h"//used in i2c
#include "sensorlib/hw_lsm303dlhc.h"//used in i2c

//typedef struct
//{
// float latitude; //ignore this
// float longitude;
//} position;
//prototype functions
void pinconfig (void); //calls function that configures pins
//void UartInit (void);
//void GpsConfigTX (void);
//position GpsRXData (void);
//float convert_decimal_degrees(float num);
//double azi (float lat1, float lon1, float lat2, float lon2); //ignore these
//void TimerSetup (void);
//void delay(uint32_t);
//void speedprofile(float,float,float, double);

tI2CMInstance sI2CInst;
volatile bool g_bLSM303DLHCMagDone;

void inthandler (void); //created this function to be called by the interrupt handler

void LSM303DLHCMagCallback(void *pvCallbackData, uint_fast8_t ui8Status)
{
// See if an error occurred.
if(ui8Status != I2CM_STATUS_SUCCESS)
{
// An error occurred, so handle it here if required. //this is from sensor library
}
// Indicate that the LSM303DLHCMag transaction has completed.
g_bLSM303DLHCMagDone = true;
}


int main(void)
{
//set clock frequency to 120MHz
uint32_t freq = SysCtlClockFreqSet(SYSCTL_OSC_MAIN|SYSCTL_USE_PLL|SYSCTL_XTAL_25MHZ | SYSCTL_CFG_VCO_480,120000000);
//variables from sensor library
float fMag[3];
tLSM303DLHCMag sLSM303DLHCMag;
//configure pins for SDA+SCL (done with all oter pins in the pinconfig function
pinconfig();
//enable system peripheral and wait until it is ready before moving on
SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C7);
while(!SysCtlPeripheralReady(SYSCTL_PERIPH_I2C7))
{
}
//configure I2C peripheral true for fast data transfers
I2CMasterInitExpClk(I2C7_BASE,120000000,true);
//Clear Master Interrupts
I2CMasterIntClear(I2C7_BASE);
//declare function pointer to the i2c master interrupt handler
void (*Handler)(void);
Handler = inthandler;
//Did not Enable I2C Interrupts

//Register an Interrupt handler for I2C Interrupts that are enabled
I2CIntRegister(I2C7_BASE, (*Handler));
//Initialize Magnetometer (possibility that param #2 is base address of I2C)
int maginit = LSM303DLHCMagInit(&sLSM303DLHCMag, &sI2CInst,0x3D,LSM303DLHCMagCallback,0);
//read continuously
while (1)
{
g_bLSM303DLHCMagDone = false;
LSM303DLHCMagDataRead(&sLSM303DLHCMag, LSM303DLHCMagCallback, 0);
while(!g_bLSM303DLHCMagDone) //gets stuck here
{
}
//
// Get the new magnetometer readings.
//
LSM303DLHCMagDataMagnetoGetFloat(&sLSM303DLHCMag, &fMag[0], &fMag[1], &fMag[2]);
}

}
void inthandler (void)
{
I2CMIntHandler(&sI2CInst);
}

////-----------------------------------------------------------------------------------------------
void pinconfig(void)
{
// Enable Peripheral Clocks
MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_EPHY0);
MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C7);
MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART4);
MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOK);

//
MAP_GPIOPinTypeGPIOOutput(GPIO_PORTK_BASE, GPIO_PIN_4);
//
MAP_GPIOPinTypeGPIOOutput(GPIO_PORTK_BASE, GPIO_PIN_6);
// Enable pin PA4 for GPIOOutput
MAP_GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_4);
// Enable pin PA5 for GPIOOutput
MAP_GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_5);
// Enable pin PA0 for GPIOOutput
MAP_GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_0);
// Enable pin PA1 for GPIOOutput
MAP_GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_1);
// Enable pin PA2 for GPIOOutput
MAP_GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_2);
// Enable pin PA3 for GPIOOutput
MAP_GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_3);
// Enable pin PF0 for GPIOOutput
MAP_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_0);
// Enable pin PD0 for I2C7 I2C7SCL
MAP_GPIOPinConfigure(GPIO_PD0_I2C7SCL);
MAP_GPIOPinTypeI2CSCL(GPIO_PORTD_BASE, GPIO_PIN_0);
// Enable pin PD1 for I2C7 I2C7SDA
MAP_GPIOPinConfigure(GPIO_PD1_I2C7SDA);
MAP_GPIOPinTypeI2C(GPIO_PORTD_BASE, GPIO_PIN_1);
// Enable pin PK0 for UART4 U4RX
MAP_GPIOPinConfigure(GPIO_PK0_U4RX);
MAP_GPIOPinTypeUART(GPIO_PORTK_BASE, GPIO_PIN_0);
// Enable pin PK1 for UART4 U4TX
MAP_GPIOPinConfigure(GPIO_PK1_U4TX);
MAP_GPIOPinTypeUART(GPIO_PORTK_BASE, GPIO_PIN_1);
}

  • Hi,
    I don't see that you call I2CMInit() first to prepare the I2C master and driver for operation before you call LSM303DLHCMagInit(). When you call I2CMInit() it prepares the state structure which will later be referenced by the LSM303DLHCMagInit().
  • Thanks!
    I added that line and I am still not getting anything on the SDa or SCL lines. Here is the updated code.


    tI2CMInstance sI2CInst;
    volatile bool g_bLSM303DLHCMagDone;

    void inthandler (void); //created this function to be called by the interrupt handler

    void LSM303DLHCMagCallback(void *pvCallbackData, uint_fast8_t ui8Status)
    {
    // See if an error occurred.
    if(ui8Status != I2CM_STATUS_SUCCESS)
    {
    // An error occurred, so handle it here if required. //this is from sensor library
    }
    // Indicate that the LSM303DLHCMag transaction has completed.
    g_bLSM303DLHCMagDone = true;
    }


    int main(void)
    {
    //set clock frequency to 120MHz
    uint32_t freq = SysCtlClockFreqSet(SYSCTL_OSC_MAIN|SYSCTL_USE_PLL|SYSCTL_XTAL_25MHZ | SYSCTL_CFG_VCO_480,120000000);
    //variables from sensor library
    float fMag[3];
    tLSM303DLHCMag sLSM303DLHCMag;
    //configure pins for SDA+SCL (done with all other pins in the pinconfig function)
    pinconfig();
    //enable system peripheral and wait until it is ready before moving on
    SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C7);
    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_I2C7))
    {
    }
    //configure I2C peripheral true for fast data transfers
    I2CMasterInitExpClk(I2C7_BASE,120000000,true);
    //Clear Master Interrupts
    I2CMasterIntClear(I2C7_BASE);
    //declare function pointer to the i2c master interrupt handler
    void (*Handler)(void);
    Handler = inthandler;
    //Did not Enable I2C Interrupts

    //Register an Interrupt handler for I2C Interrupts that are enabled
    I2CIntRegister(I2C7_BASE, (*Handler));
    //Initialize I2C Master Driver
    I2CMInit(&sI2CInst,I2C7_BASE,INT_I2C7,0xff,0xff,120000000);
    //Initialize Magnetometer (possibility that param #2 is base address of I2C)
    int maginit = LSM303DLHCMagInit(&sLSM303DLHCMag, &sI2CInst,0x3D,LSM303DLHCMagCallback,0);
    //read continuously
    while (1)
    {
    g_bLSM303DLHCMagDone = false;
    LSM303DLHCMagDataRead(&sLSM303DLHCMag, LSM303DLHCMagCallback, 0);
    while(!g_bLSM303DLHCMagDone) //gets stuck here
    {
    }
    //
    // Get the new magnetometer readings.
    //
    LSM303DLHCMagDataMagnetoGetFloat(&sLSM303DLHCMag, &fMag[0], &fMag[1], &fMag[2]);
    }

    }
    void inthandler (void)
    {
    I2CMIntHandler(&sI2CInst);
    }
  • One thing I notice is that i don't think the I2C slave address is correct. The slave address is 0x1E. You are giving 0x3D which includes the read bit. 

  • I did try it with 0x1E but it did not really make a difference. I am double checking all the hardware now to make sure there isnt anything wrong there. My concern is that the sensor library for this particular part and the I2C master driver are severely under documented. I understand the general idea of what is happening but I cannot seem to connect the dots.

    Do you have any more information on the instance data regarding both the ? I think this is part of the problem.
  • Here is my final functioning code. Turns out that it reports x,z,y instead of x,y,z. Also I don't know where it happened but somewhere along the way the bytes get swapped.


    void Maginthandler (void) //function to be called by the interrupt handler
    {
    I2CMIntHandler(&g_sI2CInst); // this API command is specified to be used in this function
    }

    static void MagCallback(void *pvCallbackData, uint_fast8_t ui8Status)
    {
    // See if an error occurred.
    if(ui8Status != I2CM_STATUS_SUCCESS)
    {
    // An error occurred, so handle it here if required. //this is from sensor library
    }
    // Indicate that the LSM303DLHCMag transaction has completed.
    g_bLSM303DLHCMagDone = true;
    }
    void MagInit (void)
    {
    //I2C SETUP
    //---------------------------------------------------------------------
    //enable system peripheral and wait until it is ready before moving on
    SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C7);
    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_I2C7))
    {
    }
    //configure I2C peripheral, true for fast data transfers (try deleting this)
    I2CMasterInitExpClk(I2C7_BASE,120000000,true);
    //Clear Master Interrupts (try deleting this)
    I2CMasterIntEnable(I2C7_BASE);
    //declare function pointer to the i2c master interrupt handler
    void (*Handler)(void);
    Handler = Maginthandler;
    //Register an Interrupt handler for I2C Interrupts that are enabled
    I2CIntRegister(I2C7_BASE, (*Handler));
    //Initialize I2C Master Driver
    I2CMInit(&g_sI2CInst,I2C7_BASE,INT_I2C7,0xff,0xff,120000000);
    // LSM303DLHC Magnetometer Configuration
    //---------------------------------------------------------------------
    // magnetometer busy
    g_bLSM303DLHCMagDone = false;
    //Initialize Magnetometer
    int maginit = LSM303DLHCMagInit(&g_sLSM303DLHCMag, &g_sI2CInst,0x1E,MagCallback,0);
    //wait until initialization is completed
    while(g_bLSM303DLHCMagDone== false)
    {
    }
    //magnetometer busy
    g_bLSM303DLHCMagDone = false;
    //configure for 75Hz update rate
    LSM303DLHCMagReadModifyWrite(&g_sLSM303DLHCMag,LSM303DLHC_O_MAG_CRA,~LSM303DLHC_MAG_CRA_DO_M,LSM303DLHC_MAG_CRA_DO_75HZ, MagCallback,0);
    //wait until configuration is completed
    while(g_bLSM303DLHCMagDone== false)
    {
    }
    //magnetometer busy
    g_bLSM303DLHCMagDone = false;
    //configure for continuous measurements
    LSM303DLHCMagReadModifyWrite(&g_sLSM303DLHCMag,LSM303DLHC_O_MAG_MR,~LSM303DLHC_MAG_MR_MODE_M,LSM303DLHC_MAG_MR_MODE_CONTINUOUS, MagCallback,0);
    //wait until configuration is completed
    while(g_bLSM303DLHCMagDone== false)
    {
    }
    //magnetometer busy
    g_bLSM303DLHCMagDone = false;
    //configure for +/- 2.5 Gauss input range
    LSM303DLHCMagReadModifyWrite(&g_sLSM303DLHCMag, LSM303DLHC_O_MAG_CRB,~LSM303DLHC_MAG_CRB_GAIN_M,LSM303DLHC_MAG_CRB_GAIN_5_6GAUSS,MagCallback,0);
    //wait until configuration is completed
    while(g_bLSM303DLHCMagDone== false)
    {
    }
    }
    float getHeading(void)
    {
    //magnetometer busy
    g_bLSM303DLHCMagDone = false;
    //read data registers on magnetometer
    LSM303DLHCMagDataRead(&g_sLSM303DLHCMag, MagCallback, 0);
    while(g_bLSM303DLHCMagDone== false)
    {
    }
    // Get the latest raw magnetometer data
    LSM303DLHCMagDataMagnetoGetRaw(&g_sLSM303DLHCMag, &g_fMag[0], &g_fMag[1], &g_fMag[2]);
    //convert to unsigned 16 bit int
    uint16_t x = (g_fMag[0]);
    //swap the bytes
    uint16_t swapped =( x << 8) | (x >> 8);
    //2's complement to signed integer conversion
    int16_t X = swapped;
    //hard iron offset calibration
    X = (X+7808.5);
    //convert to unsigned 16 bit int
    uint16_t z = (g_fMag[1]);
    //swap the bytes
    swapped =( z << 8) | (z >> 8);
    //2's complement to signed integer conversion
    int16_t Z = swapped;
    //convert to 16 bit unsigned int
    uint16_t y = (g_fMag[2]);
    //swap the bytes
    swapped =( y << 8) | (y >> 8);
    //convert twos complement to signed integer
    int16_t Y = swapped;
    //hard iron offset calibration
    Y = (Y+3);
    //compute heading
    float heading =MagnetoHeadingCompute(X,Y,Z,0,0);
    //convert radians to degrees
    heading = (heading*180)/PI;
    return heading;
    }
  • Hi Justin,

     Th registers are arranged in X, Z, Y order in the device? Take a look at the below register address map. Perhaps this is the reason.