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

16F886 I2C question
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Jun 08, 2012 1:35 pm     Reply with quote

Quote:
#define Vistfang_Gyro 0x69

Here you are using an i2c address in 7-bit Philips format. That's not
correct for CCS. CCS uses a left-justified 8-bit slave address.
That means the correct i2c slave address for CCS is 0xD2.

Also, you are using the optional slave address, with the LSB = 1. So that
means that the SDO pin on the L3G4200D must be connected to Vdd to
enable that mode. Did you make that connection on your board ?

Also, the standard in C is for constants to be in ALL CAPS. This helps
to quickly identify them as constants when you read the code.

Quote:

Read1Byte(105, 0x0F);

Here you are using a decimal number for the i2c Slave address. Don't
use decimal, it's not the custom to use it for i2c addresses. And, as I
said above, the address that you want to use is 0xD2. (Provided that
you have pin SDO on the LG4200D connected to Vdd).


Quote:

u8 Read1Byte(u8 Vistfang_Gyro,u8 I2Cadr)
{
u8 I2CRead;
I2C_Start();
I2C_Write(Vistfang_Gyro);
I2C_Write(I2Cadr);
I2C_Start();
I2C_Write(Vistfang_Gyro + 1);
I2CRead = I2C_Read();
I2C_Stop();
printf("Something : \n\r",I2CRead);
return I2CRead;
}

Don't use variable names that are very similar to the function name.
It's confusing, it makes the code harder to read quickly, and it's a bad
coding method.


Quote:
I2CRead = I2C_Read();

Here you are making a common mistake. The i2c specification requires
a NACK on the last i2c read operation in a transaction. In CCS, this is
done by using a parameter of 0. So it should be like this:
Code:

I2CRead = I2C_Read(0);
 



Quote:

#FUSES LVP

Here you are using a rare fuse setting. It's only for special home-built
programmers that program the PIC without using a 12 or 13 volt
programming voltage. Maybe only 1% of all people do this. All normal
programmers such as ICD2, ICD3, ICD-U40, etc., PicKit 2, Pickit 3,
PicStart-Plus, etc., all use High Voltage programming. For those, you
must use the NOLVP fuse.

Quote:

while(1)
{
printf("RS232 communication working\n\r");
delay_ms(1500);

Read1Byte(105,0x0F);
delay_ms(1500);
}
}

Here in your main code, you are calling the Read1Byte() routine but you
are not using the return value. Why ? (And also the 105 needs to be
changed to 0xD2).
Your code should more like the code shown below. You get the return
value from the function, and then you display it.
Code:

void main()
{
int8 result;
.
.
.

while(1)
  {
    result = Read1Byte(0xD2, 0x0F);
    printf("result = %x \n\r", result);
    delay_ms(1500);
  }

}


Below, you have the printf line in the low-level read routine. It doesn't
really belong there, except maybe as a temporary debugging tool.
The printf belongs in the main while(1) loop, as I showed above.
Quote:

u8 Read1Byte(u8 Vistfang_Gyro,u8 I2Cadr)
{
.
.
.
printf("Something : \n\r",I2CRead);
return I2CRead;
}
Tunfiskur



Joined: 01 Jun 2012
Posts: 13

View user's profile Send private message

PostPosted: Fri Jun 08, 2012 2:15 pm     Reply with quote

Thank you all for the help guys, i really appreciate it. I have fixed all the suggestions above. I'm getting something back at least but only two numbers from the results. Either 01 or 00, depending on what register adress i choose. I have never work with the i2c before, since i used the %x in printf i should only be getting two hex letters back right?

Also i have only been using CCS for a few weeks, and the int8 and int16 does not work for me(does not get the blue text). Is that normal, do i only use int for all integers?

All the questions looks pretty silly probably but i rather look silly for one day then stupid for the rest of my days hehe Very Happy
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Jun 08, 2012 3:38 pm     Reply with quote

