atmega328p - i2cmaster library - if/else statement problem

Go To Last Post
13 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello. I've been messing a couple of months with microcontrollers. I have an arduino uno and try to make it communicate with a TC74A2 temperature sensor and get temperature sample. I don't want to use the arduino libraries ( i did it in the past with success ) in order to learn better the microcontroller internals. So i fetched the i2cmaster library. I use avrdude in my Debian terminal to upload the program and the i2cmaster library's make file to compile.
I write the code and it is not getting any values but this is not the problem is i'm just experimenting and probably the code isn't correct.
The problem:
I have an if-else statement to check if the communication has began and the TC74A2 address has been sent correctly. I have attached leds on PINB0 and PINB1. The code says that in either of the two cases the one led should turn on. But since i call the i2c functions in the statement no led turns on. On the other side in a simple if-else statement, without any i2c functions inside the one led turns on. For example:

if ( 1 )
{ PORTB |= 1<<PINB0 }
else
{ PORTB |= 1<<PINB1 }

Led turns on!

result = i2c_start(0x95);
        if ( result == '1' )
        {
            i2c_stop();
            PORTB |= 1<<PINB0;
        }
        else
        {
        PORTB |= 1<<PINB1;
        }

NO led turns on!

Say the code i'm writing about the i2c communication is totally wrong.. shouldn't at least one led turn on? That's my problem and i can't locate an answer. Do you have any idea?

Here is the i2cmaster library: http://homepage.hispeed.ch/peterfleury/i2cmaster.zip
I have attached the code and a screenshot from the TC40A2 sensor, specifically about the communication.

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm not familiar with the library you're using, but I very much doubt that a routine named "i2c_start()" will return the ASCII character '1'. If the routine is prototyped to return an int or a char, then IMHO it's made a mistake; a routine that should return a boolean, and your test should look like:

if (i2c_start(0x95)) {
     oneThing();
 } else {
     otherThing();
}

And that's assuming that your manipulations of PORTB produce the effects you're looking for.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
/*************************************************************************  
  Issues a start condition and sends address and transfer direction.
  return 0 = device accessible, 1= failed to access device
*************************************************************************/
unsigned char i2c_start(unsigned char address)
{
blah blah 

This is from the source code of the library. It's really strange why it returns char, as it could do the same thing with boolean, but that's how it is.
I tried the code you posted but nothing happened..

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But that text says it returns 1 not the '1' you are testing for??

Alternatively you could just test for non-zero.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Is the address correct?? 0x95 doesnt look 7 bit address.. Just confirm it from the datasheet.. and also a basic question, is the I2C lines pulled up?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

1 = 0x01
'1' = 0x31

but I gather that's not your issue. I assume the problem is that i2c_start isn't returning. If you set result = 0 or result = '1' do you get the two leds to light?

If so, then look at the init code. Maybe something isn't done that's causing the routine to hang.

Clancy _________________ Step 1: RTFM Step 2: RTFF (Forums) Step 3: RTFG (Google) Step 4: Post

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Seems you don't call i2c_init...

Clancy _________________ Step 1: RTFM Step 2: RTFF (Forums) Step 3: RTFG (Google) Step 4: Post

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In the address i put in i2c_start is also the write or read bit. So it is 1001010 the address plus the write bit (1) it is 10010101 in total. Which is 0x95 in hex. On the second i2c_start call i changed it to 0x94 as i need to get to read mode ( it was my mistake in the previous code ).
I also added the i2c_init() function at the beginning. Also tried what clpalmer suggested ( about the declaration of the result variable ). But nothing worked.
What i see is that the i2c_start function returns integer (1 or 0) while in the prototype it says that it returns unsigned char. Here is the source code from the twimaster.c file:

/*************************************************************************  
  Issues a start condition and sends address and transfer direction.                                   
  return 0 = device accessible, 1= failed to access device
*************************************************************************/
unsigned char i2c_start(unsigned char address)
{                                                                                                      
    uint8_t   twst;                                                                                    
                                                                                                       
    // send START condition
    TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);                                                        
             
    // wait until transmission completed
    while(!(TWCR & (1<<TWINT)));                                                                       
                                               
    // check value of TWI Status Register. Mask prescaler bits.                                        
    twst = TW_STATUS & 0xF8;   
    if ( (twst != TW_START) && (twst != TW_REP_START)) return 1;                                       
                                                                                                       
    // send device address                                                                             
    TWDR = address;                                                                                    
    TWCR = (1<<TWINT) | (1<<TWEN);                                                                     
                                                                                                       
    // wail until transmission completed and ACK/NACK has been received
    while(!(TWCR & (1<<TWINT)));
                   
    // check value of TWI Status Register. Mask prescaler bits.
    twst = TW_STATUS & 0xF8;
    if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1;

    return 0;

}/* i2c_start */

and this is from the header file:

/** 
 @brief Issues a start condition and sends address and transfer direction 
  
 @param    addr address and transfer direction of I2C device
 @retval   0   device accessible 
 @retval   1   failed to access device 
 */
extern unsigned char i2c_start(unsigned char addr);

So i'm asking: Isn't this a library mistake?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Isn't this a library mistake?

I haven't the first idea why you think that? The routine returns 0/1 that easily fits into 8 bits so why shouldn't the routine return unsigned char (8bit integer) rather than unsigned int (16bit integer)?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The SLAVE_READ is 1
The SLAVE_WRITE is 0

So you select the appropriate registers by writing to SLAVE_W 0x94.
Then open the SLAVE_R 0x95 for reading.

Yes, Fleury uses 0 for GOOD and 1 for BAD return values from its library functions.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Quote:

Isn't this a library mistake?

I haven't the first idea why you think that? The routine returns 0/1 that easily fits into 8 bits so why shouldn't the routine return unsigned char (8bit integer) rather than unsigned int (16bit integer)?

Yes, it works even this way. I copied the functions i needed in my code file and compiled with my extremely newbie and simple make file. And the led now lights. So maybe it was something wrong in the makefile configuration.
I don't have deep knowledge about the makefiles and generally the programming. Now i can't still take a value from the sensor but that's another story :) I will keep experimenting and find it out..
Thank's everyone for the help, i'm happy i joined the forum!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
The SLAVE_READ is 1
The SLAVE_WRITE is 0

So you select the appropriate registers by writing to SLAVE_W 0x94.
Then open the SLAVE_R 0x95 for reading.

Yes, Fleury uses 0 for GOOD and 1 for BAD return values from its library functions.

David.


Thanks David, I had put the direction bit opposite :oops:

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Welcome to the forum. I2C is somewhat trickier than SPI in my opinion. You can also read an LM35 temperature sensor that outputs an analog voltage and read it with the avr a/d. Lots of ways to get something done. Since you can run linux, you're probably perfectly capable of making progress. Dont hesitate to ask here. Lots of smart and helpful knowledge clogging up the collective old synapses here. I'll also offer that, in my opinion, using an ide like codevision or imagecraft eliminates the need to learn the make macro syntax which might or might not be similar to unix regular expression syntax, which I hope to not have to learn also.

Imagecraft compiler user