Urgent!! LPC1769 compass sensor HMC6352 I2C

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Urgent!! LPC1769 compass sensor HMC6352 I2C

2,088 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by sgtengxiao on Mon Oct 15 02:56:35 MST 2012
This is related to my current project, and the deadline is near. Hope any one can help me find my code error.  I will wait online~  :(:(:(
Below is my code:
#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 = 0x42;
static const int COMMAND_GET_DATA = 0x41;
 
void readFromCompassHMC6352(void);

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
   [COLOR=red]printf("The angle is %d\n",value);
[/COLOR]  }
  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;
}


The result printf "anlge" is always 0. I debugged one by one, and find that in I2CWrite and I2CRead functions, it always returns -1, which means the data transfer fails.

Any one can help me?  pls~~~~~~
0 Kudos
23 Replies

1,960 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by capiman on Fri Sep 27 03:38:06 MST 2013
Hello,
when you delete one '0', so you have 10.000 and measure 20.000, it seems that you have somehow a factor of 2 somewhere in your system, which is not taken into account.
When you use the original 100.000, it seems you are actually using 200.000, which seems to be too much.
For a workaround take 50.000 as value and check if you have then 100.000
For a final bugfix it is needed to find out where this factor of 2 is coming from.
I assume one of the clocks is running faster than your clock calculation takes into account.
Check what I2C_Init is doing as clock calculation and which parameters or register content is used for it.
Best regards,
Martin
0 Kudos

1,960 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by francisxav on Fri Sep 27 00:27:11 MST 2013
Anyway, can anyone 'enlighten' me about this clock issue. How does deleting 1 '0' actually brings down the clock from >100Khz to just 20Khz?

Anyone???

Thanks in advance.
0 Kudos

1,960 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by francisxav on Thu Sep 26 23:56:27 MST 2013
MC, I really thank you for your last comment!!!!!!!!!!!!!

Indeed the clock is over 100khz!!! Out of curiosity, I deleted 1 '0' in the 'I2C_Init(LPC_I2C2, 100000)'. And it RETURN ME VALUES!!!! However, the clock reading in oscilloscope is only 20KHz. I'm still unsure if that will affect the reading of the sensor as the data sheet recommends 100Khz.

Anyway, really thanks!!! For future use, here's the code that I use:

#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){
printf("read success\n\r");
return (0);
} else {
printf("read fail\n\r");
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){
printf("write success\n\r");
return (0);
} else {
printf("write fail\n\r");
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.OpenDrain = 1;
PinCfg.Pinnum = 10;
PinCfg.Portnum = 0;
PINSEL_ConfigPin(&PinCfg);
PinCfg.Pinnum = 11;
PINSEL_ConfigPin(&PinCfg);
// Initialize I2C peripheral
I2C_Init(LPC_I2C2, 10000);
/* Enable I2C2 operation */
I2C_Cmd(LPC_I2C2, ENABLE);
}

int main(void)
{

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

return 1;
}


I use 3.3 v & 1.7K ohm for the scl and sda.

Cheers all!!!
0 Kudos

1,960 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mc on Thu Sep 19 16:11:00 MST 2013
Hi Francis,
You can also confirm it using oscilloscope. Please probe clock line and post your findings.
0 Kudos

1,960 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by francisxav on Fri Sep 13 23:51:24 MST 2013
Hi MC,

Thanks for your reply. Hmmm... Unfortunately I only bought 1 of this. So i can only try it with the current one I have.

SCL clock frequency is 100khz. This part ( I2C_Init(LPC_I2C2, 100000)) sets the SCL clock right???


Thanks in advanced,
Francis



0 Kudos

1,960 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mc on Fri Sep 13 07:22:39 MST 2013
Hi Francis,
I looked read and could see ack from I2c Slave device. Did you try another HMC6352 device?
What is I2C clock(SCL) frequency? Looks like this device can only go upto 100KHz.


Thanks,
MC
0 Kudos

1,960 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by francisxav on Thu Sep 12 23:22:11 MST 2013
I have checked it with oscilloscope. All the address are sent correctly, however no data is received. Start, Stop, ACK bit are all present. Please see the attached file.
This is the order of the data that I see btw,
Start bit
1) 0x42 -I2CWRITE
ack
2) 0X41 -slave register address
ack
stop

start
3) 0x43 -I2CREAD
ack
4) nothing - supposed to be the data from the sensor to LPC board.
stop


Thanks.
Francis
0 Kudos

1,960 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by francisxav on Thu Sep 12 21:20:56 MST 2013
I tried printing at the end of the I2CREAD and I2CWRITE. Both actually give me 'SUCCESS'. Any suggestion?
0 Kudos

1,960 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by francisxav on Wed Sep 11 22:33:32 MST 2013
Hi, Thanks for the reply.

I connect the lpc1769 to my laptop usb, so I don't directly power up the lpc board. My whole system is using 5v, and at the moment, I only have voltage regulator for 5V. So that's why i'm using 5v.

Okay, I'll try to get return value from those 2. Anw, do you spot any mistake or maybe concept mistake in the code?

Thanks,

Francis
0 Kudos

1,960 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by rocketdawg on Wed Sep 11 08:40:53 MST 2013
Why would you run this sensor at 5V?
the LPC1769 is 3.3v, the sensor will run at 3.3V.
it just adds unnecessary complication.

Why not check the return value from I2CWrite/Read  and print out something.
0 Kudos

1,960 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by francisxav on Wed Sep 11 00:45:11 MST 2013
Hi,

