PSoC 5LP + Adafruit LSM303 magnetometer (compass) module + Frozen data

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
keko_4647076
Level 1
Level 1
5 sign-ins First reply posted First question asked

Hi everyone,

I tried replicating "https://jimmyutterstrom.com/blog/2015/07/12/psoc-tutorial-adafruit-lsm303-magnetometer-compass-modul... onto PSoC5LP.

I got readings from the compass module, but it is always the same value and does not change while the PSoC plugged in.

When i remove and plug in the PSoC again, the heading value changes to what is expected but it does not update when i move the compass along. I feel like there's something wrong with the I2C communication, that the value is not being updated. Any help / guidance on how to solve this issue is greatly appreciated.

 

#include <project.h>
#include <math.h>
#include <stdio.h>

#define LSM303_ADDRESS_ACCEL          (0x32 >> 1)
#define LSM303_ADDRESS_MAG            (0x3C >> 1)

#define LSM303_REGISTER_ACCEL_CTRL_REG1_A   0x20
#define LSM303_REGISTER_MAG_MR_REG_M        0x02
#define LSM303_REGISTER_MAG_OUT_X_H_M       0x03
#define LSM303_REGISTER_ACCEL_OUT_X_L_A     0x28

typedef struct Vector3{
    int x;
    int y;
    int z;
} Vector3;

void LSM303_Init() {
    
    //Start the I2C component.
    LSM303_I2C_Start();
    
    /*------------ Accelerometer ------------*/
    
    //Send start command for write mode.
    LSM303_I2C_MasterSendStart(LSM303_ADDRESS_ACCEL, LSM303_I2C_WRITE_XFER_MODE);

    //Specify which register we want to write to.
    //This register is written to for enabling x, y and z
    //output as well as setting datarate and powermode.
    LSM303_I2C_MasterWriteByte(LSM303_REGISTER_ACCEL_CTRL_REG1_A);
    
    //Set the required bits in the register.
    LSM303_I2C_MasterWriteByte(0x27u);
    
    /*------------ Magnetometer ------------*/
   
    //This register is written to for setting data output rates
    //and controlling measurement flow.
    LSM303_I2C_MasterWriteByte(LSM303_REGISTER_MAG_MR_REG_M);
    LSM303_I2C_MasterWriteByte(0x00u);
        
    LSM303_I2C_MasterSendStop();

}

void LSM303_ReadMag(Vector3 *magData) {
    uint8 data[6];
    

    //Prepare the module for magnetometer output.
    LSM303_I2C_MasterSendStart(LSM303_ADDRESS_MAG, LSM303_I2C_WRITE_XFER_MODE);

    LSM303_I2C_MasterWriteByte(LSM303_REGISTER_MAG_OUT_X_H_M);    
        
    LSM303_I2C_MasterSendStop();
    //--
    
    //Start the communication in read mode.
    LSM303_I2C_MasterSendStart(LSM303_ADDRESS_MAG, LSM303_I2C_READ_XFER_MODE);   
    
    //Read databytes.
    data[0] = LSM303_I2C_MasterReadByte(LSM303_I2C_ACK_DATA);
    data[1] = LSM303_I2C_MasterReadByte(LSM303_I2C_ACK_DATA);
    data[2] = LSM303_I2C_MasterReadByte(LSM303_I2C_ACK_DATA);
    data[3] = LSM303_I2C_MasterReadByte(LSM303_I2C_ACK_DATA);
    data[4] = LSM303_I2C_MasterReadByte(LSM303_I2C_ACK_DATA);
    
    //Notice that we are here using "NAK_DATA". It's to tell the 
    //LSM303 that we're done and don't want to read anymore data.
    data[5] = LSM303_I2C_MasterReadByte(LSM303_I2C_NAK_DATA);
    
    //Put together the different data bytes to form complete
    //integers for storing the output values.
    magData->x = (int16_t)(data[1] | (data[0] << 8));
    magData->y = (int16_t)(data[5] | (data[4] << 8));   
    magData->z = (int16_t)(data[3] | (data[2] << 8));
 
    LSM303_I2C_MasterSendStop();

}

int main()
{  
    Vector3 magData;
    char output[4]; //String for storing uart output.
    
    PC_UART_Start();      
    LSM303_Init();   

    for(;;)
    {
        LSM303_ReadMag(&magData);
        
        //Calculate heading using arctan on the Y and X vectors.
        //And convert from radians to degrees.
        float h = (atan2(magData.y, magData.x) * 180.0) / 3.14159265359;
        
        //Map the value to comply with the standard system where the heading
        //is specified as an angle between 0 - 360 degrees.
        if(h < 0) {
            h = 360 + h;   
        }  
        
        //Output the heading through our UART component.
        sprintf(output, "%i\r\n", (int)(h+0.5));
        PC_UART_PutString(output);
        
        //Update heading at 1 Hz
        CyDelay(1000);

    }    
}

/* [] END OF FILE */
0 Likes
1 Reply
VenkataD_41
Moderator
Moderator
Moderator
750 replies posted 500 replies posted 250 solutions authored

Hi,

1. Please probe the I2C lines and see if the magnetometer is sending the data properly on every Read()

2. Please use high level APIs for Writing and Reading through the Master using I2CMasterReadBuf() and I2CMasterWriteBuf() instead of using low level APIs.

3. You can use Cypress'(now Infineon's) Bridge control Panel tool and an USB-I2C bridge to configure the magnetometer and to read the I2C data instead of using PSOC 5LP device. This test will confirm whether the issue lies in magnetometer side or psoc side.

Thanks and regards

Ganesh

 

0 Likes