I2C compass problem

Hi

I am trying to get my compass working ( http://www.sparkfun.com/commerce/produc … ts_id=7915 )

but have a bit of trubbl, I am not a verry experienced programmer so i think it is my code. This is my first I2C projekt.

the code i am using:

#include <mega8.h>
#include <stdio.h>                  

#asm  
    .equ __i2c_port=0x18     // the I2C bus is connected to PORTB  
    .equ __sda_bit=3          // the SDA signal is bit 3  
    .equ __scl_bit=4            // the SCL signal is bit 4 
#endasm


#include <i2c.h>
#include <delay.h>                                         
                         
                                                      
#define comand 0x41 //"A"  
#define compass_address 0x2A //42   


unsigned char compass_read ()
{
unsigned char data;
i2c_start();
i2c_write(compass_address | 1);
i2c_write(comand);
data=i2c_read(0);
i2c_stop();  
printf("\n\r%d", data); 
printf("\r");
return data;
}


void main(void) 
{     

unsigned char i;

// initialize the I2C bus
i2c_init();

 
 //USART
UCSRA=0x00;
UCSRB=0x18;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x33;

 
//2 Wire Bus initialization
// Generate Acknowledge Pulse: Off
// 2 Wire Bus Slave Address: 43h
// General Call Recognition: Off
// Bit Rate: 100,000 kHz
TWSR=0x00;
TWBR=0x20;
TWAR=0x86;
TWCR=0x04;     


while (1)
      {  
      
// read from compass
i=compass_read () ;

printf("\n\r%d", i);      

delay_ms (500) ;

      };
}

I have used the Code Wision AVR code wizard for the basic part of the code. in the terminal it just prints 255, and it doesent make any diffrence if i disconect the compass.

Thanks for all the help :slight_smile:

Hi. As a side note, I suggest that you learn about bit masking. I have a page about it here:

http://thedotcommune.com/bitmasking.html

I can’t help you with the code unless I know what i2c_start() and other functions do. Generally, I2C is used in an interrupt driven manner, so I suspect you have some ISRs that i2c.h provides? What compiler and libraries are you using?

thx for the bit banging link, i’ll be sure to read it:)

I am using the codevision AVR C compiler.

i have made some changes to the code, but it is stil not working.

I have also put some questions and coments in the code aswell, if you could answer the it would be great:D

any questions about the code, dont hessetate to ask.

#include <mega8.h>
#include <stdio.h>                  

#asm  
    .equ __i2c_port=0x18     // the I2C bus is connected to PORTB 
    .equ __sda_bit=3         // the SDA signal is bit 3  
    .equ __scl_bit=4         // the SCL signal is bit 4
#endasm

#include <i2c.h>
#include <delay.h>                                         
                         
                                                  
#define comand 0x41 //"A"             //the "A" comand is the get data comand , see page 5 in datasheet 
#define compass_address 0x2A //42    // am I using the rigth adress for the compass?


unsigned char compass_read ()
{
unsigned char data;

i2c_start();       //"Per the I2C spec, all transitions in the SDA line must occur when SCL is low. This requirement leads to two unique
                      //conditions on the bus associated with the SDA transitions when SCL is high. Master device pulling the SDA line low while
                      //the SCL line is high indicates the Start (S) condition, and the Stop (P) condition is when the SDA line is pulled high while
                     //the SCL line is high." datasheet.
i2c_write(compass_address | 1);     // First I am sending the adress (7 bit) folowed by a "1"
i2c_write(comand);                  // then I sending a comand, telling it to send me data
data=i2c_read(0);                   // the ricived data is put into the char, data
i2c_stop();                         // am I comunicating with the compass rigth? 
return data;
}


void main(void) 
{     

unsigned char i;	//char to put data in		

// initialize the I2C bus
i2c_init();
            
 //USART
UCSRA=0x00;
UCSRB=0x18;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x33;
                         


while (1)
      {  
      
i=compass_read () ;     // read from compass, putting data in "I"

printf("\n\r%d", i); 	// printing "I"
printf("\r");       

delay_ms (500) ;	// delay

      };
}

The address is wrong! It’s 0x42, ie: 66 decimal. By the way, the following statements are equivalent in C:

#define command 0x41

#define command ‘A’ /* ‘A’ is the same as 0x41 */

Also in general, macros are in upper case (ie: COMMAND), a good name might be COMPASS_READ or something.

constants and #define’s are customarily in UPPER CASE in C to distinguish them from variables

stevech:
constants and #define’s are customarily in UPPER CASE in C to distinguish them from variables

that’s what I just said above?

stevech:
that’s what I just said above?

sorry - your post wasn’t visible to me when I posted

ops…stupid me, mistaking hex for decimal…well thanks for noticing, but it stil doesent want to work, now it prints 127 instead of 255.

I also figured out that the data comes in two bytes, so i have changet the code for that. it then prints 127 in the first byte, and then 255 in the second.

I am pretty sure that the error is in this function;

