BMP085 Revisited...
So I have purchased a few BMP180 Module's (the new version of the BMP085), which have the same exact coding structure as the BMP085. I had problems before with i2c and have since gotten other i2c devices working. I can obtain the address of the BMP from an i2cscan and if I try to get the EEPROM values with the wrong address, the data comes back as -1. With the correct address it returns set values for the eeprom, which I understand is what it should do.
When I try to get pressure or temp data from it, I have to read to the write address $EE, which gives a bouncy reading that "appears" correct, at first glance. But is not. And if you use the address the Datasheet says (0xEF (read) and 0xEE (write)) the returned data is -1.
The pressure data changes, but not to pressure changes (blowing onto sensor).
The temp data changes, it climbs, but gets to a point then starts back over at 1, gets to that point again & repeats. (holding the sensor in my hand)
neither data's really settle at a consistent point.
This is what I am using to test the sensor with:
Which I have had similar luck with:
However, of these 2 codes, I should get the same resulting values, but I dont, as you can see below.

When I try to get pressure or temp data from it, I have to read to the write address $EE, which gives a bouncy reading that "appears" correct, at first glance. But is not. And if you use the address the Datasheet says (0xEF (read) and 0xEE (write)) the returned data is -1.
The pressure data changes, but not to pressure changes (blowing onto sensor).
The temp data changes, it climbs, but gets to a point then starts back over at 1, gets to that point again & repeats. (holding the sensor in my hand)
neither data's really settle at a consistent point.
This is what I am using to test the sensor with:
CON
_clkmode = xtal1 + pll16x 'Standard clock mode * crystal frequency = 80 MHz
_xinfreq = 5_000_000
' $AA = 1010_1010
' $77 = 0111_0111
' $EE = 1110_1110
'BMP_Addr = $EE
'BMP_Addr = $77
'BMP_Addr = %1110_1110
'BMP_Addr = %1110_1111
'BMP_Addr = 10_1110
' BMP-085 / BMP-180 Datasheet: 0xEF (read) and 0xEE (write)
BMP_Read = $EE
'BMP_Write = $77
BMP_Write = $EE
'BMP_Write = $EF
BMPSCL = 12
BMPSDA = 13
Var
word AC1,AC2,AC3,AC4,AC5,AC6,B1,B2,MB,MC,MD 'E2Prom variables from BMP085
long UT, UP
OBj
I2C : "Basic_I2C_Driver_1.3" 'By Michael Green
PST : "Parallax Serial Terminal" 'By Jeff Martin, Andy Lindsay, Chip Gracey
PUB Main | mode, MSB, LSB, XLSB
PST.Start(115_200) 'Sets BaudRate for PST.
PST.Clear 'Clears PST Screen.
I2C.Initialize(BMPSCL)
I2C.Start(BMPSCL)
repeat
'I2C.ReadWord(BMPSCL, BMP_Addr, I2C#OneAddr|$AA)
AC1 := I2C.ReadWord(BMPSCL, BMP_Read, I2C#OneAddr|$AA)
AC2 := I2C.ReadWord(BMPSCL, BMP_Read, I2C#OneAddr|$AC)
ac3 := I2C.ReadWord(BMPSCL, BMP_Read, I2C#OneAddr|$AE)
ac4 := I2C.ReadWord(BMPSCL, BMP_Read, I2C#OneAddr|$B0)
ac5 := I2C.ReadWord(BMPSCL, BMP_Read, I2C#OneAddr|$B2)
ac6 := I2C.ReadWord(BMPSCL, BMP_Read, I2C#OneAddr|$B4)
b1 := I2C.ReadWord(BMPSCL, BMP_Read, I2C#OneAddr|$B6)
b2 := I2C.ReadWord(BMPSCL, BMP_Read, I2C#OneAddr|$B8)
mb := I2C.ReadWord(BMPSCL, BMP_Read, I2C#OneAddr|$BA)
mc := I2C.ReadWord(BMPSCL, BMP_Read, I2C#OneAddr|$BC)
md := I2C.ReadWord(BMPSCL, BMP_Read, I2C#OneAddr|$BE)
' // Read Temperature
I2C.WriteByte(BMPSCL, BMP_Write, $F4|I2C#OneAddr, $2E)
waitcnt ((clkfreq / 220) + cnt) ' Pause 4.5 mS
UT := I2C.ReadWord(BMPSCL, BMP_Read, $F6|I2C#OneAddr)
' // Read Pressure
mode := 3
I2C.WriteByte(BMPSCL, BMP_Write, $F4|I2C#OneAddr, $34|(mode<<6))
waitcnt ((clkfreq / 38) + cnt) ' Pause 26 mS
MSB := I2C.ReadByte(BMPSCL, BMP_Read, $F6|I2C#OneAddr)
LSB := I2C.ReadByte(BMPSCL, BMP_Read, $F7|I2C#OneAddr)
XLSB := I2C.ReadByte(BMPSCL, BMP_Read, $F8|I2C#OneAddr)
UP := (MSB<<16 + LSB<<8 + XLSB)>> (8 - mode)
PST.NewLine
PST.Dec(UT)
PST.NewLine
PST.Dec(UP)
PST.NewLine
PST.Dec(AC1)
PST.NewLine
PST.Dec(AC2)
PST.NewLine
PST.Dec(AC3)
PST.NewLine
PST.Dec(AC4)
PST.NewLine
PST.Dec(AC5)
PST.NewLine
PST.Dec(AC6)
PST.NewLine
PST.Dec(B1)
PST.NewLine
PST.Dec(B2)
PST.NewLine
PST.Dec(MB)
PST.NewLine
PST.Dec(MC)
PST.NewLine
PST.Dec(MD)
PST.NewLine
PST.Dec(AC2)
PST.NewLine
waitcnt(clkfreq + cnt)
Which I have had similar luck with:
CON
_clkmode = xtal1 + pll16x ' System clock → 80 MHz
_xinfreq = 5_000_000
CR = 13
' i2c bus contants
_i2cNAK = 1
_i2cACK = 0
BMPSCL = 12
BMPSDA = 13
Baro_Addr = $EE 'i2c address of baro sensor
{
' UT & UP Are Calculated by BMP Object.
' // Calculate True Temperature
X1 := (UT - AC6) * AC5 / 2^15
X2 := MC * 2^11 / (X1 + MD)
B5 := X1 + X2
T := (B5 + 8) / 2^4
T := Temp in 0.1 deg C
' // Calculate True Pressure
B6 := B5 - 4000
X1 := (B2 * (B6 * B6 / 2^12)) / 2^11
X2 := AC2 * B6 / 2^11
X3 := X1 + X2
B3 := (((AC1 * 4 + X3) << oss) + 2) / 4
X1 := AC3 * B6 / 2^13
X2 := (B1 * (B6 * B6 / 2^12)) / 2^16
X3 := ((X1 + X2) + 2) / 2^2
B4 := AC4 * (X3 + 32768) / 2^15
B7 := (UP - B3) * (50000 >> oss)
if B7 < $8000_0000 ' might need to be if B7 & $8000_0000 (B7 = -B7) else (B7 = +B7)
p := (B7 * 2) / B4
else
p := (B7 / B4) * 2
X1 := (p / 2^8) * (p / 2^8)
X1 := (X1 * 3808) / 2^16
X2 := (-7357 * p) / 2^16
p := p + (X1 + X2 + 3791) / 2^4
'p = Pressure in Pa
}
VAR
byte Baro_Data_f6
byte Baro_Data_f7
byte Baro_Data_f8
byte Baro_Data_f9
byte Baro_Data_fa
byte Baro_Data_fb
byte Baro_Data_fc
byte Baro_Data_fd
byte Baro_Data_fe
byte Baro_Data_ff
byte Baro_Data_AA
byte Baro_Data_AB
byte Baro_Data_AC
byte Baro_Data_AD
byte Baro_Data_AE
byte Baro_Data_AF
byte Baro_Data_B0
byte Baro_Data_B1
byte Baro_Data_B2
byte Baro_Data_B3
byte Baro_Data_B4
byte Baro_Data_B5
byte Baro_Data_B6
byte Baro_Data_B7
byte Baro_Data_B8
byte Baro_Data_B9
byte Baro_Data_BA
byte Baro_Data_BB
byte Baro_Data_BC
byte Baro_Data_BD
byte Baro_Data_BE
byte Baro_Data_BF
byte i2cSDA, i2cSCL
word UP,UT,ac1,ac2,ac3,ac4,ac5,ac6, MB,MC,MD, B1, B2
long tTemp, tPressure, tAltitude, tAirSpeed
OBJ
'umath : "umath" '0 Cog
Debug : "FullDuplexSerialPlus" ' Use with Parallax Serial Terminal to
Pub Start
Debug.Start(31, 30, 0, 115200)
' // Baro.init:
i2cSCL := BMPSCL
i2cSDA := BMPSDA
Init_i2c(i2cSDA, i2cSCL)
repeat
Debug.Str(String(13, "BMP-180 Demo"))
' // Read Pressure
start_adcPres ' start the adc then
readBaro ' read data via i2c bus
UP := baro_f6 * 256 + baro_f7 ' raw 16 bit pressure data put in UP
waitcnt(clkfreq/100 + cnt)
' // Read Temperature
start_adcTemp ' start the adc then
readBaro ' read data via i2c bus
UT := baro_f6 * 256 + baro_f7 ' raw 16 bit pressure data in UT
' // Update Values
AC1 := baro_AA * 256 + baro_AB
AC2 := baro_AC * 256 + baro_AD
AC3 := baro_AE * 256 + baro_AF
AC4 := baro_B0 * 256 + baro_B1
AC5 := baro_B2 * 256 + baro_B3
AC6 := baro_B4 * 256 + baro_B5
B1 := baro_B6 * 256 + baro_B7
B2 := baro_B8 * 256 + baro_B9
MB := baro_BA * 256 + baro_BB
MC := baro_BC * 256 + baro_BD
MD := baro_BE * 256 + baro_BF
' // Calculate Ailtutude
'Convert(3, tTemp, tPressure)
' // Display Results
Debug.Str(String(13, "Temperature = "))
Debug.Dec(tTemp)
Debug.Str(String(13, "Pressure = "))
Debug.Dec(tPressure)
Debug.Str(String(13, "Altitude = "))
Debug.Dec(tAltitude)
Debug.Str(String(13, "Air Speed = "))
Debug.Dec(tAirSpeed)
Debug.Str(String(13, "UP = "))
Debug.Dec(UP)
Debug.Str(String(13, "UT = "))
Debug.Dec(UT)
Debug.Str(String(13, "AC1 = "))
Debug.Dec(AC1)
Debug.Str(String(13, "AC2 = "))
Debug.Dec(AC2)
Debug.Str(String(13, "AC3 = "))
Debug.Dec(AC3)
Debug.Str(String(13, "AC4 = "))
Debug.Dec(AC4)
Debug.Str(String(13, "AC5 = "))
Debug.Dec(AC5)
Debug.Str(String(13, "AC6 = "))
Debug.Dec(AC6)
Debug.Str(String(13, "B1 = "))
Debug.Dec(B1)
Debug.Str(String(13, "B2 = "))
Debug.Dec(B2)
Debug.Str(String(13, "MB = "))
Debug.Dec(MB)
Debug.Str(String(13, "MC = "))
Debug.Dec(MC)
Debug.Str(String(13, "MD = "))
Debug.Dec(MD)
'waitcnt(clkfreq + cnt)
' // Return Calculated Altitude
Pub Altitude
' Calculate Altitude
return tAltitude
' // Return Calculated Temperature (Obtained via Convert)
Pub Temperature
return tTemp
' // Return Calculated Pressure (Obtained via Convert)
Pub Pressure
return tPressure
Pub Baro_UT
return UT
Pub Baro_UP
return UP
Pub Baro_AC1
return AC1
Pub Baro_AC2
return AC2
Pub Baro_AC3
return AC3
Pub Baro_AC4
return AC4
Pub Baro_AC5
return AC5
Pub Baro_AC6
return AC6
Pub Baro_MB
return MB
Pub Baro_MC
return MC
Pub Baro_MD
return MD
Pub Baro_B1a
return B1
Pub Baro_B2a
return B2
' // Convert to Calculated Values
Pri Convert(mode, TempPtr, PressurePtr) | th, x1, x2, b5, b6, x3, b3, p, b4, b7
{
' // Calculate True Temperature
X1 := (UT - AC6) * AC5 / 2^15
X2 := MC * 2^11 / (X1 + MD)
B5 := X1 + X2
T := (B5 + 8) / 2^4
T := Temp in 0.1 deg C
}
X1 := ((UT - AC6) * AC5) ~> 15
'x2 := (mc << 11) / (x1 + md)
X2 := (MC ~> 11) / (x1 + MD)
B5 := X1 + X2
long[TempPtr] := (B5 + 8) ~> 4
{
' // Calculate True Pressure
B6 := B5 - 4000
X1 := (B2 * (B6 * B6 / 2^12)) / 2^11
X2 := AC2 * B6 / 2^11
X3 := X1 + X2
B3 := (((AC1 * 4 + X3) << oss) + 2) / 4
X1 := AC3 * B6 / 2^13
X2 := (B1 * (B6 * B6 / 2^12)) / 2^16
X3 := ((X1 + X2) + 2) / 2^2
B4 := AC4 * (X3 + 32768) / 2^15
B7 := (UP - B3) * (50000 >> oss)
if B7 < $8000_0000 ' might need to be if B7 & $8000_0000 (B7 = -B7) else (B7 = +B7)
p := (B7 * 2) / B4
else
p := (B7 / B4) * 2
X1 := (p / 2^8) * (p / 2^8)
X1 := (X1 * 3808) / 2^16
X2 := (-7357 * p) / 2^16
p := p + (X1 + X2 + 3791) / 2^4
'p = Pressure in Pa
}
B6 := B5 - 4000
X1 := (B2 * ((B6 * B6) ~> 12)) ~> 11
'x2 := (AC2 * B6) ~> 11
X2 := AC2 * B6 ~> 11
X3 := X1 + X2
'B3 := ((((AC1 << 2) + X3) << mode) + 2) ~> 2
B3 := (((AC1 * 4 + X3) << mode) + 2) ~> 2
'X1 := (AC3 * B6) ~> 13
X1 := AC3 * B6 ~> 13
X2 := (B1 * ((B6 * B6) ~> 12)) ~> 16
X3 := ((X1 + X2) + 2) ~> 2
B4 := AC4 * (X3 + 32768) ~> 15
'B4 := (AC4 * (X3 + 32768)) >> 15 'unsigned 32 bit multiple
'B4 := umath.multdiv(AC4, (X3 + 32768), 32768)
B7 := (UP - B3) * (50000 >> mode) 'unsigned 32 bit multiple
'if B7 < $8000_0000
if B7 & $8000_0000
'p := (B7 / B4) << 1
p := (B7 * 2) / B4
else
'p := (B7 * 2) / B4
p := (B7 * B4) * 2
'p := umath.multdiv((UP - B3), (100000 >> mode), B4)
'th := p ~> 8
'X1 := th * th
X1 := (p ~> 8) * (p ~> 8)
X1 := (X1 * 3038) ~> 16
X2 := (-7357 * p) ~> 16
long[PressurePtr] := p + (X1 + X2 + 3791) ~> 4
' // EC_i2c_readbaro:
Pri start_adcTemp
i2cStart
i2cWrite(Baro_Addr) 'write 0xEE to i2c bus
i2cWrite($F4) 'write 0xF4 to i2c bus
i2cWrite($EE) 'write 0xEE sequence to start temp conversion
i2cStop
Pri start_adcPres
i2cStart
i2cWrite(Baro_Addr) 'write 0xEE to i2c bus
i2cWrite($F4) 'write 0xF4 to i2c bus
i2cWrite($F4 ) 'write 0xF4 sequence to start pressure conversion
i2cStop
Pri readbaro
i2cStart
i2cWrite(Baro_Addr) 'write 0xEE to i2c bus sensor write address
i2cWrite($F6) 'write 0xF6 to i2c bus sensor starting register
i2cStart 'do a restart
i2cWrite(Baro_Addr|1) 'write 0xEF (read cmd) to i2c bus sensor read address
Baro_Data_f6 := (i2cRead(0)) 'i2c read 12 BYTES with ack bit
Baro_Data_f7 := (i2cRead(0)) ' V
Baro_Data_f8 := (i2cRead(0)) ' V
Baro_Data_f9 := (i2cRead(0)) ' V
Baro_Data_fa := (i2cRead(0)) ' V
Baro_Data_fb := (i2cRead(0)) ' V
Baro_Data_fc := (i2cRead(0)) ' V
Baro_Data_fd := (i2cRead(0)) ' V
Baro_Data_fe := (i2cRead(0)) ' V
Baro_Data_ff := (i2cRead(1)) ' V
i2cStop
i2cStart
i2cWrite(Baro_Addr) 'write 0xEE to i2c bus sensor write address
i2cWrite($AA) 'write 0xF6 to i2c bus sensor starting register
i2cStart 'do a restart
i2cWrite(Baro_Addr|1) 'write 0xEF (read cmd) to i2c bus sensor read address
Baro_Data_AA := (i2cRead(0)) 'i2c read 12 BYTES with ack bit
Baro_Data_AB := (i2cRead(0)) ' V
Baro_Data_AC := (i2cRead(0)) ' V
Baro_Data_AD := (i2cRead(0)) ' V
Baro_Data_AE := (i2cRead(0)) ' V
Baro_Data_AF := (i2cRead(1)) ' V
i2cStop
i2cStart
i2cWrite(Baro_Addr) 'write 0xEE to i2c bus sensor write address
i2cWrite($B0) 'write 0xF6 to i2c bus sensor starting register
i2cStart 'do a restart
i2cWrite(Baro_Addr|1) 'write 0xEF (read cmd) to i2c bus sensor read address
Baro_Data_B0 := (i2cRead(0)) 'i2c read 12 BYTES with ack bit
Baro_Data_B1 := (i2cRead(0)) ' V
Baro_Data_B2 := (i2cRead(0)) ' V
Baro_Data_B3 := (i2cRead(0)) ' V
Baro_Data_B4 := (i2cRead(0)) ' V
Baro_Data_B5 := (i2cRead(0)) ' V
Baro_Data_B6 := (i2cRead(0)) ' V
Baro_Data_B7 := (i2cRead(0)) ' V
Baro_Data_B8 := (i2cRead(0)) ' V
Baro_Data_B9 := (i2cRead(1)) ' V
i2cStop
i2cStart
i2cWrite(Baro_Addr) 'write 0xEE to i2c bus sensor write address
i2cWrite($BA) 'write 0xF6 to i2c bus sensor starting register
i2cStart 'do a restart
i2cWrite(Baro_Addr|1) 'write 0xEF (read cmd) to i2c bus sensor read address
Baro_Data_BA := (i2cRead(0)) 'i2c read 12 BYTES with ack bit
Baro_Data_BB := (i2cRead(0)) ' V
Baro_Data_BC := (i2cRead(0)) ' V
Baro_Data_BD := (i2cRead(0)) ' V
Baro_Data_BE := (i2cRead(0)) ' V
Baro_Data_BF := (i2cRead(1)) ' V
i2cStop
PUB Baro_f6
return Baro_Data_f6
PUB Baro_f7
return Baro_Data_f7
PUB Baro_f8
return Baro_Data_f8
PUB Baro_f9
return Baro_Data_f9
PUB Baro_fa
return Baro_Data_fa
PUB Baro_fb
return Baro_Data_fb
PUB Baro_fc
return Baro_Data_fc
PUB Baro_fd
return Baro_Data_fd
PUB Baro_fe
return Baro_Data_fe
PUB Baro_ff
return Baro_Data_ff
PUB Baro_AA
return Baro_Data_AA
PUB Baro_AB
return Baro_Data_AB
PUB Baro_AC
return Baro_Data_AC
PUB Baro_AD
return Baro_Data_AD
PUB Baro_AE
return Baro_Data_AE
PUB Baro_AF
return Baro_Data_AF
PUB Baro_B0
return Baro_Data_B0
PUB Baro_B1
return Baro_Data_B1
PUB Baro_B2
return Baro_Data_B2
PUB Baro_B3
return Baro_Data_B3
PUB Baro_B4
return Baro_Data_B4
PUB Baro_B5
return Baro_Data_B5
PUB Baro_B6
return Baro_Data_B6
PUB Baro_B7
return Baro_Data_B7
PUB Baro_B8
return Baro_Data_B8
PUB Baro_B9
return Baro_Data_B9
PUB Baro_BA
return Baro_Data_BA
PUB Baro_BB
return Baro_Data_BB
PUB Baro_BC
return Baro_Data_BC
PUB Baro_BD
return Baro_Data_BD
PUB Baro_BE
return Baro_Data_BE
PUB Baro_BF
return Baro_Data_BF
' // I2C Control
Pri init_i2c(_i2cSDA, _i2cSCL)
i2cSDA := _i2cSDA 'referances passed from main file for pin numbers
i2cSCL := _i2cSCL
outa[i2cSDA] := 0 'as inputs to start
outa[i2cSCL] := 0
Pri readLocation(deviceAddress, deviceRegister) : i2cData | ackbit
' do a standard i2c address, then read
' read a device's register
ackbit := _i2cACK
i2cStart
ackbit := (ackbit << 1) | i2cWrite(deviceAddress)
ackbit := (ackbit << 1) | i2cWrite(deviceRegister)
i2cStart
ackbit := (ackbit << 1) | i2cWrite(deviceAddress | 1) ' repeat with read bit now set
i2cData := i2cRead(_i2cNAK)
i2cStop
' return the data
return i2cData
Pri writeLocation(deviceAddress, deviceRegister, i2cDataValue) : ackbit
' do a standard i2c address, then write
' return the ACK bit from the device address
ackbit := _i2cACK
i2cstart
ackbit := (ackbit << 1) | i2cWrite(deviceAddress)
ackbit := (ackbit << 1) | i2cWrite(deviceRegister)
ackbit := (ackbit << 1) | i2cWrite(i2cDataValue)
i2cStop
return ackbit
Pri i2cStop
' i2c stop sequence - the SDA goes LOW to HIGH while SCL is HIGH
dira[i2cSCL] ~
dira[i2cSDA] ~
Pri i2cStart
dira[i2cSDA] ~
dira[i2cSCL] ~
dira[i2cSDA] ~~
repeat until ina[i2cSCL] == 1
Pri i2cWrite(i2cData) : ackbit
i2cData <<=24
' init the clock line
dira[i2cSCL] := 1
repeat 8
' set the SDA while the SCL is LOW
dira[i2cSDA] := (!(i2cData <-= 1) & 1)
' toggle SCL HIGH
dira[i2cSCL] := 0
' toogle SCL LOW
dira[i2cSCL] := 1
' setup for ACK - pin to input'
dira[i2cSDA] := 0
' read in the ACK
dira[i2cSCL] := 0
ackbit := ina[i2cSDA]
dira[i2cSCL] := 1
' leave the SDA pin LOW
dira[i2cSDA] := 1
return ackbit
Pri i2cRead(ackbit): i2cData
' set the SCL to output and the SDA to input
dira[i2cSDA] := 0
dira[i2cSCL] := 1
' clock in the byte
i2cData := 0
repeat 8
dira[i2cSCL] := 0
i2cData := (i2cData << 1) | ina[i2cSDA]
dira[i2cSCL] := 1
' send the ACK or NAK
dira[i2cSDA] ~~
dira[i2cSCL] := 0
dira[i2cSDA] := !ackbit
dira[i2cSCL] := 1
' return the data
return i2cData
However, of these 2 codes, I should get the same resulting values, but I dont, as you can see below.



Comments
If you give it the wrong BMP Address say $A5 instead of $EE the result you will see is -1. The numbers only show up when i use $EE, which was discovered by i2cscan.
Here is my code that kinda works:
Con _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 CLK_FREQ = ((_clkmode-xtal1)>>6)*_xinfreq MS_001 = CLK_FREQ / 1_000 ' // Propeller Pinout Misc1 = 0 Misc2 = 1 Misc3 = 2 Misc4 = 3 MCPCLK = 4 MCPDOut = 5 MCPDIn = 5 MCPCS = 6 NC1 = 7 MPUsda = 8 ' All I2C Sensors on SAME Bus MPUscl = 9 RPitx = 10 RPirx = 11 GPSrx = 12 ' SCL GPStx = 13 ' SDA BMPSCL = 12 BMPSDA = 13 WiFitx = 14 ' White WiFirx = 15 ' Green Misc5 = 16 Misc6 = 17 Misc7 = 18 LED = 19 Piezo = 20 Servo6 = 21 ' Left Side Airlerons Servo5 = 22 ' Gyro Select Servo4 = 23 ' Gyro / Rudder NC2 = 24 Servo3 = 25 ' Motor Speed / Power Servo2 = 26 ' Elevator Servo1 = 27 ' Right Side Airlerons EEPROMscl = 28 EEPROMsda = 29 DEBUGSERtx = 30 DEBUGSERrx = 31 SCL = 12 alt_address = %1110_1110 ' // BMP-180 Settings bmpAddr = %1110_1110 bmpAddrR = %1110_1110 bmpAddrW = %1110_1111 OSS1 = 0 ' Ultra Low Power OSS2 = 1 ' Standard OSS3 = 2 ' High Resolution OSS4 = 3 ' Ultra High Resolution ' EEPROM data base address - i.e 32K (assumes a 64kb eeprom installed!!) EEPROM_Base = $8000 EEPROMAddr = %1010_0000 i2cSCL = 28 ' i2cSDA = 29 OBJ i2cObject : "basic_i2c_driver_1.3" Ser : "FullDuplexSerial" Var long ac1, ac2, ac3, ac4, ac5, ac6, b1, b2, mb, mc, md, id long UT, UP long T, P long i2cAddress, i2cSlaveCounter long oss Pub Start ser.start(31,30,0,115200) i2cObject.Initialize(bmpSCL) oss := OSS2 repeat if i2cObject.devicePresent(bmpSCL, alt_address) == True ser.str(string("Device Located!")) ser.tx(13) waitcnt(clkfreq + cnt) GetBMP else ser.str(string("Device Not Found")) ser.tx(13) waitcnt(clkfreq + cnt) Pub GetBMP | v1, v2, v3, up1, up2, up3, ut1, ut2 repeat { Table 5: Calibration Coefficients BMP180 reg adr Parameter MSB LSB AC1 0xAA 0xAB AC2 0xAC 0xAD AC3 0xAE 0xAF AC4 0xB0 0xB1 AC5 0xB2 0xB3 AC6 0xB4 0xB5 B1 0xB6 0xB7 B2 0xB8 0xB9 MB 0xBA 0xBB MC 0xBC 0xBD MD 0xBE 0xBF } ' i2cObject.readLocation(SCL,device_address, register) ' // Read Calibration Coefficients ac1 := i2cObject.readLocation(bmpSCL, bmpAddr, $AA) ' 1B ac2 := i2cObject.readLocation(bmpSCL, bmpAddr, $AC) ' FB ac3 := i2cObject.readLocation(bmpSCL, bmpAddr, $AE) ' C7 ac4 := i2cObject.readLocation(bmpSCL, bmpAddr, $B0) ' 84 ac5 := i2cObject.readLocation(bmpSCL, bmpAddr, $B2) ' 61 ac6 := i2cObject.readLocation(bmpSCL, bmpAddr, $B4) ' 49 b1 := i2cObject.readLocation(bmpSCL, bmpAddr, $B6) ' 19 b2 := i2cObject.readLocation(bmpSCL, bmpAddr, $B8) ' 00 mb := i2cObject.readLocation(bmpSCL, bmpAddr, $BA) ' 80 mc := i2cObject.readLocation(bmpSCL, bmpAddr, $BC) ' D1 md := i2cObject.readLocation(bmpSCL, bmpAddr, $BE) ' 0A id := i2cObject.readLocation(bmpSCL, bmpAddr, $D0) ' 55 *** Should = 0x55 waitcnt((clkfreq / 4) + cnt) ser.str(string("AC1: ")) ser.hex(ac1, 2) ser.str(string(" ")) ser.dec(ac1) ser.tx(13) ser.str(string("AC2: ")) ser.hex(ac2, 2) ser.str(string(" ")) ser.dec(ac2) ser.tx(13) ser.str(string("AC3: ")) ser.hex(ac3, 2) ser.str(string(" ")) ser.dec(ac3) ser.tx(13) ser.str(string("AC4: ")) ser.hex(ac4, 2) ser.str(string(" ")) ser.dec(ac4) ser.tx(13) ser.str(string("AC5: ")) ser.hex(ac5, 2) ser.str(string(" ")) ser.dec(ac5) ser.tx(13) ser.str(string("AC6: ")) ser.hex(ac6, 2) ser.str(string(" ")) ser.dec(ac6) ser.tx(13) ser.str(string("B1: ")) ser.hex(b1, 2) ser.str(string(" ")) ser.dec(b1) ser.tx(13) ser.str(string("B2: ")) ser.hex(b2, 2) ser.str(string(" ")) ser.dec(b2) ser.tx(13) ser.str(string("MB: ")) ser.hex(mb, 2) ser.str(string(" ")) ser.dec(mb) ser.tx(13) ser.str(string("MC: ")) ser.hex(mc, 2) ser.str(string(" ")) ser.dec(mc) ser.tx(13) ser.str(string("MD: ")) ser.hex(md, 2) ser.str(string(" ")) ser.dec(md) ser.tx(13) ser.str(string("ID: ")) ser.hex(id, 2) ser.str(string(" ")) ser.dec(id) ser.tx(13) 'ser.str(string("bmpAddr: ")) 'ser.hex(bmpAddr | 1, 2) ' 0 = EE, 1 = EF 'ser.tx(13) ' // Read Uncompressed Temperature Value ' Write 0x2E into reg 0xF4, wait 4.5ms ' Read reg 0xF6 (MSB), 0xF7 (LSB) i2cObject.writeLocation(bmpSCL, bmpAddrW, $F4, $2E) ' Temperature 0x2E 4.5 waitcnt((clkfreq / 222) + cnt) ' 4.5ms ut1 := i2cObject.readLocation(bmpSCL, bmpAddr, i2cObject#OneAddr|$F6) ut2 := i2cObject.readLocation(bmpSCL, bmpAddr, i2cObject#OneAddr|$F7) 'UT := i2cObject.readLocation16(bmpSCL, bmpAddr, i2cObject#OneAddr|$F6) ser.str(string("UT: ")) ser.hex(ut1, 2) ser.str(string(" ")) ser.hex(ut2, 2) ser.str(string(" ")) ser.dec(ut1 + ut2) ser.tx(13) ' // Read Uncompressed Pressure Value ' Write 0x34+(oss<<6) into reg 0xF4, wait #.#ms ' Read reg 0xF6 (MSB), 0xF7 (LSB), 0xF8 (XLSB) 'i2cObject.writeLocation(bmpSCL, bmpAddr, $F4, $34 + (oss<<6)) ' i2cObject.readLocation(SCL,device_address, register) ' i2cObject.writeLocation(SCL,device_address, register, value) if oss == 0 i2cObject.writeLocation(bmpSCL, bmpAddrW, $F4, $34) ' Pressure (oss = 0) 0x34 4.5 waitcnt((clkfreq / 222) + cnt) ' 4.5ms elseif oss == 1 i2cObject.writeLocation(bmpSCL, bmpAddrW, $F4, $74) ' Pressure (oss = 1) 0x74 7.5 waitcnt((clkfreq / 133) + cnt) ' 7.5ms elseif oss == 2 i2cObject.writeLocation(bmpSCL, bmpAddrW, $F4, $B4) ' Pressure (oss = 2) 0xB4 13.5 waitcnt((clkfreq / 74) + cnt) ' 13.5ms elseif oss == 3 i2cObject.writeLocation(bmpSCL, bmpAddrW, $F4, $F4) ' Pressure (oss = 3) 0xF4 25.5 waitcnt((clkfreq / 39) + cnt) ' 25.5ms up1 := i2cObject.readLocation(bmpSCL, bmpAddr, $F6) up2 := i2cObject.readLocation(bmpSCL, bmpAddr, $F7) up3 := i2cObject.readLocation(bmpSCL, bmpAddr, $F8) ser.str(string("UP: ")) ser.hex(up1 + up2 + up3, 6) ser.str(string(" ")) ser.dec(up1 + up2 + up3) ser.tx(13) ser.str(string("UP 123 Hex: ")) ser.hex(up1, 2) ser.str(string(" ")) ser.hex(up2, 2) ser.str(string(" ")) ser.hex(up3, 2) ser.tx(13) ser.str(string("UP 123 Dec: ")) ser.dec(up1) ser.str(string(" ")) ser.dec(up2) ser.str(string(" ")) ser.dec(up3) ser.tx(13) ' // Calculate True Temperature ' // Calculate True Pressure waitcnt(clkfreq + cnt)'' Basic I2C Routines Version 1.3 '' Written by Michael Green and copyright (c) 2009 '' Permission is given to use this in any program for the Parallax '' Propeller processor as long as this copyright notice is included. '' Version: 1.0 - Initial version '' 1.1 - Corrected some comments '' 1.2 - Corrected example, added this list '' 1.3 - Added logic for non-memory devices '' This is a minimal version of an I2C driver in SPIN. It assumes '' that the SDA pin is one higher than the SCL pin. It assumes that '' neither the SDA nor the SCL pins have pullups, so drives both. '' These routines are primarily intended for reading and writing EEPROMs. '' The low level I2C are provided for use with other devices, but the '' read/write byte routines assume a standard I2C serial EEPROM with a '' 16 bit device address register, paged writes, and acknowledge polling. '' All of these read/write routines accept an EEPROM address up to 19 '' bits (512K) even though the EEPROM addressing scheme normally allows '' for only 16 bits of addressing. The upper 3 bits are used as part of '' the device select code and these routines will take the upper 3 bits '' of the address and "or" it with the supplied device select code bits '' 3-1 which are used to select a particular EEPROM on an I2C bus. There '' are two schemes for selecting 64K "banks" in 128Kx8 EEPROMs. Atmel's '' 24LC1024 EEPROMs allow simple linear addressing up to 256Kx8 ($00000 '' to $3FFFF). Microchip's 24LC1025 allows for up to 512Kx8, but in two '' areas: $00000 to $3FFFF and $40000 to $7FFFF. Each EEPROM provides '' a 64K "bank" in each area. See the device datasheets for details. '' If bit 21 of the address value is non-zero, then bit 20 indicates how '' many address bytes are to be sent to the device. If bit 20 is zero, '' no address is sent. If bit 20 is a one, then a single address byte '' is sent. '' This will work with the boot EEPROM and does not require a pull-up '' resistor on the SCL line (but does on the SDA line ... about 4.7K to '' +3.3V). According to the Philips I2C specification, both pull-ups '' are required. Many devices will tolerate the absence of a pull-up '' on SCL. Some may tolerate the absence of a pull-up on SDA as well. '' Initialize may have to be called once at the beginning of your '' program. Sometimes an I2C device is left in an invalid state. This '' will reset the device to a known state so it will respond to the I2C '' start transition (sent out by the i2cStart routine). '' To read from or write to an EEPROM on pins 28/29 like the boot EEPROM: '' CON '' eepromAddress = $7000 '' VAR '' byte buffer[32] '' OBJ '' i2c : "Basic_I2C_Driver" '' PRI readIt '' if i2c.ReadPage(i2c#BootPin, i2c#EEPROM, eepromAddress, @buffer, 32) '' abort ' an error occurred during the read '' PRI writeIt | startTime '' if i2c.WritePage(i2c#BootPin, i2c#EEPROM, eepromAddress, @buffer, 32) '' abort ' an error occured during the write '' startTime := cnt ' prepare to check for a timeout '' repeat while i2c.WriteWait(i2c#BootPin, i2c#EEPROM, eepromAddress) '' if cnt - startTime > clkfreq / 10 '' abort ' waited more than a 1/10 second for the write to finish '' Note that the read and write use something called paged reads/writes. '' This means that any read using ReadPage must fit entirely in one '' EEPROM if you have several attached to one set of pins. For writes, '' any write using i2cWritePage must fit entirely within a page of the '' EEPROM. Usually these pages are either 32, 64, 128 or 256 bytes in '' size depending on the manufacturer and device type. 32 bytes is a '' good limit for the number of bytes to be written at a time if you '' don't know the specific page size (and the write must fit completely '' within a multiple of the page size). The WriteWait waits for the '' write operation to complete. Alternatively, you could wait for 5ms '' since currently produced EEPROMs will finish within that time. '' To read from an I2C device that uses a single register address byte, '' you could use any of these methods and supply a device address as '' follows: '' i2c.ReadByte( <SCL pin #>, <device code>, <register> | i2c#OneAddr) '' Similarly, to write to a device that doesn't use an address byte, '' you'd use: '' i2c.WriteByte( <SCL pin #>, <device code>, i2c#NoAddr) CON ACK = 0 ' I2C Acknowledge NAK = 1 ' I2C No Acknowledge Xmit = 0 ' I2C Direction Transmit Recv = 1 ' I2C Direction Receive BootPin = 28 ' I2C Boot EEPROM SCL Pin EEPROM = $A0 ' I2C EEPROM Device Address NoAddr = $200000 ' I2C Don't use register address OneAddr = $300000 ' I2C Use 8-bit register address PUB Initialize(SCL) | SDA ' An I2C device may be left in an SDA := SCL + 1 ' invalid state and may need to be outa[SCL] := 1 ' reinitialized. Drive SCL high. dira[SCL] := 1 dira[SDA] := 0 ' Set SDA as input repeat 9 outa[SCL] := 0 ' Put out up to 9 clock pulses outa[SCL] := 1 if ina[SDA] ' Repeat if SDA not driven high quit ' by the EEPROM PUB Start(SCL) | SDA ' SDA goes HIGH to LOW with SCL HIGH SDA := SCL + 1 outa[SCL]~~ ' Initially drive SCL HIGH dira[SCL]~~ outa[SDA]~~ ' Initially drive SDA HIGH dira[SDA]~~ outa[SDA]~ ' Now drive SDA LOW outa[SCL]~ ' Leave SCL LOW PUB Stop(SCL) | SDA ' SDA goes LOW to HIGH with SCL High SDA := SCL + 1 outa[SCL]~~ ' Drive SCL HIGH outa[SDA]~~ ' then SDA HIGH dira[SCL]~ ' Now let them float dira[SDA]~ ' If pullups present, they'll stay HIGH PUB Write(SCL, data) : ackbit | SDA '' Write i2c data. Data byte is output MSB first, SDA data line is valid '' only while the SCL line is HIGH. Data is always 8 bits (+ ACK/NAK). '' SDA is assumed LOW and SCL and SDA are both left in the LOW state. SDA := SCL + 1 ackbit := 0 data <<= 24 repeat 8 ' Output data to SDA outa[SDA] := (data <-= 1) & 1 outa[SCL]~~ ' Toggle SCL from LOW to HIGH to LOW outa[SCL]~ dira[SDA]~ ' Set SDA to input for ACK/NAK outa[SCL]~~ ackbit := ina[SDA] ' Sample SDA when SCL is HIGH outa[SCL]~ outa[SDA]~ ' Leave SDA driven LOW dira[SDA]~~ PUB Read(SCL, ackbit): data | SDA '' Read in i2c data, Data byte is output MSB first, SDA data line is '' valid only while the SCL line is HIGH. SCL and SDA left in LOW state. SDA := SCL + 1 data := 0 dira[SDA]~ ' Make SDA an input repeat 8 ' Receive data from SDA outa[SCL]~~ ' Sample SDA when SCL is HIGH data := (data << 1) | ina[SDA] outa[SCL]~ outa[SDA] := ackbit ' Output ACK/NAK to SDA dira[SDA]~~ outa[SCL]~~ ' Toggle SCL from LOW to HIGH to LOW outa[SCL]~ outa[SDA]~ ' Leave SDA driven LOW PUB ReadPage(SCL, devSel, addrReg, dataPtr, count) : ackbit '' Read in a block of i2c data. Device select code is devSel. Device starting '' address is addrReg. Data address is at dataPtr. Number of bytes is count. '' The device select code is modified using the upper 3 bits of the 19 bit addrReg. '' Return zero if no errors or the acknowledge bits if an error occurred. devSel |= addrReg >> 15 & %1110 if addrReg & $300000 <> $200000 ' One or two byte address or memory? Start(SCL) ' Select the device & send address ackbit := Write(SCL, devSel | Xmit) if addrReg & $300000 == $000000 ' Two byte address or memory device? ackbit := (ackbit << 1) | Write(SCL, addrReg >> 8 & $FF) ackbit := (ackbit << 1) | Write(SCL, addrReg & $FF) Start(SCL) ' Reselect the device for reading ackbit := (ackbit << 1) | Write(SCL, devSel | Recv) repeat count - 1 byte[dataPtr++] := Read(SCL, ACK) byte[dataPtr++] := Read(SCL, NAK) Stop(SCL) return ackbit PUB ReadByte(SCL, devSel, addrReg) : data '' Read in a single byte of i2c data. Device select code is devSel. Device '' starting address is addrReg. The device select code is modified using the '' upper 3 bits of the 19 bit addrReg. This returns true if an error occurred. if ReadPage(SCL, devSel, addrReg, @data, 1) return -1 PUB ReadWord(SCL, devSel, addrReg) : data '' Read in a single word of i2c data. Device select code is devSel. Device '' starting address is addrReg. The device select code is modified using the '' upper 3 bits of the 19 bit addrReg. This returns true if an error occurred. if ReadPage(SCL, devSel, addrReg, @data, 2) return -1 PUB ReadLong(SCL, devSel, addrReg) : data '' Read in a single long of i2c data. Device select code is devSel. Device '' starting address is addrReg. The device select code is modified using the '' upper 3 bits of the 19 bit addrReg. This returns true if an error occurred. '' Note that you can't distinguish between a return value of -1 and true error. if ReadPage(SCL, devSel, addrReg, @data, 4) return -1 PUB WritePage(SCL, devSel, addrReg, dataPtr, count) : ackbit '' Write out a block of i2c data. Device select code is devSel. Device starting '' address is addrReg. Data address is at dataPtr. Number of bytes is count. '' The device select code is modified using the upper 3 bits of the 19 bit addrReg. '' Most devices have a page size of at least 32 bytes, some as large as 256 bytes. '' Return zero if no errors or the acknowledge bits if an error occurred. If '' more than 31 bytes are transmitted, the sign bit is "sticky" and is the '' logical "or" of the acknowledge bits of any bytes past the 31st. devSel |= addrReg >> 15 & %1110 Start(SCL) ' Select the device & send address ackbit := Write(SCL, devSel | Xmit) if addrReg & $300000 <> $200000 ' One or two byte address or memory? if addrReg & $300000 == $000000 ' Two byte address or memory device? ackbit := (ackbit << 1) | Write(SCL, addrReg >> 8 & $FF) ackbit := (ackbit << 1) | Write(SCL, addrReg & $FF) repeat count ' Now send the data ackbit := ackbit << 1 | ackbit & $80000000 ' "Sticky" sign bit ackbit |= Write(SCL, byte[dataPtr++]) Stop(SCL) return ackbit PUB WriteByte(SCL, devSel, addrReg, data) '' Write out a single byte of i2c data. Device select code is devSel. Device '' starting address is addrReg. The device select code is modified using the '' upper 3 bits of the 19 bit addrReg. This returns true if an error occurred. if WritePage(SCL, devSel, addrReg, @data, 1) return true return false PUB WriteWord(SCL, devSel, addrReg, data) '' Write out a single word of i2c data. Device select code is devSel. Device '' starting address is addrReg. The device select code is modified using the '' upper 3 bits of the 19 bit addrReg. This returns true if an error occurred. '' Note that the word value may not span an EEPROM page boundary. if WritePage(SCL, devSel, addrReg, @data, 2) return true return false PUB WriteLong(SCL, devSel, addrReg, data) '' Write out a single long of i2c data. Device select code is devSel. Device '' starting address is addrReg. The device select code is modified using the '' upper 3 bits of the 19 bit addrReg. This returns true if an error occurred. '' Note that the long word value may not span an EEPROM page boundary. if WritePage(SCL, devSel, addrReg, @data, 4) return true return false PUB WriteWait(SCL, devSel, addrReg) : ackbit '' Wait for a previous write to complete. Device select code is devSel. Device '' starting address is addrReg. The device will not respond if it is busy. '' The device select code is modified using the upper 3 bits of the 18 bit addrReg. '' This returns zero if no error occurred or one if the device didn't respond. devSel |= addrReg >> 15 & %1110 Start(SCL) ackbit := Write(SCL, devSel | Xmit) Stop(SCL) return ackbit ' ******************* Extra's ******************* PUB ReStart(SCL) | SDA ' SDA goes HIGH to LOW with SCL HIGH SDA := SCL + 1 outa[SDA]~~ ' Initially drive SDA HIGH dira[SDA]~~ outa[SCL]~~ ' Initially drive SCL HIGH 'waitcnt(clkfreq / I2CDelay + cnt) outa[SDA]~ ' Now drive SDA LOW 'waitcnt(clkfreq / I2CDelay + cnt) outa[SCL]~ ' Leave SCL LOW PUB devicePresent(SCL,deviceAddress) : ackbit ' send the deviceAddress and listen for the ACK Start(SCL) ackbit := Write(SCL,deviceAddress | 0) Stop(SCL) if ackbit == ACK return true else return false PUB readLocation(SCL,device_address, register) : value start(SCL) write(SCL,device_address | 0) write(SCL,register) start(SCL) write(SCL,device_address | 1) value := read(SCL,NAK) stop(SCL) return value PUB writeLocation(SCL,device_address, register, value) start(SCL) write(SCL,device_address) write(SCL,register) write(SCL,value) stop (SCL) PUB readLocation16(SCL,device_address, register) : value start(SCL) write(SCL,device_address | 0) write(SCL,register) restart(SCL) write(SCL,device_address | 1) value := read(SCL,ACK) value <<= 8 value |= (read(SCL,NAK) & $ff) stop(SCL) return value PUB readLocation24(SCL,device_address, register) : value start(SCL) write(SCL,device_address | 0) write(SCL,register) restart(SCL) write(SCL,device_address | 1) value := read(SCL,ACK) value <<= 8 value |= (read(SCL,ACK) & $ff) value <<= 8 value |= (read(SCL,NAK) & $ff) stop(SCL) return valuein the same code I am testing my other sensor (mpu-9150) but with the mpu6050's driver (only way i can get it to work).
I have ran this with both of them plugged in, and just one with the same results for the bmp.
BMP i2c Test.zip