I'm not sure if you are really talking to the L3G4200D. Let's find out.
Here is an i2c bus scanner program that will report the addresses of any
i2c slave devices that it finds on the bus. Modify the #include, #fuses,
and the #use statements so it will work with your PIC and your board.
Then run it and see what devices it finds:
http://www.ccsinfo.com/forum/viewtopic.php?t=47707&start=21
Tunfiskur



Joined: 01 Jun 2012
Posts: 13

View user's profile Send private message

PostPosted: Fri Jun 08, 2012 3:49 pm     Reply with quote

Thats a neat little code. It returned the slave address and a number of i2c chips.

Code:
Start:
ACD ADDR: D2

Number if i2c chips found: 1
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Jun 08, 2012 4:54 pm     Reply with quote

OK, it found your chip. Post your current test program that reads the
ID register. It should be a compilable program. In other words, if
I copy and paste it into MPLAB and press the compile button, it should
not give me any errors, such as undefined variables, etc. Test it before
you post it.
Tunfiskur



Joined: 01 Jun 2012
Posts: 13

View user's profile Send private message

PostPosted: Fri Jun 08, 2012 5:04 pm     Reply with quote

Copied, compiled without errors before posted:


Code:
#include <16F887.h>
#fuses INTRC_IO,NOWDT,NOPROTECT,PUT,NOLVP,NOBROWNOUT
#use delay(clock=4M)
#use i2c(Master, sda=PIN_C4, scl=PIN_C3)
#use rs232(baud=19200, xmit=PIN_C6, rcv=PIN_C7)

// This function writes the slave address to the i2c bus.
// If a slave chip is at that address, it should respond to
// this with an "ACK".   This function returns TRUE if an
// ACK was found.  Otherwise it returns FALSE.
int8 get_ack_status(int8 address)
{
int8 status;

i2c_start();
status = i2c_write(address);  // Status = 0 if got an ACK
i2c_stop();

if(status == 0)
   return(TRUE);
else
   return(FALSE);
}


