CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

I2C Communication Problem using PIC16F877A
Goto page Previous  1, 2, 3, 4  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
(-_-)
Guest







PostPosted: Sun Jan 07, 2007 5:06 am     Reply with quote

I've used the code that post by PCM programmer from my hmc6352 sensor, but why is the output that I get from it as shown below?:
Heading in degrees = 6298
Heading in degrees = 6298
Heading in degrees = 6298
Heading in degrees = 6298
Heading in degrees = 6298
Heading in degrees = 6298
Heading in degrees = 5658
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Jan 07, 2007 1:26 pm     Reply with quote

Look at the previous comments in the thread:
Quote:

I just received two new compasses from Honeywell and they work fine.
The two that I received before were from a "bad batch".

So it's possible that you also have a bad unit.

Quote:

I'm not a cracker-jack programmer, but I got the code PCM Programmer
posted to work by changing the return line of the HMC6352_read_heading
function to the following:
return((int16)lsb | ((int16)msb << 8));

Did you try this ?


The problem is that I don't have a HMC6352 unit to test. They're very
expensive. The cheapest one at Sparkfun is $60 (US).
http://www.sparkfun.com/commerce/product_info.php?products_id=7915
I don't want to spend $60 just to help someone write a driver. I tried
to help as much as I could by writing a preliminary driver, based on
the data sheet. But I don't guarantee that it works, because I don't
have an actual HMC6352 unit to test. You have to keep this in mind,
when using that driver code.
YARGICH



Joined: 19 Jan 2007
Posts: 8

View user's profile Send private message

PostPosted: Fri Jan 19, 2007 4:19 am     Reply with quote

Hi,

I try to use my HMC6352 sensor with PIC16f687 and CCS. But I didn't accomplish to use it. When I send a first command, it gives to me ACK. But when I send next command or new command, it gives to me NOACK. Also when I choose "force_HW", it always gives to me "2=Collision". I didn't understand anything about ack answers of my HMC6352 sensor. According to you, is it broken down? or what is my mistake.

This is my test software:

Code:

#include <16F687.h>

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES PUT
#FUSES NOPROTECT                //Code not protected from reading
#FUSES BROWNOUT                 //No brownout reset
#FUSES NOMCLR                   //Master Clear pin used for I/O
#FUSES HS                       //Internal RC Osc, no CLKOUT

#use delay(clock=20000000,RESTART_WDT)
#use i2c(Master,slow,sda=PIN_B4,scl=PIN_B6)
#use rs232(xmit=PIN_B7, rcv=PIN_B5)

//Port Adreslerini tanımlama
#byte    PORTA  = 0x05
#byte    PORTB  = 0x06
#byte    PORTC  = 0x07
#byte    SSPCON = 0x14
#byte    ANSEL  = 0x11E
#byte    CM1CON0 = 0x119
#byte    CM2CON0 = 0x11A

short timeout_error;
byte Byte1,Byte2;
long i,j,k;


//******************************************************************************
//timeout lu com port okuması
char timed_getc()
{
long timeout;
timeout_error=false;
timeout=0;
while (!kbhit()&&(++timeout<50000)) //  1/2 sn
 delay_us(10);
 if (kbhit())
   return (getc());
 else {
   timeout_error=true;
   return (0);
}
}
//******************************************************************************
void init_I2C() {
   output_float(PIN_B4);
   output_float(PIN_B6);
}
//******************************************************************************
#int_rda
void usart_kesme(){
byte buf1,buf2,buf3,ack;

buf1=Timed_getc();

switch(buf1)
 {
   case 'a':

      I2C_START();
      ack=I2C_WRITE(0x42); // write command
      ack=I2C_WRITE(0x47); // "G" command
      ack=I2C_WRITE(0x74); // RAM adress
      ack=I2C_WRITE(0x30); // Standby Mode // I tried to Operating mode
      I2C_STOP();

      Delay_ms(10);

      I2C_START();
      ack=I2C_WRITE(0x42); // write command
      ack=I2C_WRITE(0x47); // "G" command
      ack=I2C_WRITE(0x4E); // RAM adress
      ack=I2C_WRITE(0x00); // Output Mode // I tried to Query mode
      I2C_STOP();

      Delay_ms(10);

      I2C_START();
      ack=I2C_WRITE(0x41); // 'A' Command (in Standby Mode) // 0x43 Command (in Operating Mode)
      buf2=I2C_READ();     // Read MSB of Heading
      buf3=I2C_READ();     // Read LSB of Heading
      I2C_STOP();

      printf("\n\r ack : %u",ack);
      printf("\n\r buf2: %u",buf2);
      printf("\n\r buf3: %u",buf3);
      Delay_us(100);
      break;
   case 'b':

     break;
   default: Printf("\n\rDefault "); break;
 }

}
//******************************************************************************
#int_RTCC
RTCC_isr()
{

}
//******************************************************************************
//******************************************************************************
//                               ANA PROGRAM
//******************************************************************************
void main()
{
   setup_adc_ports(NO_ANALOGS|VSS_VDD);
   setup_adc(ADC_OFF);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_8);

   init_I2C();

   enable_interrupts(INT_RTCC);
   enable_interrupts(INT_RDA);
   enable_interrupts(GLOBAL);

   set_tris_a(0x00);
   set_tris_b(0x20);
   set_tris_c(0x00);