unsigned char compass_read ()
{
unsigned char datah;   
unsigned char datal; 
                    
i2c_start();                            

i2c_write(COMPASS_ADDRESS);     
        
i2c_write(COMPASS_COMAND);  

datah=i2c_read(0);

datal=i2c_read(1);           
           
i2c_stop();
 
printf("\n\r%d", datah); 
printf("\r");          
                
printf("\n\r%d", datal); 
printf("\r");                           
    
return ;
}

the I2C standard says that the slave will put the SDA line low when it has recived a byte to confirm that there is no problem, how can i check this? does the code support it?

I have spendt a Week trying to make this work…getting cind of desperate and all help is appriciated, maby a code to test if the compass works?

[/code]

datah=i2c_read(0);

datal=i2c_read(1);

What does i2c_read do exactly (what parameter does it take?) in your library? I use GNU, so I don’t know how your library and tools work, but it would be helpful to know what that function is supposed to take. For example: how does i2c_read know the slave’s address? How do you set your AVR’s (master) address? What does the 0 and 1 in the parameter do?

Sparkfun has sample code for the ARM7 for talking to this chip:

http://www.sparkfun.com/Code/LPC2138_Test_IIC.zip

(look at just main.c, specifically the function “HMC6352_breakout( void )” – this code isn’t portable to yours, but it might give you some ideas.

I wanted to fire up an AVR here and try to test things out for you but unfortunately both my AVR ISPs are somehow dead. I’ve ordered an AVR ISP MkII from digikey but it will take 3 days or so to get here :frowning: If you still don’t have it working by then, I will be happy to duplicate your efforts here with one of my AVRs and then we can hopefully get to the bottom of it. In general, your code looks OK, I would be concerned about your use of their i2c library calls.

On a side note: how is it wired? Do you have pull-up resistors on both I2C lines? Did you tell your AVR to use the pins in question as I2C pins? Some of that might be done by the i2c init stuff, but I don’t know. Are you using 5V or 3.3V for VCC?

I am not sure exactly what it does, how can i find out?

I am using 3,3V and have 10k pull up resistors.

Well, you should know how to use your libraries, and at least some of what they do. Try to find API documentation for your i2c library or, failing that, find that file named ‘i2c.h’ and read any comments in it. Make sure you’re using the functions that start with ‘i2c_’ correctly. Your compiler/IDE might come with help pages that describe the API as well.

3.3V and 10K sounds right, I have also heard of people (on the ARM forum) using smaller resistors, like 4.7K.

this is how I2C.h looks like:

/*
  CodeVisionAVR C Compiler
  (C) 1998-2000 Pavel Haiduc, HP InfoTech S.R.L.

  Prototypes for I2C bus master functions

  BEFORE #include -ING THIS FILE YOU
  MUST DECLARE THE I/O ADDRESS OF THE
  DATA REGISTER OF THE PORT AT WHICH
  THE I2C BUS IS CONNECTED AND
  THE DATA BITS USED FOR SDA & SCL

  EXAMPLE FOR PORTB:

    #asm
        .equ __i2c_port=0x18
        .equ __sda_bit=3
        .equ __scl_bit=4
    #endasm
    #include <i2c.h>
*/

#ifndef _I2C_INCLUDED_
#define _I2C_INCLUDED_

#pragma used+
void i2c_init(void);
unsigned char i2c_start(void);
void i2c_stop(void);
unsigned char i2c_read(unsigned char ack);
unsigned char i2c_write(unsigned char data);
#pragma used-

#endif

Ok, and when you do this:

datah=i2c_read(0);

datal=i2c_read(1);

Is that right, based on their API?

I can give you some source for I2c that is complete, i.e., it doesn’t use any library routines. Thus, you have total visibility and control, if you want. It works with a DS1307 chip.

yeah thanks that would be great:D

I dont understand much of the content in I2C.h, can anine axplain shortly?

I was going to attach a zip file to this posting - containing the I2C routines in C. But this forum doesn’t seem to allow attachments?

So you may get the DS1307 code for I2C and modify it for your chip. That DS1307 code is a module within a larger application. That code can be found at

http://www.atmanecl.net/EnglishSite/indexEnglish.htm

and look for the link to the OPEX download,.

Is your compass hooked up with SDA to port B bit 3 and SCL to port B bit 4?

If not, you will have to change the equates at the start of your program. Also , does the I2C routiine work with by bitbanging on any generic I/O or does it use the internal I2C port on the cpu?

/mike

yes it is hooked up on pin 3 and 4…

I am not sure how the functions i use work, i think finding that out is the key. But i dont know what liberary it uses etc. does anyone know?

check your makefile? read some documentation? Find something called ‘i2c.c’ or ‘i2c.s’ or something? No offense intended, but you should know at least something about your tools…

It looks like the code expects it to be hooked to port b bit 3 (DIP pin 17, TQFP pin 15) and bit 4 (DIP pin 18, TQFP pin 16), assuming it bit-bangs. This is also the SPI port, so you may have to disconnect your programmer for it to work.

I found a manual for CodeVision AVR at http://www.ece.auckland.ac.nz/~swar051/ … Manual.PDF