//=================================
void main()
{
int8 i;
int8 status;
int8 count = 0;

printf("\n\rStart:\n\r");

delay_ms(1000);

// Try all slave addresses from 0x10 to 0xEF.
// See if we get a response from any slaves
// that may be on the i2c bus.
for(i=0x10; i < 0xF0; i+=2)
   {
    status = get_ack_status(i);
    if(status == TRUE)
      { 
       printf("ACK addr: %X\n\r", i);
       count++;
       delay_ms(2000);
      }
   }

if(count == 0)
   printf("\n\rNothing Found");
else
   printf("\n\rNumber of i2c chips found: %u", count);

while(1);
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Jun 08, 2012 5:09 pm     Reply with quote

I didn't mean the i2c bus scanner program. I mean your program that
reads the WHO_AM_I register in the L3G4200D (register address 0x0F).
Post your current compilable version of that. You said it was returning
0 or 1, which is not correct.
Tunfiskur



Joined: 01 Jun 2012
Posts: 13

View user's profile Send private message

PostPosted: Fri Jun 08, 2012 5:33 pm     Reply with quote

This is currently what im working with:


Code:
#include "i2cversion2.h"

void write_device(unsigned char address, unsigned char data)
 {
   i2c_start();
   i2c_write(0xD2);
   i2c_write(address);
   i2c_write(data);
   i2c_stop();
   Delay_Ms(10);
}

unsigned char read_device(unsigned char address)
{
   unsigned char data;

   i2c_start();
   i2c_write(0xD2);
   i2c_write(address);
   i2c_start();
   i2c_write(0xD2+1);
   data=i2c_read(0);
   i2c_stop();
   return(data);
}

   void init_device()
{
   // not done
}

void main()
{
   int8 result=0;   

   setup_adc_ports(NO_ANALOGS|VSS_VDD);
   setup_adc(ADC_OFF);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_comparator(NC_NC_NC_NC);
   setup_oscillator(False);
   output_high (PIN_A4);

   printf("I2C TEST: \n\r");

while(1)
{   
   result=read_device(0x2D);
   printf("result = %x \n\r", result);
   delay_ms (1000);
}
}


i2cversion2.h :


Code:
#include <16F886.h>
#device adc=8

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES HS                       //High speed Osc (> 4mhz)
#FUSES NOPUT                    //No Power Up Timer
#FUSES MCLR                     //Master Clear pin enabled
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NOCPD                    //No EE protection
#FUSES BROWNOUT                 //Reset when brownout detected
#FUSES IESO                     //Internal External Switch Over mode enabled
#FUSES FCMEN                    //Fail-safe clock monitor enabled
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES BORV40                   //Brownout reset at 4.0V
#FUSES NOWRT                    //Program memory not write protected

#use delay(clock=4000000)
#use rs232(baud=19200,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#use i2c(Master,Fast,sda=PIN_C4,scl=PIN_C3)



I'm getting some data back from the gyro, for example with the current setup i have above i get result=06 . But i would think that i need to set the chip in "ON" mode by writing some values to the registers to get the chip into on mode, because according to the datasheet it comes in power down mode by default
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Jun 08, 2012 5:51 pm     Reply with quote

Here you are trying to read the OUT_Z_H register.
Quote:

result=read_device(0x2D);


Why don't you change it and try to read the WHO_AM_I register:
Code:

result=read_device(0x0F);
Tunfiskur



Joined: 01 Jun 2012
Posts: 13

View user's profile Send private message

PostPosted: Fri Jun 08, 2012 5:58 pm     Reply with quote

Update: this is finally working to some extent at least, and I'm receiving data back when i request a read from the registers. I added a init_device() to the code that sets up the chip to ON mode and other configurations.

Code:
   void init_device()
{
   write_device(0x20,0x0F);     // freq & power up/down
   write_device(0x23,0x20);    // dps settings
}


Code:
void main()
{
   int8 result=0;   

...
...
...

   printf("I2C TEST: \n\r");
   init_device();
   delay_ms (50);

...
hamid9543



Joined: 31 Jan 2013
Posts: 63

View user's profile Send private message

l3g4200d
PostPosted: Sun Feb 10, 2013 7:16 am     Reply with quote

hi to all!
i read your code and write new code
Code:

#Include <16f873a.h>
#use delay (clock = 20000000)
#Use I2C (master, sda = PIN_C3, scl = PIN_C4)
#define LCD_RS_PIN      PIN_b1                                    ////
#define LCD_RW_PIN      PIN_b2                                    ////
#define LCD_ENABLE_PIN  PIN_b3                                    ////
#define LCD_DATA4       PIN_b4                                    ////
#define LCD_DATA5       PIN_b5                                    ////
#define LCD_DATA6       PIN_b6                                    ////
#define LCD_DATA7       PIN_b7
#define CTRL_REG1 0x20
#define CTRL_REG2 0x21
#define CTRL_REG3 0x22
#define CTRL_REG4 0x23
#define CTRL_REG5 0x24
#include <LCD.c>
int L3G4200D_Address = 0xD2;   //I2C address of the L3G4200D
int x,y,z;
void writeRegister(int deviceAddress, int address,int val)
 {
    i2c_start();
    i2c_write(deviceAddress); // start transmission to device
    i2c_write(address);       // send register address
    i2c_write(val);           // send value to write
    i2c_stop();               // end transmission
 }

void setupL3G4200D(int scale)
{
  writeRegister(L3G4200D_Address, CTRL_REG3, 0b00001000);
  if(scale == 250)
  {
  writeRegister(L3G4200D_Address, CTRL_REG4, 0b00000000);
  }
  else if(scale == 500)
  {
  writeRegister(L3G4200D_Address, CTRL_REG4, 0b00010000);
  }
  else
  {
  writeRegister(L3G4200D_Address, CTRL_REG4, 0b00110000);
  }
}

void main()
{
lcd_init();
lcd_gotoxy(1,1);
printf(lcd_putc,"starting up L3G4200D");
delay_ms (1000);
setupL3G4200D(2000);            //Configure L3G4200  - 250, 500 or 2000 deg/sec
writeRegister(L3G4200D_Address,0x20,0x0F);
delay_ms(1500);                 //wait for the sensor to be ready

while(true)
{
    i2c_start();
    i2c_write(L3G4200D_Address);
    i2c_write(0xD3);
    i2c_start();
    int xLSB=i2c_read(0x28);  // register to read
    int xHSB=i2c_read(0x29);  // register to read
    x = make16(xHSB,xLSB);
    int yLSB=i2c_read(0x2A); 
    int yHSB=i2c_read(0x2B);
    y = make16(yHSB,yLSB);
    int zLSB=i2c_read(0x2C); 
    int zHSB=i2c_read(0x2D);
    z = make16(zHSB,zLSB);
    i2c_stop();              //This will update x, y, and z with new values
  lcd_gotoxy(1,2); 
  printf(lcd_putc,"x=%03u",x);
  lcd_gotoxy(6,1);
  printf(lcd_putc,"y=%03u",y);
  lcd_gotoxy(12,1);
  printf(lcd_putc,"z=%03u",z);
  delay_ms(100);
}
}

}

but lcd show x=-1 y=-1 z=-1
can you help me?
Ttelmah



Joined: 11 Mar 2010
Posts: 19348

View user's profile Send private message

PostPosted: Sun Feb 10, 2013 8:27 am     Reply with quote

You have misunderstood how to reverse the I2C bus:
Code:

    int xLSB,xMSB,yLSB,yMSB,zLSB,zMSB;
    //C requires variables to be declared at the start of a code section
    //CCS doesn't complain, but commonly goes wrong if you use the
    //midblock definitions (not standard C)....
    i2c_start();
    i2c_write(L3G4200D_Address);
    //This is where you have to _write_ the register number you want
    i2c_write(0x28); //select the register you want to read
    i2c_write(L3G4200D_Address + 1); //now turn the bus round
    i2c_start(); //restart - the bus is now set to _read_
    xLSB=i2c_read();  //Now read the register
    //I2c_read cannot send anything except ack/nack at the end of
    //the transfer - the bus is in _read_ mode now......
    xMSB=i2c_read(); //Most chips will auto-increment to the next
    //register - check that yours does
    x = make16(xMSB,xLSB);
    yLSB=i2c_read();
    yMSB=i2c_read();
    y = make16(yMSB,yLSB);
    zLSB=i2c_read();
    zMSB=i2c_read(0);  //ACK the last byte - i2c _requires_ this
    z = make16(zHSB,zLSB);
    i2c_stop();              //This will update x, y, and z with new values


Once the bus is set to 'read', you can't send addresses. I2C_read, accepts just 0/1, for NACK/ACK, and the last byte should use this.

Best Wishes
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

Re: l3g4200d
PostPosted: Sun Feb 10, 2013 8:40 am     Reply with quote

hamid9543 wrote:
i read your code and write new code
The only relation between your question and the original Topic Starter is that you both are using the same gyro sensor.
For a new question like this please start a new thread, there you can optionally add a link to this thread for reference but since your code is so different it doesn't matter.

A few tips to start with:
- Try the I2C scanner program mentioned a few postings earlier in this thread. It will prove your I2C hardware is setup correctly and is configured for the address you expect it is using.
- I'm confused you get results of '-1' when using '%u' as format specifier. The 'u' is for 'unsigned', so only positive values can be displayed. Is the code as posted the exact same version as you are testing with?
- In CCS an int has an 8 bits size for the PIC16 and PIC18. Your values of 500 and 2000 don't fit this.
- Add #case to your program. By default the CCS compiler doesn't care about mixing small and upper case letters but the original the C language is case sensitive. Your program is easier to read when words 'look' the same as what everybody got used to.

Post the results in the new topic you are going to start.
otacon



Joined: 12 Nov 2010
Posts: 3

View user's profile Send private message

PostPosted: Fri Mar 22, 2013 1:15 pm     Reply with quote

Hi PGM
I did everything is right and i got a value about every axis X,Y,or Z but it seem not change when i move the sensor,it's just update the value when i cut off and reconnect the power supply for this sensor. what happened with my sensor? Can i reset it with a auto cycle!
Sorry about my english!
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 1, 2  Next
Page 1 of 2

 
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