//ANA_DONGU:
while(TRUE){

}


}
YARGICH



Joined: 19 Jan 2007
Posts: 8

View user's profile Send private message

PostPosted: Fri Jan 19, 2007 5:30 am     Reply with quote

I want to add something. When I send 0x43 command without force_HW, it gives to me ACK and I read MSB of heading=0 and LSB of heading=255.

I haven't got a oscillascope. So, I don't see my signals. What can I do to use this sensor.
Ttelmah
Guest







PostPosted: Fri Jan 19, 2007 11:07 am     Reply with quote

First, get rid of Timed_getc. This is used in 'mainline' code, when it is important not to hang, if a charcater doesn't arrive. In the interrupt, it is unecessary (the interrupt only gets called, if there _is_ a character), and using it will result in interrupts being disabled, if you latter use a timing function in main.
Second do the same with your I2C operations. These should move to the main code. In the interrupt, simply receive a character, and store it. Get rid of all delays in the interrupt handler. In the main, check if a character is waiting, and if it is, get it, and execute the required I2C routine.
You don't need to fiddle around with the tris registers yourself. Unless you select 'fast_io', or 'fixed_io', the compiler takes care of this.
Send you mode setting, just _once_ when you initialise the chip.
Then in your main code, send an 'A' command. This triggers a reading to be taken, wait for the reading time, then send another 'A' command, and retrieve the data.

Best Wishes
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Jan 19, 2007 2:36 pm     Reply with quote

In addition to Ttelmah's comments, I have this comment:

Quote:

I2C_START();
ack=I2C_WRITE(0x41); // 'A' Command (in Standby Mode) // 0x43 Command (in Operating Mode)
buf2=I2C_READ(); // Read MSB of Heading
buf3=I2C_READ(); // Read LSB of Heading
I2C_STOP();

Your code to read the data is not correct. It doesn't follow the method
shown in the HMC6352 data sheet.

The data sheet shows how to read two bytes in Example 2, on page 9.
http://www.sparkfun.com/datasheets/Components/HMC6352.pdf
They show this sequence:
Start bit
Send 0x43 to slave
Get ACK from slave
Receive 0x55 from slave
Send ACK to slave
Receive 0x00 from slave
Send NACK to slave (no acknowledge)
Stop bit

I showed how to do this in my sample code posted earlier in this thread.
arunb



Joined: 08 Sep 2003
Posts: 492
Location: India

View user's profile Send private message Send e-mail

RE:"
PostPosted: Sat Jan 20, 2007 11:05 am     Reply with quote

Hi,

Just for your information.

I have had trouble making the standard I2C functions for the 24LC256 memory work for the 16F877A mcu, I was using PCM version 3.228. I noticed that the pic went haywire when I accessed the i2c functions.

I then used PCM version 3.169 instead of 3.228 and this solved the problem !!

thanks
arunb
YARGICH



Joined: 19 Jan 2007
Posts: 8

View user's profile Send private message

PostPosted: Sat Jan 20, 2007 1:56 pm     Reply with quote

@PCM programmer,

I wrote a new software as you said. But it isn't working. When the program start, it gives NOACK, MSB=255 and LSB=255.

when write only this commands;
Start bit
Send 0x43 to slave
Get ACK from slave
Receive 0x55 from slave
Send ACK to slave
Receive 0x00 from slave
Send NACK to slave (no acknowledge)
Stop bit