I've tried several things but the compass sensor still doesn't work. I figured that only the sl.addr7bit got shifted and ORed accordingly whether it's 'write' or 'read'. So the slave's 7 bit address (READ_WRITE_OPERATION) is 0x21 while the slave register address (COMMAND_GET_DATA) stays at 0x41. I've tried others combination (eg. both shift left, in binary form, etc) also, but it still doesn't work.

Just some extra info (data sheet is attached),
•I’m using SDA2 (P0.10) and SCL2 (p0.11) - I'm using lpc1769
•As given in data sheet (pg.3) The compass sensor address is 0x42 (read) / 0x43 (write). So, I shift right by 1 bit and use 0x21 as the 7bit address for I2C_READ and I2C_WRITE in the code .
•The slave register address is 0x41 (data sheet pg. 5 – command ‘A’)
•The code use 6000u sec delay as suggested (data sheet pg.8 table 3)
•I connect 15kohm resistor between SCAL and SDA line to 5v. (10k is recommended for 3.3v. However 5v is still within the accepted range)

The program is returning '0' all the time even when I move the compass sensor.

So, this is the code

#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;
}


Pleaseeeeeeeeeee helpppppp.... Thanks in advanced!!!
0 Kudos

1,960 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by francisxav on Wed Sep 11 00:36:36 MST 2013
Hi,

I've tried to changes a few things but all failed. I figured (if i don't understand wrongly) that only the sl.addr7bit will get shifted and ORed depending whether it is 'write' or 'read' (which has been mentioned earlier). Thus, the 7bit address of the HMC6352 (READ_WRITE_OPERATION) is 0x21 while the slave register address (COMMAND_GET_DATA) stays at 0x41.

Just some extra info,
  •I’m using SDA2 (P0.10) and SCL2 (p0.11)

  •As given in data sheet (pg.3) The compass sensor address is 0x42 (read) / 0x43 (write). So, I shift right by 1 bit and use 0x21 as the   7bit address for I2C_READ and I2C_WRITE in the code .

  •The slave register address (which is used to constantly get heading) is 0x41 (data sheet pg. 5 – command ‘A’)

  •The code use 6000u sec delay as suggested (data sheet pg.8 table 3)

  •I connect 15kohm resistor between SCAL and SDA line to 5v (recommended is 10k for 3.3v. But 5v is still within the voltage limit).

The program runs, however, I only get '0' printed as the heading.

So here's my current code

#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;
}


Pleaseeeeeeeeeeeeeeeeeeeeeeeeeee help..... Data sheet is attached!! Thanks in advance!!!
0 Kudos

1,960 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by francisxav on Tue Sep 03 21:27:35 MST 2013
Alright!!! Real thanks for your help. Hope it works  :) .

Cheers,
Francis
0 Kudos

1,960 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by usb10185 on Tue Sep 03 13:35:34 MST 2013
Hi,

Yes, I think that should do it.
Also ensure that you have the correct pull up resistors on the SDA and SCL lines.

Ken
0 Kudos

1,960 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by francisxav on Sat Aug 31 23:33:40 MST 2013
Hi Ken,

Thanks again for the response. Alright, it's getting clearer now. But let me confirm with you for another time to ensure that I understand it correctly. So, i'll change the following in the code:

static const int READ_WRITE_OPERATION = 0x21; //(previously 0x42)

static const int COMMAND_GET_DATA = 0x20; //(previously 0x41)

is this correct?

Thanks again in advance.

Regards,
Francis

0 Kudos

1,960 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by usb10185 on Fri Aug 30 07:01:14 MST 2013
Hi Francis,

See http://www.robot-electronics.co.uk/acatalog/I2C_Tutorial.html

Quote:
The placement of the 7 bit address in the upper 7 bits of the byte is a source of confusion for the newcomer. It means that to write to address 21, you must actually send out 42 which is 21 moved over by 1 bit. It is probably easier to think of the I2C bus addresses as 8 bit addresses, with even addresses as write only, and the odd addresses as the read address for the same device.



So you need 20 for Write and 21 for Read

Cheers,
Ken
0 Kudos

1,960 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by francisxav on Thu Aug 29 20:35:36 MST 2013
Hi, Ken!!

Firstly, really thanks for the reply. I didn't expect it to be so fast.

Okay, I'm getting the resolution part. However, I'm unsure which exact line that I need to change. My guess is the 'static const int COMMAND_GET_DATA = 0x41;' Do i change that to '0x21' instead? And if it is, do i need to change the 'static const int READ_WRITE_OPERATION = 0x42;' too???

Thanks again in advance. My project budget is only $50 and this sensor cost $30++. So I have to be very sure about this before i make the purchase.

Thanks again,
Francis
0 Kudos

1,960 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by usb10185 on Thu Aug 29 11:15:49 MST 2013
Hi,

The issue resolution is given above. The slave address needs to be correctly set in the code.
What is defined and what is sent out on the I2C bus are shifted by 1 bit.
Maybe get the trusty scope out and double check what you see on the SDA line!

Thanks,
Ken
0 Kudos

1,960 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by francisxav on Thu Aug 29 10:35:51 MST 2013
Hey, this is a really old thread, but I hope someone would reply. Do you mind showing me the working code for your program. I'm using the same compass sensor and lpc1769 and I'm kinda loss. I still don't understand the correction made.
0 Kudos

1,960 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by sgtengxiao on Tue Oct 16 02:37:03 MST 2012
Thank you thankyou thankyou very very very much.

The problem is solved.
0 Kudos