I2C difficulties reading BMP180 temperature

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

Hey guys i was trying to learn how to use the I2C or TWI to learn how to communicate with different sensors and chips because i have alot of cool things but they all require I2C so i decided to try educate myself. So far i think im close but i still need alot of practice and reading. I was testing what i knew with the BMP180 pressure sensor and temperature sensor to see if i could read the temperature but i  must be doing something wrong. Here is a display of the full comunication to the BMP180:

 

 

So the issue i am experiencing is that i can not read the temperature. When i read the LSB it is always 0x00 and when i read the MSB it is always 0x80. Also if you have a look at the picture above there is an address i circled with a red circle. this is supposed to be 0xEF not 0xEE. What is strange is that it shows 0xEE but says Read?  0xEE is supposed to be write though so im not sure what the problem is there

Last Edited: Sun. Dec 6, 2015 - 03:52 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here is the code i am using. 

/*
 * i2c_test.c
 *
 * Created: 12/5/2015 6:49:53 AM
 *  Author: Atticus
 */

#define F_CPU 16000000UL
#include <avr/io.h>
#include <stdio.h>
#include <avr/pgmspace.h>
#include <util/delay.h>

#define START 0x08
#define RESTART 0x10

#define SLA_W 0xEE
#define SLA_R 0xEF

#define SLA_W_DATA_ACK 0x18
#define SLA_R_DATA_ACK 0x40
#define DATA_ACK 0x28

#define TEMP 0x2E
#define TEMP_REG_MSB 0xF6
#define TEMP_REG_LSB 0xF7

uint8_t read_status =0;

//two bytes to store temperature word in
uint8_t MSB = 0;
uint8_t LSB = 0;

int counter;

int main(void)
{
  Serial.begin(9600);
  init_i2c();
  DDRB |= (1<<PINB5);
  sei();

  while(1)
  {

    _delay_ms(4);

    TWIStart();

    if ((TWSR & 0xF8) != START){
      Serial.println(TWSR);
      led();
    }

    TWIWrite(SLA_W);

    if ((TWSR & 0xF8) != SLA_W_DATA_ACK){
      Serial.println(TWSR & 0xF8);
      led();
    }

    TWIWrite(TEMP);

    if ((TWSR & 0xF8) != DATA_ACK){
      Serial.println(TWSR & 0xF8);
      led();
    }

    TWIStop();

    _delay_ms(5);

    TWIStart();

    if ((TWSR & 0xF8) != START){
      Serial.println(TWSR);
      led();
    }

    TWIWrite(SLA_W);

    if ((TWSR & 0xF8) != SLA_W_DATA_ACK){
      Serial.println(TWSR & 0xF8);
      led();
    }

    TWIWrite(TEMP_REG_MSB);

    if ((TWSR & 0xF8) != DATA_ACK){
      Serial.println(TWSR & 0xF8);
      led();
    }

    TWIStart();

    if ((TWSR & 0xF8) != RESTART){
      Serial.println(TWSR);
      led();
    }

    TWIWrite(0xEF);                            //Even though i write 0xEF here the logic analyser reads it as 0xEE? but the binary

    if ((TWSR & 0xF8) != SLA_R_DATA_ACK){
      Serial.println(TWSR & 0xF8);
      led();
    }

    MSB = TWIReadNACK();

    //LSB = TWIReadNACK();

    TWIStop();

  }

}

void init_i2c(void){

  //set SCL to 400kHz
  TWSR = 0x00;
  TWBR = 0x0C;

  //enable TWI
  TWCR = (1<<TWEN);
}

void TWIStart(void){
  TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
  while ((TWCR & (1<<TWINT)) == 0);
}

//send stop signal
void TWIStop(void){
  TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);
}

void TWIWrite(uint8_t u8data){
  TWDR = u8data;
  TWCR = (1<<TWINT)|(1<<TWEN);
  while ((TWCR & (1<<TWINT)) == 0);
}

uint8_t TWIReadACK(void){
  TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
  while ((TWCR & (1<<TWINT)) == 0);
  return TWDR;
}

//read byte with NACK
uint8_t TWIReadNACK(void)
{
  TWCR = (1<<TWINT)|(1<<TWEN);
  while ((TWCR & (1<<TWINT)) == 0);
  return TWDR;
}

uint8_t TWIGetStatus(void)
{
  uint8_t status;
  //mask status
  status = TWSR & 0xF8;
  return status;
}

void led(void){

  for (counter = 0;counter<20;counter++){
    PORTB ^= (1<<PINB5);
    //_delay_ms(50);
  }
}

 

Last Edited: Sun. Dec 6, 2015 - 03:48 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Not sure if this actually destroyed the chip:

 

  • chip BMP180
  • Supply voltage: 1.8V to 3.6V(VDDA), 1.62V-3.6V(VDDD)V

 