it gives ACK, MSB=0 and LSB=0.


is it useful to change my CCS 3.228 to CCS 3.169?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sat Jan 20, 2007 2:11 pm     Reply with quote

Quote:
When the program start, it gives NOACK, MSB=255 and LSB=255.

Do you have pull-up resistors installed on the i2c bus ?
You need them. You need one pull-up on SDA and
one on SCL. A typical value is 4.7K ohms.
YARGICH



Joined: 19 Jan 2007
Posts: 8

View user's profile Send private message

PostPosted: Sat Jan 20, 2007 2:51 pm     Reply with quote

Yes, I have. But I have 2 pieces 10k pull-up on SDA and SCL. I know that, 10K is needed for 100kHz communication and 1K is needed for 400kHz communication. am I right? What is your opinion about value of pull-up.
YARGICH



Joined: 19 Jan 2007
Posts: 8

View user's profile Send private message

PostPosted: Sat Jan 20, 2007 3:27 pm     Reply with quote

when I send these commands;
Code:

      I2C_START();
      ack1=I2C_WRITE(0x43); // Read from HMC6352
      ack2=I2C_WRITE(0x72); // Read from EEprom
      ack3=I2C_WRITE(0x00); // EEprom adress 0x00
      Byte1=I2C_READ(0);      // it must read 0x42 (default slave adress)
      I2C_STOP();

I see these results;
ack1 : 0
ack2 : 1
ack3 : 1
Byte1: 255


Thank you very much for your interests.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sat Jan 20, 2007 4:07 pm     Reply with quote

Quote:
I2C_START();
ack1=I2C_WRITE(0x43); // Read from HMC6352
ack2=I2C_WRITE(0x72); // Read from EEprom
ack3=I2C_WRITE(0x00); // EEprom adress 0x00
Byte1=I2C_READ(0); // it must read 0x42 (default slave adress)
I2C_STOP();

That's not the correct protocol to read a byte from EEPROM in the HMC6352.
On page 10 of the HMC6352 data sheet, they show a timing diagram
of how to read a byte from a register. The procedure for reading
EEPROM is similar.

The diagram on page 10 shows the sequence of i2c operations that
are required to read a byte. Your code above is trying to invent a
new protocol, but you can't do that. You can only use the protocol
that the chip designers put into the chip.

HMC6352 data sheet:
http://www.sparkfun.com/datasheets/Components/HMC6352.pdf
YARGICH



Joined: 19 Jan 2007
Posts: 8

View user's profile Send private message

PostPosted: Sat Jan 20, 2007 6:57 pm     Reply with quote

Thak you very much. I accomplished to run the HMC6352. When @PCM Programmer said that it is like EEPROM, I remembered that I wrote my EEPROM software.

But, in page 10 of HMC6352 datasheet said that I2C_STOP and I2C_START is between write and read commands.

anyway...


Thank you very much again to help me to PCM Programmer.

Best Regards
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Jan 21, 2007 5:55 pm     Reply with quote

I agree that most chip manufacturers specify that a Restart operation
should be done at that point, instead of a Start and a Stop.

This slide show presentation from Microchip goes into some detail on
why a Restart is used when reading from an EEPROM. The slides and
explanations for Restart are mainly on pages 20 to 22:
http://ww1.microchip.com/downloads/en/devicedoc/i2c.pdf
Nickmo
Guest







HMC6352 does not recalculate heading
PostPosted: Fri Apr 13, 2007 12:14 pm     Reply with quote

I've been having trouble interfacing an HMC6352 with a PIC18LF2520.

I call the following function repeatedly, but after the first heading calculation on power-up, the compass does not recalculate heading and just returns the first value, regardless of how I rotate the compass.

Any help would be greatly appreciated.

Code:

#use    I2C(Master, sda=SDA_PIN, scl=SCL_PIN)

void getHeading(){
   disable_interrupts(global);
   i2c_start();
   i2c_write(COMP_W_ADDY);
   i2c_write(GET_DATA_CMD);
   i2c_stop();
   delay_ms(6);
   i2c_start();
   i2c_write(COMP_R_ADDY);
   msb = i2c_read();
   lsb = i2c_read();
   i2c_stop();
   heading = ((int16)lsb | ((int16)msb << 8));
   enable_interrupts(global);
}
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page Previous  1, 2, 3, 4  Next
Page 2 of 4

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group