SparkFun Forums 

Where electronics enthusiasts find answers.

Everything ARM and LPC
By baldforehead
#163385
Hey guys,

So I'm working on a compass sensor HMC6352 and lpc1769 with I2C protocol. The compass sensor suppose to give new heading every time I move its position, but I only get '0' as the printf reading.

I'm totally new to I2c, so your guidance is really appreciated. I also have done my homework on this, here's some extra detail if you decided to help me:
• As given in data sheet (pg.3) The compass sensor address (slave address) is 0x42 (read) / 0x43 (write). So, the 7bit address (before shifting and OR-ing) that i sent is 0x21 to either I2C_READ or I2C_WRITE
• The slave register address is 0x41 (data sheet pg. 5, table 1 – command ‘A’)
• I’m using SDA2 (P0.10) and SCL2 (p0.11) - I'm using lpc1769
• The code use 6000u sec delay as suggested (data sheet pg.8 table 3)
• Clock is 100kHz
• I connect 15kohm resistor between SCAL and SDA line to 5v. (10k is recommended for 3.3v. However 5v is still within the acceptable range. I've tried 2k, 10k, and 15k, but all give the same result)

So here's the datasheet for reference https://www.sparkfun.com/datasheets/Com ... MC6352.pdf.
And here's the code
Code: Select all
#include "lpc17xx_pinsel.h"
#include "lpc17xx_i2c.h"
#include "lpc17xx_timer.h"
#include "stdio.h"


#define I2CDEV LPC_I2C2
static const int READ_WRITE_OPERATION = 0x21;
static const int COMMAND_GET_DATA = 0x41;

void readFromCompassHMC6352(void);
static int I2CRead(uint8_t addr, uint8_t* buf, uint32_t len);
static int I2CWrite(uint8_t addr, uint8_t* buf, uint32_t len);

static int I2CRead(uint8_t addr, uint8_t* buf, uint32_t len)
{
	I2C_M_SETUP_Type rxsetup;
	rxsetup.sl_addr7bit = addr;
	rxsetup.tx_data = NULL; // Get address to read at writing address
	rxsetup.tx_length = 0;
	rxsetup.rx_data = buf;
	rxsetup.rx_length = len;
	rxsetup.retransmissions_max = 3;
	if (I2C_MasterTransferData(I2CDEV, &rxsetup, I2C_TRANSFER_POLLING) == SUCCESS){
		return (0);
	} else {
		return (-1);
	}
}

static int I2CWrite(uint8_t addr, uint8_t* buf, uint32_t len)
{
	I2C_M_SETUP_Type txsetup;
	txsetup.sl_addr7bit = addr;
	txsetup.tx_data = buf;
	txsetup.tx_length = len;
	txsetup.rx_data = NULL;
	txsetup.rx_length = 0;
	txsetup.retransmissions_max = 3;
	if (I2C_MasterTransferData(I2CDEV, &txsetup, I2C_TRANSFER_POLLING) == SUCCESS){
		return (0);
	} else {
		return (-1);
	}
}

void readFromCompassHMC6352(void)
{
	int value = -1;
	uint8_t data[2]={0,0};
	while(1) {

		// Send a "Get Data" command to the compass
		data[0]= COMMAND_GET_DATA;
		I2CWrite(READ_WRITE_OPERATION, data, 2);

		// datasheet suggests to wait at least 6000 microseconds
		Timer0_Wait(6);

		// Read two bytes from the compass (compass heading)
		data[0] = 1;
		I2CRead(READ_WRITE_OPERATION, data, 2);
		value = ((data[0] << 8 )+data[1]) / 10;

		// read compass twice to clear last reading
		Timer0_Wait(6);
		data[0] = 0;
		I2CRead(READ_WRITE_OPERATION,data, 2);

		//Display the value on the display
		if(value >= 0 && value <= 359) {
			//Display degree value
			printf("The angle is %d\n",value);
		}
		Timer0_Wait(60);
	}
}

static void init_i2c(void)
{
	PINSEL_CFG_Type PinCfg;
	/* Initialize I2C2 pin connect
	 * P0.10 - I2C_SDA(Serial Data)
	 * P0.11 - I2C_SCL(Serial Clock line)
	 * */
	PinCfg.Funcnum = 2;
	PinCfg.Pinnum = 10;
	PinCfg.Portnum = 0;
	PINSEL_ConfigPin(&PinCfg);
	PinCfg.Pinnum = 11;
	PINSEL_ConfigPin(&PinCfg);
	// Initialize I2C peripheral
	I2C_Init(LPC_I2C2, 100000);
	/* Enable I2C2 operation */
	I2C_Cmd(LPC_I2C2, ENABLE);
}

int main(void)
{

	init_i2c();
	Timer0_Wait(1);
	readFromCompassHMC6352();

	return 1;
}
I'm pretty sure that there is a small mistake that I don't notice somewhere in the code. Pleeeaseeeeeeee help... Thanks in advanced people!!! :D

*edit* - I have checked it with oscilloscope. All the address are sent correctly, however no data is received. Start, Stop, ACK bit are all present.
This is the order of the data that I see btw,
1) 0x42 -I2CWRITE
2) 0X41 - slave register address
3) 0x43- I2CREAD
4) nothing - supposed to be the data from the sensor to LPC board.

Regards,
Francis
Last edited by baldforehead on Fri Sep 13, 2013 11:53 pm, edited 1 time in total.
By jremington
#163510
At this point, you don't know whether the I2C routines or the compass is not working (or both). I would try to isolate the problem by using some other I2C device, like an EEPROM, with the LPC, and the compass with some other micro using known good code. There are several examples available of code for AVR processors that works perfectly with the HMC6352, and I've had no trouble talking to one.

Note: please use the code tags. It makes your code easier to read and take up less space.
By baldforehead
#163513
jremington wrote:At this point, you don't know whether the I2C routines or the compass is not working (or both). I would try to isolate the problem by using some other I2C device, like an EEPROM, with the LPC, and the compass with some other micro using known good code. There are several examples available of code for AVR processors that works perfectly with the HMC6352, and I've had no trouble talking to one.

Note: please use the code tags. It makes your code easier to read and take up less space.
Hi jremington,

Thanks for your reply. Unfortunately I only have LPC micro at the moment. But yea, I'd give it a try with EEPROM. I put it in code tags ald... :D

Thanks again,
Francis
By baldforehead
#163907
I solved it!! This line (I2C_Init(LPC_I2C2, 100000) gives clock over 100Khz. So what I did is i deleted 1 '0' and it works. However the clock is 20Khz, so I'm not sure if this will affect the sensor performance as the data sheet recommend 100Khz.

Anyway, for future use, everything is the same except 'I2C_Init(LPC_I2C2, 100000'. Change that to I2C_Init(LPC_I2C2, 10000). I use 3.3v & 1.7kohm for scl and sda. It should work with 5v too.

Thanks all
By jremington
#163934
Great that you found a solution to the problem! However, if the purpose of the second parameter in the I2C_Init routine is to set the I2C clock frequency, then either there is a serious bug in these routines or something else is wrong, like a timing constant. Perhaps the compiler is making an incorrect assumption about the main crystal clock frequency.