i have been using 5v for signal lines but 3v for power supply line. Will this cause damage?

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

Will this cause damage?

According to the data sheet, absolute maximum voltage is 4.5 volts... so yes it is highly possible that did some damage. 

 

 

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

Well i soldered up another BMP chip and supplied 3v for power supply and signal pins. i still get the same values. Atleast the damaged chip has been ruled out. i think it must be my I2C

 

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

Maybe time to use a trusted library.

http://homepage.hispeed.ch/peterfleury/avr-software.html

 

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

I got it working. The problem was that i was not addressing the control register address(0xF4) before i was addressing the temperature address(0x2E). Now i get two byte values MSB and LSB which holds the temperature before all the conversions i need to do. 

 

The way i checked that it is working is by printing the byte values to my LCD. so the MSB = s and the LSB = e. the LSB changes quite frequently and the MSB only changes after a while if i hold my finger on the chip.

 

 

Thanx joeymorin i think this is a good opportunity for me to read and understand the library you have pointed me too. i will, once i understand his library which will probably take me a few solid months, test it against the code i wrote to see if its actually really working.

 

 

I have one question (would like kartman to chime in here too). Today i came across 1 situation  where I THINK that the arduino limited me in a way. i say i think because it probably did not limit me but i dont know that. So this BMP180 needs 3v. I was using the arduino to get it working by conveniently using the Serial.print() to debug stuff as i coded and tested. i say convenient because its easy to use the Serial.print function and there are no extra wires. its really quick. So the reason why i think the arduino limited me is because it was sending 5v signals and i needed it to send out 3v signals. now i could have used a logic level converter chip but i did not have. I guess i could have also used voltage dividers? i never tried this though. Anyways so i kinda forced myself to build a stand alone avr and program it with my mk2 isp while supplying it with 3v. So the power supply was 3 volts and the scl and sca signals were 3 volts. that solved my voltage problem but debuging was more dificult. I had to add an LCD library and more wires etc. So ya please tell me what i don't know that i could have done with the arduino?

 

There are 4 learning stages

 

1. you dont know that you dont know

2. you know that you dont know

3. you know that you know

4. you dont know that you know

 

 

So im at level 2 now hahaha

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

I2c relies on the pullup resistors to work. I2c masters and slaves do not actively drive the signals - they only pull them down to 0V. Thus, if your bmp180 board has the pullup resistors, then all you would see is 3V levels. Not exactly the best setup, but it works.

Last Edited: Sun. Dec 6, 2015 - 09:18 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It is my understanding that when using a 3v I2C slave device with +5 volt signal lines that failures happen because the slave can not assert (pull down) the SDA/SCL lines all the way to the logic 0 electrical level (which is near 0 volts;ground).  The +5V SCL/SDA lines get pulled down 3 or 3.3v from +5v,  which leaves them at +1.7 to +2 volts.  This is in the range that is between I2C-released-state [ logic high_ V+ ] and asserted state [logic low_ 0v].

 

I deal with this by converting the Arduino to run at 3.3V using an additional AMS1117_3.3 IC LDO voltage regulator.  They sell quantity 10-25 for about $0.30 each [ USD] on eBay.  I lift the cathode side of the schottky diode that is connected to the USB-Vcc +5V and run a AWG30 wire-wrap piece to the Vin of the AMS1117_3.3.  Then I connect the AMS1117_3.3 Vout to the Arduino's Vcc.   I sometimes remove the original AMS1117_5.0 LDO IC and just install the AMS1117_3.3 in its place.

 

Most Arduino clones do a weird hack where the VUSB_5.0 goes into the schottky diode (this type of diode has a voltage drop of only 0.3V instead of the standard silicon diode drop of 0.7v) and then into the AMS1117_5.0's Vin.  So they're feeding +4.5 into a 5.0 regulator chip.  Doing this with an AMS1117 causes the final Vout to be about 4.0 V, which is what Vcc is on most Arduino clones that are being powered by the USB. 

 

  The Vcc is +5.0 v when the V_RAW input (with +7--+15) is used to power the Arduino.

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

Rubbish.   Any Slave can actively sink the bus.   e.g. to 0V.    The pull-up resistors pull the inactive level to 3.3V or whatever your VCC is.

 

Yes, a few tricks are necessary if you have a 3.3V Slave with pull-ups to 5V.    i.e. you want to "catch" the high signal at 3.3V before it starts passing current through the Slave's substrate diodes.   This subject is covered in the I2C spec.

 

David.

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

The main issue is the voltage level for logic 1 at the 5V side. Since the resistors pull to the 3V3 rail, that is usually more than enough to satisfy the level requirements. Things get trickier with higher speed, longer busses and a number of slaves.