I got a problem I need help with.
I’m trying to configure the I2C on my freescale FRDM-KL25Z protoboard to run the HMC5883L magnetometer. My problem is that when I try to read the six access registers on the HMC5883L, all I get is 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF. What am I doing wrong?
Here is an image from my scope of the communication:
https://fbcdn-sphotos-c-a.akamaihd.net/ … fb2d37e841
I first write a 0x3C (write address of HMC5883L), then a 0x03 for the address of the first data register. I do a repeat start, then write a 0x3D (read address of HMC5883L), I then do a dummy read of the first register than six more reads of a data register. I use a while loop terminated by the IICIF flag to wait for transfers to complete.
The last byte transfer is cut off in the photo. The last three bytes are a 0x3C, 0x02, 0x01 to initiate a new single-measurement (this works).
All this takes place within the MagTask() function which reoccurs every 40ms. No interrupts or RTOS are used at this point.
My relevant code is below.
----- I2C.c -----
#include "includes.h"
// Hardware Defines
#define ENABLE_ACK() (I2C0_C1 &= ~(I2C_C1_TXAK_MASK))
#define DISABLE_ACK() (I2C0_C1 |= I2C_C1_TXAK_MASK)
#define REPEATED_START() (I2C0_C1 |= I2C_C1_RSTA_MASK)
#define ENTER_MASTER() (I2C0_C1 |= (I2C_C1_MST_MASK))
#define ENTER_SLAVE() (I2C0_C1 &= ~(I2C_C1_MST_MASK))
#define ENTER_RX_MODE() (I2C0_C1 &= ~(I2C_C1_TX_MASK))
#define ENTER_TX_MODE() (I2C0_C1 |= (I2C_C1_TX_MASK))
#define FLAG_REG() (I2C0_S)
#define WRITE_BYTE(x) (I2C0_D = x)
#define READ_BYTE() (I2C0_D)
// Prototypes
void I2C0Init(void);
INT32U I2C0Read(void);
void I2C0Write(INT32U Data);
void I2C0Start(void);
void I2C0RepeatedStart(void);
void I2C0Stop(void);
void I2C0RXMode(void);
void I2C0TXMode(void);
void I2C0DisAck(void);
void I2C0EnAck(void);
void I2C0Wait(void);
void I2C0Init(void)
{
PORTB_PCR0 = PORT_PCR_MUX(2);
PORTB_PCR1 = PORT_PCR_MUX(2);
I2C0_F = 0x50;
I2C0_C1 |= I2C_C1_IICEN_MASK;
}
void I2C0Pause(void)
{
INT32U n;
for(n=1;n<50;n++)
{
asm("nop");
}
}
INT32U I2C0Read(void)
{
return READ_BYTE();
}
void I2C0Write(INT32U Data)
{
WRITE_BYTE(Data); // Send the device address
I2C0Wait();
}
void I2C0Start(void)
{
ENTER_MASTER();
}
void I2C0RepeatedStart(void)
{
REPEATED_START();
}
void I2C0Stop(void)
{
ENTER_SLAVE();
}
void I2C0RXMode(void)
{
ENTER_RX_MODE();
}
void I2C0TXMode(void)
{
ENTER_TX_MODE();
}
void I2C0DisAck(void)
{
DISABLE_ACK();
}
void I2C0EnAck(void)
{
ENABLE_ACK();
}
void I2C0Wait(void)
{
// INT32U i;
// for(i=0; i<500; i++){};
while((FLAG_REG() & I2C_S_IICIF_MASK) == 0){} // Wait for flag to set
FLAG_REG() |= I2C_S_IICIF_MASK; // Clear flag
}
----- Mag.c -----
#include "includes.h"
// Prototypes
void MagInit(void);
void MagDelay2p2Us(void);
INT32U MagAxisX(void);
INT32U MagAxisY(void);
INT32U MagAxisZ(void);
void MagWrite(INT32U address, INT32U data);
void MagReadData(void);
void MagTask(void);
// Hardware Defines
#define CONFIG_REG_A 0x00
#define CONFIG_REG_B 0x01
#define MODE_REG 0x02
#define X_REG_MSB 0x03
#define X_REG_LSB 0x04
#define Z_REG_MSB 0x05
#define Z_REG_LSB 0x06
#define Y_REG_MSB 0x07
#define Y_REG_LSB 0x08
// Private Variables
volatile INT32U xAxis;
volatile INT32U yAxis;
volatile INT32U zAxis;
void MagInit(void)
{
xAxis = 0;
yAxis = 0;
zAxis = 0;
MagWrite(CONFIG_REG_A, 0x70);
MagWrite(CONFIG_REG_B, 0xA0);
}
void MagDelay2p2Us(void)
{
INT32U i;
for(i=0; i<100; i++){}
}
INT32U getAxisX(void)
{
return xAxis;
}
INT32U getAxisY(void)
{
return yAxis;
}
INT32U getAxisZ(void)
{
return zAxis;
}
void MagWrite(INT32U address, INT32U data)
{
I2C0Start();
I2C0TXMode();
I2C0Write(0x3C);
I2C0Write(address);
I2C0Write(data);
I2C0RXMode();
I2C0Stop();
MagDelay2p2Us();
}
void MagReadData(void)
{
I2C0Start();
I2C0TXMode();
I2C0EnAck();
I2C0Write(0x3C);
I2C0Write(X_REG_MSB);
I2C0RepeatedStart();
I2C0Write(0x3D);
// I2C0Write(0x06);
// I2C0DisAck();
I2C0RXMode();
xAxis = (I2C0Read() & 0xFF); // Dummy Read
I2C0Wait();
xAxis = ((I2C0Read() & 0xFF) << 0x08);
I2C0Wait();
xAxis |= (I2C0Read() & 0xFF);
I2C0Wait();
zAxis = ((I2C0Read() & 0xFF) << 0x08);
I2C0Wait();
zAxis |= (I2C0Read() & 0xFF);
I2C0Wait();
yAxis = ((I2C0Read() & 0xFF) << 0x08);
I2C0Wait();
I2C0DisAck();
I2C0Stop();
yAxis |= (I2C0Read() & 0xFF);
MagDelay2p2Us();
}
void MagTask(void)
{
MagReadData();
MagWrite(MODE_REG, 0x01);
}
----- main.c -----
#include "includes.h" // include peripheral declarations
// Task Prototypes
void WaitForSlice(void);
void TempTask(void);
int main(void)
{
//-------------------------------------------------------------------------
// Initializations
SysTickInit();
I2C0Init();
MagInit();
while(TRUE)
{
WaitForSlice(); // This function assures the main while loop is run every 40ms
// This function works fine
MagTask();
}
}
Thank you for your help, ask me any questions. This is my first time using I2C.
Andrew