BMP085 i2c Problems...
I keep reading other peoples issues with the bmp085 and it seems the problem is, same one im having, that none of the i2c drivers just "work" as is. Everyone ends up needing a customized version of the bmp085 object or basic_i2c_driver. Read about something that works, go to try it, oops your file dont have "ALL" the code it is suppose to. ### Function dont exist. " I2C#OneAddr| " dont exist. Can we get a COMPLETE file Please?!?!?!
Cant find "Minimal_I2C_Driver" on OBEX (But referenced to by Basic_i2c_Driver.spin)
I have tried swapping out the sensor, i have 3 of them. Chances they ALL came Broken???
I have tried every combination i can think of with the BAROMETRO.spin, BMP085Object.spin & Basic_i2c_Driver.spin. I have even tried other i2c drivers.
i have a 10k on SCL & SDA to +3.3v.
ALL Data out is "0" or none at all.
With an O-scope i can see Data on SDA, but SCL is all mixed up kinda like a video signal with 3 states (AC) +3.3v(ON), 1.65v(Half ON), 0v(OFF) instead of two (DC) +3.3v(ON) or 0v(OFF).
Should i remove the SCL pull-up resistor to remove the possibility of the pin "Floating" at 1.65v?
To top it off this is the First time using i2c. I can access my prop eeprom as a "test", but no love on ANY other i2c sensors. I have some MLX90615's that are i2c and wont work as well (tried 7 of them; none work).
I would prefer not to scrap this project, as others have gotten the bmp085 to work. However, soon with the MPU-9050 being i2c as well if i cant get something working i might just have to.
I wrote my own SPI Protocol for my Magnetometer, it works well. Just cant get i2c to work. Or im being sent bunk parts from multiple dealers (x3).
Some Example Code (Not Working & Had to modify nearly everything to match my setup):
BAROMETRO.spin:
BMP085Object.spin:
Basic_i2c_Driver_E.spin:
Cant find "Minimal_I2C_Driver" on OBEX (But referenced to by Basic_i2c_Driver.spin)
I have tried swapping out the sensor, i have 3 of them. Chances they ALL came Broken???
I have tried every combination i can think of with the BAROMETRO.spin, BMP085Object.spin & Basic_i2c_Driver.spin. I have even tried other i2c drivers.
i have a 10k on SCL & SDA to +3.3v.
ALL Data out is "0" or none at all.
With an O-scope i can see Data on SDA, but SCL is all mixed up kinda like a video signal with 3 states (AC) +3.3v(ON), 1.65v(Half ON), 0v(OFF) instead of two (DC) +3.3v(ON) or 0v(OFF).
Should i remove the SCL pull-up resistor to remove the possibility of the pin "Floating" at 1.65v?
To top it off this is the First time using i2c. I can access my prop eeprom as a "test", but no love on ANY other i2c sensors. I have some MLX90615's that are i2c and wont work as well (tried 7 of them; none work).
I would prefer not to scrap this project, as others have gotten the bmp085 to work. However, soon with the MPU-9050 being i2c as well if i cant get something working i might just have to.
I wrote my own SPI Protocol for my Magnetometer, it works well. Just cant get i2c to work. Or im being sent bunk parts from multiple dealers (x3).
Some Example Code (Not Working & Had to modify nearly everything to match my setup):
BAROMETRO.spin:
CON
_clkmode = xtal1 + pll16x ' System clock → 80 MHz
_xinfreq = 5_000_000
CR = 13
BMPscl = 9 ' Currently on 8, 9 Bus
BMPsda = 8
'#define BMP085_ADDRESS 0x77 // I2C address of BMP085
{{
The BMP085 module address is shown below. The LSB
of the device address distinguishesbetween
read (1) and write (0) operation, correspon
ding to address 0xEF (read) and 0xEE (write).
A7 A6 A5 A4 A3 A2 A1 W/R
1 1 1 0 1 1 1 0/1
}}
'BMPAddress = 11_0111 ' 0x77 = 110111
'BMPAddress = 10_1110 ' BMP - Write
BMPAddress = 10_1111 ' BMP - Read
' P8 = SDA
' P9 = SCL
VAR
word t,p,t2,p2
OBJ
Baro : "bmp085Object"
Debug : "FullDuplexSerialPlus"
PUB Init
'Debug.Start(31, 30, 0, 115200)
waitcnt(clkfreq * 2 + cnt)
'Baro.init(BMPscl, BMPsda, 1)
Baro.init(BMPscl, BMPsda, BMPAddress)
repeat
baro.GetPressureTemp(BMPscl,1,1,t,p)
baro.GetPressureTemp(BMPscl, BMPAddress,1,t2,p2)
debug.tx(0)
' Display Result
Debug.Str(String(CR, "T = "))
Debug.Dec(t)
Debug.Str(String(CR, "P = "))
Debug.Dec(P)
baro.GetPressureTemp(BMPscl, BMPAddress,0,t2,p2)
DEBUG.tx(13)
' Display Result
Debug.Str(String(CR, "T = "))
Debug.Dec(t2)
Debug.Str(String(CR, "P = "))
Debug.Dec(P2)
waitcnt(clkfreq*1000 + cnt)
BMP085Object.spin:
{{
┌──────────────────────────────────────────┐
│ BMP085 Driver 1.0 │
│ Author: Tim Moore │
│ Copyright (c) May 2010 Tim Moore │
│ See end of file for terms of use. │
└──────────────────────────────────────────┘
I2C addresses is 10_1110
breakout board availble (http://www.sparkfun.com/commerce/product_info.php?products_id=9694)
Note: GetPressureTemp and GetPressureTempA are only usable from a single Cog. Calling from multiple Cogs will confuse the state machine
}}
Con
_clkmode = xtal1 + pll16x ' System clock → 80 MHz
_xinfreq = 5_000_000
'BMPscl = 9 ' Currently on 8, 9 Bus
'BMPsda = 8
OBJ
i2cObject : "basic_i2c_driver_E" '0 Cog
umath : "umath" '0 Cog
ser : "FullDuplexSerialPlus"
VAR
long ac1, ac2, ac3, ac4, ac5, ac6, b1, b2, mb, mc, md 'see the datasheet for what these mean
long state, time, temput
long delays[4]
DAT
shifts long 50000, 50000>>1, 50000>>2, 50000>>3
PUB Init(i2cSCL, i2cSDA, _deviceAddress)
''initializes BMP085
''reads in sensor coefficients etc. from eeprom
i2cObject.Initialize(i2cSCL, i2cSDA)
state := 0
delays[0] := clkfreq/222 '4.5ms
delays[1] := clkfreq/133 '7.5ms
delays[2] := clkfreq/74 '13.5ms
delays[3] := clkfreq/39 '25.5ms
result := true
'read all the coefficient and sensor values from eeprom
ac1 := i2cObject.readLocation16(i2cSCL, _deviceAddress, $AA)
ac2 := i2cObject.readLocation16(i2cSCL, _deviceAddress, $AC)
ac3 := i2cObject.readLocation16(i2cSCL, _deviceAddress, $AE)
ac4 := i2cObject.readLocation16(i2cSCL, _deviceAddress, $B0)
ac5 := i2cObject.readLocation16(i2cSCL, _deviceAddress, $B2)
ac6 := i2cObject.readLocation16(i2cSCL, _deviceAddress, $B4)
b1 := i2cObject.readLocation16(i2cSCL, _deviceAddress, $B6)
b2 := i2cObject.readLocation16(i2cSCL, _deviceAddress, $B8)
mb := i2cObject.readLocation16(i2cSCL, _deviceAddress, $BA)
mc := i2cObject.readLocation16(i2cSCL, _deviceAddress, $BC)
md := i2cObject.readLocation16(i2cSCL, _deviceAddress, $BE)
if ac1 == 0 OR ac2 == 0 OR ac3 == 0 OR ac4 == 0 OR ac5 == 0 OR ac6 == 0 OR b1 == 0 OR b2 == 0 OR mb == 0 OR mc == 0 OR md == 0
result := false
elseif ac1 == $ffff OR ac2 == $ffff OR ac3 == $ffff OR ac4 == $ffff OR ac5 == $ffff OR ac6 == $ffff OR b1 == $ffff OR {
} b2 == $ffff OR mb == $ffff OR mc == $ffff OR md == $ffff
result := false
~~ac1 'sign extend correctly, note ac4, ac5, ac6 are not sign extended
~~ac2
~~ac3
~~b1
~~b2
~~mb
~~mc
~~md
PUB GetPressureTemp(i2cSCL, _deviceAddress, mode, TempPtr, PressurePtr)
' Temp in 0.1°C
' Pressure in Pa
'
repeat until result == true
if (result := GetPressureTempA(i2cSCL, _deviceAddress, mode, TempPtr, PressurePtr)) == false
waitcnt(delays[mode&3] + cnt) '4.5ms/7.5/13.5/25.5
PUB GetPressureTempA(i2cSCL, _deviceAddress, mode, TempPtr, PressurePtr) | up
' mode is oversampling setting
' 0 - 1 sample every 4.5ms
' 1 - 2 samples every 7.5ms
' 2 - 4 samples every 13.5ms
' 3 - 8 samples every 25.5ms
' Temp in 0.1°C
' Pressure in Pa
'
mode &= 3 'make sure 0-3
case state
0:
i2cObject.WriteLocation(i2cSCL, _deviceAddress, $f4, $2e) 'request for temp
time := cnt
state++
1:
if (cnt-time) > delays[0] '4.5ms
temput := i2cObject.readLocation16(i2cSCL, _deviceAddress, $F6)
i2cObject.WriteLocation(i2cSCL, _deviceAddress, $f4, $34|(mode<<6)) 'request for pressure
time := cnt
state++
2:
if (cnt-time) > delays[mode] '4.5ms/7.5/13.5/25.5
up := i2cObject.readLocation24(i2cSCL, _deviceAddress, $F6)
up >>= (8 - mode)
state := 0
Convert(temput, up, mode, TempPtr, PressurePtr)
result := true
PRI Convert(ut, up, mode, TempPtr, PressurePtr) | x1, x2, b5, b6, x3, b3, p, b4, th
''
x1 := ((ut - ac6) * ac5) ~> 15
x2 := (mc << 11) / (x1 + md)
b5 := x1 + x2
long[TempPtr] := (b5 + 8) ~> 4
b6 := b5 - 4000
x1 := (b2 * ((b6 * b6) ~> 12)) ~> 11
x2 := (ac2 * b6) ~> 11
x3 := x1 + x2
b3 := ((((ac1 << 2) + x3) << mode) + 2) ~> 2
x1 := (ac3 * b6) ~> 13
x2 := (b1 * ((b6 * b6) ~> 12)) ~> 16
x3 := ((x1 + x2) + 2) ~> 2
'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 & $80000000
' p := (b7 / b4) << 1
'else
' p := (b7 * 2) / b4
p := umath.multdiv((up - b3), (100000 >> mode), b4)
th := p ~> 8
x1 := th * th
x1 := (x1 * 3038) ~> 16
x2 := (-7357 * p) ~> 16
long[PressurePtr] := p + ((x1 + x2 + 3791) ~> 4)
{{
┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ TERMS OF USE: MIT License │
├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation │
│files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, │
│modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software│
│is furnished to do so, subject to the following conditions: │
│ │
│The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.│
│ │
│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE │
│WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR │
│COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │
│ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
}}
Basic_i2c_Driver_E.spin:
'' Basic I2C Routines Version 1.1
'' Written by Michael Green and copyright (?) 2007
''
'' Modified by James Burrows
''
'' Modified Tim Moore Jul/Aug 08
'' Slow down to handle 100Khz devices
'' Add readlocation16, writeValue, readValue16
'' Added slave clock stretching to read/write
'' Changed call to start when reading register to restart - different order of SDA/SCL for taking them high
''
'' Permission is given to use this in any program for the Parallax
'' Propeller processor as long as this copyright notice is included.
'' 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.
'' 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 : "Minimal_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.
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
I2CDelay = 100_000 'delay to lower speed to 100KHz
I2CDelayS = 10_000 'clock stretch delay
Var
long SDA
PUB Initialize(SCL, mSDA) ' An I2C device may be left in an
SDA := mSDA ' 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
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
dira[SCL]~ ' Now let them float
dira[SDA]~ ' If pullups present, they'll stay HIGH
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]~~
'waitcnt(clkfreq / I2CDelay + cnt)
outa[SDA]~ ' Now drive SDA LOW
'waitcnt(clkfreq / I2CDelay + cnt)
outa[SCL]~ ' Leave SCL LOW
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 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
'waitcnt(clkfreq / I2CDelay + cnt)
dira[SDA]~ ' If pullups present, they'll stay HIGH
PUB WriteNS(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.
'' Doesn't do clock stretching so would work without pull-up on SCL
'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]~
dira[SCL]~~
outa[SDA]~ ' Leave SDA driven LOW
dira[SDA]~~
PUB ReadNS(SCL, ackbit): data | b', 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.
'' Doesn't do clock stretching so would work without pull-up on SCL
'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
b := ina[SDA]
outa[SCL]~
data := (data << 1) | b
outa[SDA] := ackbit ' Output ACK/NAK to SDA
dira[SDA]~~
dira[SCL]~ ' Toggle SCL from LOW to HIGH to LOW
dira[SCL]~~
outa[SDA]~ ' Leave SDA driven LOW
PUB Write(SCL, data) : ackbit | wait', 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.
'' Requires pull-up on SCL
'
'SDA := SCL + 1
ackbit := 0
data <<= 24
repeat 8 ' Output data to SDA
outa[SDA] := (data <-= 1) & 1
'waitcnt(500 + cnt)
dira[SCL]~ ' Toggle SCL from LOW to HIGH to LOW
'waitcnt(500 + cnt)
'wait := cnt
'repeat while 0 == ina[SCL]
' if (cnt-wait) > clkfreq/I2CDelayS
' quit
dira[SCL]~~
'waitcnt(500 + cnt)
dira[SDA]~ ' Set SDA to input for ACK/NAK
'waitcnt(500 + cnt)
dira[SCL]~
'waitcnt(500 + cnt)
wait := cnt
repeat while 0 == ina[SCL]
if (cnt-wait) > clkfreq/I2CDelayS
quit
ackbit := ina[SDA] ' Sample SDA when SCL is HIGH
dira[SCL]~~
'waitcnt(500 + cnt)
outa[SDA]~ ' Leave SDA driven LOW
'waitcnt(500 + cnt)
dira[SDA]~~
PUB Read(SCL, ackbit):data | wait', 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.
'' Requires pull-up on SCL
'
'SDA := SCL + 1
data := 0
dira[SDA]~ ' Make SDA an input
repeat 8 ' Receive data from SDA
'waitcnt(500 + cnt)
dira[SCL]~ ' Sample SDA when SCL is HIGH
'waitcnt(500 + cnt)
wait := cnt
repeat while 0 == ina[SCL]
if (cnt-wait) > clkfreq/I2CDelayS
quit
data := (data << 1) | ina[SDA]
'waitcnt(500 + cnt)
dira[SCL]~~
'waitcnt(500 + cnt)
outa[SDA] := ackbit ' Output ACK/NAK to SDA
'waitcnt(500 + cnt)
dira[SDA]~~
'waitcnt(500 + cnt)
dira[SCL]~ ' Toggle SCL from LOW to HIGH to LOW
'waitcnt(500 + cnt)
wait := cnt
repeat while 0 == ina[SCL]
if (cnt-wait) > clkfreq/I2CDelayS
quit
dira[SCL]~~
'waitcnt(500 + cnt)
outa[SDA]~ ' Leave SDA driven LOW
PUB ReadChar(SCL): data | ackbit', 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
waitcnt(clkfreq / I2CDelay + cnt)
outa[SCL]~~ ' Sample SDA when SCL is HIGH
waitcnt(clkfreq / I2CDelay + cnt)
data := (data << 1) | ina[SDA]
outa[SCL]~
if data == 0
ackbit := NAK
else
ackbit := ACK
outa[SDA] := ackbit ' Output ACK/NAK to SDA
dira[SDA]~~
outa[SCL]~~ ' Toggle SCL from LOW to HIGH to LOW
waitcnt(clkfreq / I2CDelay + cnt)
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 & 10
Start(SCL) ' Select the device & send address
ackbit := Write(SCL, devSel | Xmit)
ackbit := (ackbit << 1) | Write(SCL, addrReg >> 8 & $FF)
ackbit := (ackbit << 1) | Write(SCL, addrReg & $FF)
reStart(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 & 10
Start(SCL) ' Select the device & send address
ackbit := Write(SCL, devSel | Xmit)
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
' james edit - wait for 5ms for page write to complete (80_000 * 5 = 400_000)
waitcnt(400_000 + cnt)
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
' james edit - wait for 5ms for page write to complete (80_000 * 5 = 400_000)
waitcnt(400_000 + cnt)
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
' james edit - wait for 5ms for page write to complete (80_000 * 5 = 400_000)
waitcnt(400_000 + cnt)
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 & 10
Start(SCL)
ackbit := Write(SCL, devSel | Xmit)
Stop(SCL)
return ackbit
' *************** JAMES'S Extra BITS *********************
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 writeLocation(SCL,device_address, register, value)
start(SCL)
write(SCL,device_address)
write(SCL,register)
write(SCL,value)
stop (SCL)
PUB readLocation(SCL,device_address, register) : value
start(SCL)
write(SCL,device_address | 0)
write(SCL,register)
restart(SCL) 'note change to restart from start, SCP1000 doesnt work without this change and so far works with other devices
write(SCL,device_address | 1)
value := read(SCL,NAK)
stop(SCL)
return value
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 value
PUB writeValue(SCL,device_address, value)
start(SCL)
write(SCL,device_address)
result := write(SCL,value)
stop (SCL)
PUB readValue16(SCL,device_address) : value
start(SCL)
write(SCL,device_address | 1)
value := read(SCL,ACK)
value <<= 8
value |= (read(SCL,NAK) & $ff)
stop(SCL)
return value
PUB readValue8(SCL,device_address) : value
start(SCL)
write(SCL,device_address | 1)
value := read(SCL,NAK)
stop(SCL)
return value

Comments
The only thing that I can think of that could cause that would be if the BMP058 uses clock-stretching - though it's not mentioned in the datasheet. I notice that the basic I2C driver you're using drives the lines both high and low, if the BMP is holding the clock low (stretching it) while the driver is trying to assert a high, that could be causing that problem.
The forum has some screwyness with the percent sign. Please verify that you're using percent 111_0111 as the the device address.
I've cobbled together a quick routine using my Spin-based driver that's worked with everything I've tested in on.
BMP058 - Archive.zip
Chris- i tried that code, bmp not found when i run on 28 & 29, but when i try 8 & 9 prop term stays blank.
Does the prop ONLY do i2c on pins 28 & 29 ????
i am seriously considering trying to find a i2c to serial ic to use so that all i have purchased (i2c) is not junk. or it is time to quit using the propeller all together.
This is a serious stress as my project uses 3+ i2c sensors, and right now, i cant use a single one of them.
Ive had a few hurdles so far that were a bit rough to get over & the forums here had the answers. Hopefully this one too will become a past problem.
i also keep noticing that different people have gotten it to work with different addresses...
BAROMETRO.spin uses address "1"
http://mbed.org/users/tkreyche/notebook/bmp085-pressure-sensor/ uses 0xEF
the DATASHEET uses 1110_1110 Write & 1110_1111 Read
your example $77 = 0x77 = 0111_0111
which one is correct? is there a default ("1") that works for Everything?
i changed your code around a bit, more for a debug setting.
{{ }} CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 'SDA_pin = 29 'SCL_pin = 28 SDA_pin = 8 SCL_pin = 9 'BMPscl = 9 ' Currently on 8, 9 Bus 'BMPsda = 8 BMP = $77 'BMPAddress = $77 'BMPAddress = %0111_0111 ' 0x77 = %01110111 pct0111_0111 'BMPAddress = %1110_1110 ' BMP - Write pct1110_1110 BMPAddress = %1110_1111 ' BMP - Read pct1110_1111 VAR word array[11] OBJ I2C : "I2C Spin driver v1.2" FDS : "FullDuplexSerial" PUB Main | device_id, register, n I2C.start(SCL_pin,SDA_pin) FDS.start(31,30,0,115200) waitcnt(clkfreq + cnt) repeat FDS.tx($00) if not \I2C.command(BMPAddress,$AA) 'if not \I2C.command(BMP,$AA) ' Test to see if the pressure sensor is on the bus FDS.str(string(" BMP058 not found at address $77. Polling bus for other I2C devices.",$0D,$0D)) device_id := 0 repeat until device_id == $80 if \I2C.command(device_id,0) ' This is just to make sure that everything else is working FDS.str(string("Device found at %")) ' The EEPROM should show up as %1010000 if using P28 and P29 for I2C FDS.bin(device_id,7) ' The BMP058 should show up as %1110111 FDS.tx($0D) device_id++ fds.str(string(" Device Found...")) ' Halt program {I'm not even going to pretend to understand that datasheet, so this is just going to list all of the registers from AA through BF as 11 words} n~ if \I2C.read_words(BMPAddress,$AA,@array,11) 'if \I2C.read_words(BMP,$AA,@array,11) ' Read 11 words from BMP58 starting at register $AA repeat register from $AA to $BE step 2 FDS.hex(register,2) FDS.str(string(": ")) FDS.hex(array[n],4) n += 2 FDS.tx($0D)PUB Main | device_id FDS.start(31,30,0,115_200) waitcnt(cnt + clkfreq) FDS.tx($00) I2C.start(SCL,SDA) device_ID := 0 repeat until device_ID == $80 if \I2C.command(device_ID,0) FDS.str(string("Device found at %")) FDS.bin(device_ID,7) FDS.tx($0D) device_ID++ FDS.str(string("Finished"))In response to the addressing question in post #5, I2C devices have a 7-bit identifier, followed by a read/write bit. The basic I2C driver expects the user to format the 7-bit ID and 1-bit read/write into a single byte. I wrote my driver to accept just the 7-bit ID and automatically add the read/write depending on what method was called, so $77 should work for all methods -- I2C.write($77,$00,$01)) write the value $01 to register $00 of device $77, I2C.read($77,$00) return the value in register $00 of device $77, should be just that simple.
is 10k ohm too much for 3.3v? i know the datasheet said 10k was the max, and my eeprom uses a 10k so ive got plenty layin around. I wouldnt expect it to be too much. i know when i was trying to get my 7 mlx90615's to work (all i2c) i tried various values with no luck.
changed from the spin i2c driver to the pasm driver and it acts totally different, still no correct data out. if the pins are right or wrong, it gives the same output forwards and backwards (sda = 8 & scl = 9 or sda = 9 & scl = 8) even on pins that have NOTHING hooked up to them i still get the same output.
I don't see any pull up resistors on I2C traces.
You need think I2C are open collector that need's that
they are on there, follow the two i2c traces, they go to the only two resistors on that side of the board & theyr hooked to 3.3v (R5 & R6)
So i have tried running FreqSynth out on pins 8 & 9.... here we have a problem. i didnt expect one pin on my prop chip to be jacked up...
Still same problems, no data, etc, etc.
could i have over heated it during soldering??? i did it on a pretty low temp and only heated it very little. i have one left i can hook up via silver epoxy.
also, sinci i dont have any, as far as i know working, i2c devices, i am considering connecting two propeller chips together using the i2c bus.
when i scoped the square waves, no, it was unplugged. that was right out of my prop pin. i have since switched to my smd pcb that was in my helicopter. checked its square wave and it was clean. still the same problems with i2c.
right now, if my i2c is unplugged and i run BAROMETRO, sda has some pulses, scl is high, same for read REGISTERS. but i2cScan has a clock signal on scl & data on sda, Nothing is plugged in the i2c header, that is what the prop is producing from the code. as shown in photos below. when plugged in... read REGISTERS both lines are pulled low ~0.027v, BAROMETRO has most data like output & i2cScan is closest to BAROMETRO.
*** i2cScan CAN find propeller EEPROM but finds 0 devices for bmp085.
i just got my mpu-6050 module in the mail today so ive got a second i2c device to test with that i didnt have to soldier.
going to try your i2c master/slave demo right quick before i mess with the mpu-6050.
i2cScan.spin:
{{ ┌──────────────────────────────────────────┐ │ I2CScan 1.0 │ │ Author: Tim Moore │ │ Copyright (c) 2008> Tim Moore │ │ See end of file for terms of use. │ │ Based on code by James Burrows │ │ │ │ Modified to support SMBus timing │ └──────────────────────────────────────────┘ }} CON _clkmode = xtal1 + pll16x ' System clock → 80 MHz _xinfreq = 5_000_000 ' EEPROM = 01010000 ' 01010000 10100000 'aSDA = 29 ' Correct Values for EEPROM 'aSCL = 28 ' BMP085 = Not Found aSDA = 8 ' SMD SDA = 8 aSCL = 9 ' SMD SCL = 9 OBJ uarts : "FullDuplexSerial" pub start uarts.start(31, 30, 0, 115200) repeat i2cScan(aScl) waitcnt((clkfreq / 3) + cnt) PUB i2cScan(i2cSCL) | value, ackbit, i2cSlaveCounter, i2cAddress ' Scan the I2C Bus and debug the LCD uarts.str(string("Scanning I2C Bus....")) uarts.tx(13) ' initialize variables i2cSlaveCounter := 0 ' i2c Scan - scans all the address's on the bus ' sends the address byte and listens for the device to ACK (hold the SDA low) ' Skip address 0 sinces its the broadcast address and multiple devices can respond repeat i2cAddress from 1 to 127 value := i2cAddress << 1 | 0 ackbit := Check(i2cSCL,value) if ackbit==false 'uarts.str(string("NAK ")) else ' show the scan uarts.str(string("Scan Addr : %")) uarts.bin(value,8) uarts.str(" ") uarts.bin(i2cAddress,8) uarts.str(string(", ACK")) ' the device has set the ACK bit i2cSlaveCounter ++ waitcnt(clkfreq/4+cnt) ' slow the scan so we can read it. 'waitcnt(clkfreq/10 + cnt) ' update the counter uarts.tx(13) uarts.tx(13) uarts.str(string("i2cScan found ")) uarts.dec(i2cSlaveCounter) uarts.str(string(" devices!")) uarts.tx(13) uarts.tx(13) PRI Check(SCL,deviceAddress) : ackbit | SDA, ob, d '' send the deviceAddress and listen for the ACK ' All the code is inlined here to meet the SMBus SCL low timing constraints ' SDA := aSDA 'SCL + 1 d := deviceAddress << 24 'Need this for MLX90614 outa[SCL]~~ dira[SDA]~~ dira[SCL]~~ outa[SDA]~ outa[SDA]~~ 'Do it twice since MLX90614 doesn't respond 1st time always outa[SCL]~~ ' Initially drive SCL HIGH dira[SCL]~~ outa[SDA]~~ ' Initially drive SDA HIGH dira[SDA]~~ outa[SDA]~ ' Now drive SDA LOW ob := (d <-= 1) & 1 outa[SCL]~ ' Leave SCL LOW repeat 8 ' Output data to SDA outa[SDA] := ob outa[SCL]~~ ' Toggle SCL from LOW to HIGH to LOW ob := (d <-= 1) & 1 outa[SCL]~ dira[SDA]~ ' Set SDA to input for ACK/NAK outa[SCL]~~ ackbit := ina[SDA] == 0 ' Sample SDA when SCL is HIGH outa[SCL]~ dira[SCL]~ ' Now let them float dira[SDA]~ ' If pullups present, they'll stay HIGH d := deviceAddress << 24 outa[SCL]~~ ' Initially drive SCL HIGH dira[SCL]~~ outa[SDA]~~ ' Initially drive SDA HIGH dira[SDA]~~ outa[SDA]~ ' Now drive SDA LOW ob := (d <-= 1) & 1 outa[SCL]~ ' Leave SCL LOW repeat 8 ' Output data to SDA outa[SDA] := ob outa[SCL]~~ ' Toggle SCL from LOW to HIGH to LOW ob := (d <-= 1) & 1 outa[SCL]~ dira[SDA]~ ' Set SDA to input for ACK/NAK outa[SCL]~~ ackbit |= ina[SDA] == 0 ' Sample SDA when SCL is HIGH, accept either ack outa[SCL]~ dira[SCL]~ ' Now let them float dira[SDA]~ ' If pullups present, they'll stay HIGH {{ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ TERMS OF USE: MIT License │ ├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation │ │files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, │ │modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software│ │is furnished to do so, subject to the following conditions: │ │ │ │The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.│ │ │ │THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE │ │WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR │ │COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │ │ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ }}OScope i2c BMP085:
BAROMETRO SCL:
BAROMETRO SDA:
i2cScan SCL:
i2cScan SDA:
OScope Readings i2c UnPlugged:
BAROMETRO SDA Line (SCL was High 3.3v):
read REGISTERS SDA line (SCL was High):
i2cScan SCL:
i2cScan SDA:
I am starting to think my bmp085's are toasting when i am soldering them up.
got one left, gonna try silver conductive epoxy & a homemade breakout board. if that fails, its off to an MPL115A1 SPI pressure sensor (or get a bmp085 breakout).
so i can only conclude that the bmp085's are themselves damaged, or are being damaged when soldered.
MPU-6050.spin:
'' MPU-60X0-PASM.spin '' Reads gyro and accelerometer data from the MPU-60X0 chips '' Read loop is in Propeller Assembler '' '' Based on Jason Dorie's code for the ITG-3200 and ADCL345 chips '' '' Note that this code assumes an 80 MHz clock '' '' The TestMPU routine can be used to verify correct setup of, and '' communication with, the MPU-60X0. Load the object into RAM, then '' use f12 to bring up the terminal emulator to see the output. '' {{ The slave address of the MPU-60X0 is b110100X which is 7 bits long. The LSB bit of the 7 bit address is determined by the logic level on pin AD0. This allows two MPU-60X0s to be connected to the same I2C bus. When used in this configuration, the address of the one of the devices should be b1101000 (pin AD0 is logic low) and the address of the other should be b1101001 (pin AD0 is logic high). }} CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 CON ' CONs for TestMPU test routine SDA_PIN = 8 SCL_PIN = 9 SERIAL_TX_PIN = 30 SERIAL_RX_PIN = 31 VAR long x0, y0, z0, t long Cog long rx, ry, rz, temp, ax, ay, az, arx, ary 'PASM code assumes these to be contiguous OBJ 'debug : "FullDuplexSerialPlus.spin" debug : "FullDuplexSerial" PUB TestMPU | MPUcog '----------------------------------------------- ' Start serial i/o cog ' Start cog to pull gyro/accel data from chip ' Print data to serial out every few seconds '------------------------------------------------ debug.start(SERIAL_RX_PIN, SERIAL_TX_PIN, 0, 115200) 'Start cog to allow IO with serial terminal repeat 4 waitcnt(clkfreq + cnt) debug.str(string("Starting...")) debug.tx(13) debug.str(string("GX GY GZ AX AY AZ")) debug.tx(13) debug.str(string("-------------------------")) debug.tx(13) MPUcog := Start( SCL_PIN, SDA_PIN) 'Output gyro data, then accel data, once per second repeat debug.dec(GetRX) debug.str(string(", ")) debug.dec(GetRY) debug.str(string(", ")) debug.dec(GetRZ) debug.str(string(" ")) debug.dec(GetAX) debug.str(string(", ")) debug.dec(GetAY) debug.str(string(", ")) debug.dec(GetAZ) debug.tx(13) waitcnt(clkfreq + cnt) PUB Start( SCL, SDA ) : Status ComputeTimes gyroSCL := 1 << SCL 'save I2C pins gyroSDA := 1 << SDA Status := Cog := cognew(@Start_Sensors, @rx) + 1 Calibrate PUB Stop if Cog cogstop(Cog~ - 1) '********************** ' Accessors '********************** PUB GetTemp return temp PUB GetRX return rx - x0 PUB GetRY return ry - y0 PUB GetRZ return rz - z0 PUB GetAX return ax PUB GetAY return ay PUB GetAZ return az PUB GetARX return arx PUB GetARY return ary PRI computeTimes '' Set up timing constants in assembly ' (Done this way to avoid overflow) i2cDataSet := ((clkfreq / 10000) * 350) / 100000 ' Data setup time - 350ns (400KHz) i2cClkLow := ((clkfreq / 10000) * 1300) / 100000 ' Clock low time - 1300ns (400KHz) i2cClkHigh := ((clkfreq / 10000) * 600) / 100000 ' Clock high time - 600ns (400KHz) i2cPause := clkfreq / 100000 ' Pause between checks for operations PRI Calibrate | tc, xc, yc, zc, dr x0 := 0 ' Initialize offsets y0 := 0 z0 := 0 'wait 1/2 second for the body to stop moving waitcnt( constant(80_000_000 / 2) + cnt ) 'Find the zero points of the 3 axis by reading for ~1 sec and averaging the results xc := 0 yc := 0 zc := 0 repeat 256 xc += rx yc += ry zc += rz waitcnt( constant(80_000_000/192) + cnt ) 'Perform rounding if( xc > 0 ) xc += 128 elseif( xc < 0 ) xc -= 128 if( yc > 0 ) yc += 128 elseif( yc < 0 ) yc -= 128 if( zc > 0 ) zc += 128 elseif( zc < 0 ) zc -= 128 x0 := xc / 256 y0 := yc / 256 z0 := zc / 256 DAT org 0 Start_Sensors ' --------- Debugger Kernel add this at Entry (Addr 0) --------- ' long $34FC1202,$6CE81201,$83C120B,$8BC0E0A,$E87C0E03,$8BC0E0A ' long $EC7C0E05,$A0BC1207,$5C7C0003,$5C7C0003,$7FFC,$7FF8 ' -------------------------------------------------------------- mov p1, par ' Get data pointer mov prX, p1 ' Store the pointer to the rx var in HUB RAM add p1, #4 mov prY, p1 ' Store the pointer to the ry var in HUB RAM add p1, #4 mov prZ, p1 ' Store the pointer to the rz var in HUB RAM add p1, #4 mov pT, p1 ' Store the pointer to the temp var in HUB RAM add p1, #4 mov paX, p1 ' Store the pointer to the ax var in HUB RAM add p1, #4 mov paY, p1 ' Store the pointer to the ay var in HUB RAM add p1, #4 mov paZ, p1 ' Store the pointer to the az var in HUB RAM add p1, #4 mov paRX, p1 ' Store the pointer to the arx var in HUB RAM add p1, #4 mov paRY, p1 ' Store the pointer to the ary var in HUB RAM mov i2cTemp,i2cPause add i2cTemp,CNT ' Wait 10us before starting waitcnt i2cTemp,#0 call #SetConfig mov loopCount, CNT add loopCount, loopDelay '------------------------------------------------------------------------------ ' Main loop ' loopDelay defined in data section ' Nominally set to CLK_FREQ/200 give 200hz update rate, but the update takes less than ' 500us, so the delay could potentially be set to give an update rate as high as 2000hz ' :loop call #MPUReadValues call #MPUComputeDrift call #ComputeAngles wrlong iT, pT subs irX, drift wrlong irX, prX subs irY, drift wrlong irY, prY subs irZ, drift wrlong irZ, prZ wrlong iaX, paX wrlong iaY, paY wrlong iaZ, paZ wrlong iaRX, paRX wrlong iaRY, paRY waitcnt loopCount, loopDelay jmp #:loop '------------------------------------------------------------------------------ ' MPUReadValues ' ' Starting at the ACCEL_X data register, read in the 3 accel values, ' the temperature, and the 3 gyro values, as these are held in ' sequential register locations. ' MPUReadValues mov i2cSDA, gyroSDA 'Use gyro SDA,SCL mov i2cSCL, gyroSCL mov i2cAddr, #59 ' Address of ACCEL_XOUT_H mov i2cDevID, #%11010000 ' Device ID of the MPU call #StartRead ' Tell the I2C device we're starting mov i2cMask, i2cWordReadMask test i2cTestCarry, #0 wc ' Clear the carry flag to make reads auto-increment call #i2cRead call #i2cRead 'Sign extend the 15th bit test i2cData, i2cWordReadMask wc muxc i2cData, i2cWordMask mov iaX, i2cData mov i2cMask, i2cWordReadMask test i2cTestCarry, #0 wc ' Clear the carry flag to make reads auto-increment call #i2cRead call #i2cRead 'Sign extend the 15th bit test i2cData, i2cWordReadMask wc muxc i2cData, i2cWordMask mov iaY, i2cData mov i2cMask, i2cWordReadMask test i2cTestCarry, #0 wc ' Clear the carry flag to make reads auto-increment call #i2cRead call #i2cRead 'Sign extend the 15th bit test i2cData, i2cWordReadMask wc muxc i2cData, i2cWordMask mov iaZ, i2cData mov i2cMask, i2cWordReadMask test i2cTestCarry, #0 wc ' Clear the carry flag to make reads auto-increment call #i2cRead 'test i2cTestCarry, #1 wc ' Set the carry flag to tell it we're done call #i2cRead test i2cData, i2cWordReadMask wc muxc i2cData, i2cWordMask mov iT, i2cData mov i2cMask, i2cWordReadMask test i2cTestCarry, #0 wc ' Clear the carry flag to make reads auto-increment call #i2cRead call #i2cRead 'Sign extend the 15th bit test i2cData, i2cWordReadMask wc muxc i2cData, i2cWordMask mov irX, i2cData mov i2cMask, i2cWordReadMask test i2cTestCarry, #0 wc ' Clear the carry flag to make reads auto-increment call #i2cRead call #i2cRead 'Sign extend the 15th bit test i2cData, i2cWordReadMask wc muxc i2cData, i2cWordMask mov irY, i2cData mov i2cMask, i2cWordReadMask test i2cTestCarry, #0 wc ' Clear the carry flag to make reads auto-increment call #i2cRead test i2cTestCarry, #1 wc ' Set the carry flag to tell it we're done call #i2cRead 'Sign extend the 15th bit test i2cData, i2cWordReadMask wc muxc i2cData, i2cWordMask mov irZ, i2cData call #i2cStop MPUReadValues_Ret ret '------------------------------------------------------------------------------ ' Compute drift - for my gyro (Jason's ITG-3200) '(Temp + 15000) / 100 = drift '------------------------------------------------------------------------------ MPUComputeDrift mov drift, iT ' Start with the temperature reading add drift, tempOffset ' Offset it by 15,000 ' divide drift by 100 mov divisor, #100 mov dividend, drift test dividend, i2cWordReadMask wc muxc signbit, #1 ' record the sign of the original value abs dividend, dividend mov divCounter, #10 shl divisor, divCounter mov resultShifted, #1 shl resultShifted, divCounter add divCounter, #1 mov drift, #0 :divLoop cmp dividend, divisor wc if_nc add drift, resultShifted if_nc sub dividend, divisor shr resultShifted, #1 shr divisor, #1 djnz divCounter, #:divLoop test signbit, #1 wc negc drift, drift MPUComputeDrift_Ret ret '------------------------------------------------------------------------------ ComputeAngles mov cx, iaZ mov cy, iaX call #cordic mov iaRX, ca mov cx, iaZ mov cy, iaY call #cordic mov iaRY, ca ComputeAngles_ret ret '------------------------------------------------------------------------------ ' SetConfig ' ' See MPU-6000/6050 Register Map document for register addresses and ' valid settings ' SetConfig mov i2cSDA, gyroSDA 'Use gyro SDA,SCL mov i2cSCL, gyroSCL call #i2cReset 'Reset i2c :MPUSetConfig mov i2cDevID, #%11010000 'Device ID for the MPU-6000/6050 mov i2cAddr, #107 'Set PWR_MGMT_1 register bit 0 to choose mov i2cValue, #%00000001 ' X gyro as clock source ' call #i2cWriteRegisterByte mov i2cAddr, #26 mov i2cValue, #%00000100 'Set DLPF_CONFIG to 4 for 20Hz bandwidth call #i2cWriteRegisterByte mov i2cAddr, #25 'SMPLRT_DIV = 1 => 1khz/(1+1) = 500hz sample rate mov i2cValue, #%00000001 call #i2cWriteRegisterByte mov i2cAddr, #27 'GYRO_CONFIG register, set FS_SEL bits to 3 gives a mov i2cValue, #%00011000 ' full scale range of 2000 deg/sec call #i2cWriteRegisterByte mov i2cAddr, #28 'Set ACCEL_CONFIG register AFS_SEL bits to 1, mov i2cValue, #%00001000 ' sets +-4g full scale range call #i2cWriteRegisterByte 'ACCEL_HPF is zero which turns off high-pass filtering SetConfig_Ret ret '------------------------------------------------------------------------------ StartRead call #i2cStart mov i2cData, i2cDevID mov i2cMask, #%10000000 call #i2cWrite mov i2cData, i2cAddr mov i2cMask,#%10000000 call #i2cWrite call #i2cStart mov i2cData, i2cDevID or i2cData, #1 mov i2cMask, #%10000000 call #i2cWrite StartRead_Ret ret '------------------------------------------------------------------------------ i2cWriteRegisterByte call #i2cStart mov i2cData, i2cDevID mov i2cMask,#%10000000 call #i2cWrite mov i2cTime,i2cClkLow add i2cTime,cnt ' Allow for minimum SCL low waitcnt i2cTime, #0 mov i2cData, i2cAddr mov i2cMask,#%10000000 call #i2cWrite mov i2cTime,i2cClkLow add i2cTime,cnt ' Allow for minimum SCL low waitcnt i2cTime, #0 mov i2cData, i2cValue mov i2cMask,#%10000000 call #i2cWrite call #i2cStop i2cWriteRegisterByte_Ret ret '------------------------------------------------------------------------------ '' Low level I2C routines. These are designed to work either with a standard I2C bus '' (with pullups on both SCL and SDA) or the Propellor Demo Board (with a pullup only '' on SDA). Timing can be set by the caller to 100KHz or 400KHz. '------------------------------------------------------------------------------ '' Do I2C Reset Sequence. Clock up to 9 cycles. Look for SDA high while SCL '' is high. Device should respond to next Start Sequence. Leave SCL high. i2cReset andn dira,i2cSDA ' Pullup drive SDA high mov i2cBitCnt,#9 ' Number of clock cycles mov i2cTime,i2cClkLow add i2cTime,cnt ' Allow for minimum SCL low :i2cResetClk andn outa,i2cSCL ' Active drive SCL low or dira,i2cSCL waitcnt i2cTime,i2cClkHigh or outa,i2cSCL ' Active drive SCL high or dira,i2cSCL andn dira,i2cSCL ' Pullup drive SCL high waitcnt i2cTime,i2cClkLow ' Allow minimum SCL high test i2cSDA,ina wz ' Stop if SDA is high if_z djnz i2cBitCnt,#:i2cResetClk ' Stop after 9 cycles i2cReset_ret ret ' Should be ready for Start '------------------------------------------------------------------------------ '' Do I2C Start Sequence. This assumes that SDA is a floating input and '' SCL is also floating, but may have to be actively driven high and low. '' The start sequence is where SDA goes from HIGH to LOW while SCL is HIGH. i2cStart or outa,i2cSCL ' Active drive SCL high or dira,i2cSCL or outa,i2cSDA ' Active drive SDA high or dira,i2cSDA mov i2cTime,i2cClkHigh add i2cTime,cnt ' Allow for bus free time waitcnt i2cTime,i2cClkLow andn outa,i2cSDA ' Active drive SDA low waitcnt i2cTime,#0 andn outa,i2cSCL ' Active drive SCL low i2cStart_ret ret '------------------------------------------------------------------------------ '' Do I2C Stop Sequence. This assumes that SCL is low and SDA is indeterminant. '' The stop sequence is where SDA goes from LOW to HIGH while SCL is HIGH. '' i2cStart must have been called prior to calling this routine for initialization. '' The state of the (c) flag is maintained so a write error can be reported. i2cStop or outa,i2cSCL ' Active drive SCL high mov i2cTime,i2cClkHigh add i2cTime,cnt ' Wait for minimum clock low waitcnt i2cTime,i2cClkLow or outa,i2cSDA ' Active drive SDA high waitcnt i2cTime,i2cClkLow andn dira,i2cSCL ' Pullup drive SCL high waitcnt i2cTime,i2cClkLow ' Wait for minimum setup time andn dira,i2cSDA ' Pullup drive SDA high waitcnt i2cTime,#0 ' Allow for bus free time i2cStop_ret ret '------------------------------------------------------------------------------ '' Write I2C data. This assumes that i2cStart has been called and that SCL is low, '' SDA is indeterminant. The (c) flag will be set on exit from ACK/NAK with ACK == false '' and NAK == true. Bytes are handled in "little-endian" order so these routines can be '' used with words or longs although the bits are in msb..lsb order. i2cWrite mov i2cBitCnt,#8 mov i2cTime,i2cClkLow add i2cTime,cnt ' Wait for minimum SCL low :i2cWriteBit waitcnt i2cTime,i2cDataSet test i2cData,i2cMask wz if_z or dira,i2cSDA ' Copy data bit to SDA if_nz andn dira,i2cSDA waitcnt i2cTime,i2cClkHigh ' Wait for minimum setup time or outa,i2cSCL ' Active drive SCL high waitcnt i2cTime,i2cClkLow andn outa,i2cSCL ' Active drive SCL low ror i2cMask,#1 ' Go do next bit if not done djnz i2cBitCnt,#:i2cWriteBit andn dira,i2cSDA ' Switch SDA to input and waitcnt i2cTime,i2cClkHigh ' wait for minimum SCL low or outa,i2cSCL ' Active drive SCL high waitcnt i2cTime,i2cClkLow ' Wait for minimum high time test i2cSDA,ina wc ' Sample SDA (ACK/NAK) then andn outa,i2cSCL ' active drive SCL low andn outa,i2cSDA ' active drive SDA low or dira,i2cSDA ' Leave SDA low rol i2cMask,#16 ' Prepare for multibyte write waitcnt i2cTime,#0 ' Wait for minimum low time i2cWrite_ret ret '------------------------------------------------------------------------------ '' Read I2C data. This assumes that i2cStart has been called and that SCL is low, '' SDA is indeterminant. ACK/NAK will be copied from the (c) flag on entry with '' ACK == low and NAK == high. Bytes are handled in "little-endian" order so these '' routines can be used with words or longs although the bits are in msb..lsb order. i2cRead mov i2cBitCnt,#8 andn dira,i2cSDA ' Make sure SDA is set to input mov i2cTime,i2cClkLow add i2cTime,cnt ' Wait for minimum SCL low :i2cReadBit waitcnt i2cTime,i2cClkHigh or outa,i2cSCL ' Active drive SCL high waitcnt i2cTime,i2cClkLow ' Wait for minimum clock high test i2cSDA,ina wz ' Sample SDA for data bits andn outa,i2cSCL ' Active drive SCL low if_nz or i2cData,i2cMask ' Accumulate data bits if_z andn i2cData,i2cMask ror i2cMask,#1 ' Shift the bit mask and djnz i2cBitCnt,#:i2cReadBit ' continue until done waitcnt i2cTime,i2cDataSet ' Wait for end of SCL low if_c or outa,i2cSDA ' Copy the ACK/NAK bit to SDA if_nc andn outa,i2cSDA or dira,i2cSDA ' Make sure SDA is set to output waitcnt i2cTime,i2cClkHigh ' Wait for minimum setup time or outa,i2cSCL ' Active drive SCL high waitcnt i2cTime,i2cClkLow ' Wait for minimum clock high andn outa,i2cSCL ' Active drive SCL low andn outa,i2cSDA ' Leave SDA low waitcnt i2cTime,#0 ' Wait for minimum low time i2cRead_ret ret '------------------------------------------------------------------------------ '' Perform CORDIC cartesian-to-polar conversion ''Input = cx(x) and cy(x) ''Output = cx(ro) and ca(theta) cordic abs cx,cx wc if_c neg cy,cy mov ca,#0 rcr ca,#1 movs :lookup,#cordicTable mov t1,#0 mov t2,#20 :loop mov dx,cy wc sar dx,t1 mov dy,cx sar dy,t1 sumc cx,dx sumnc cy,dy :lookup sumc ca,cordicTable add :lookup,#1 add t1,#1 djnz t2,#:loop shr ca, #16 cordic_ret ret cordicTable long $20000000 long $12E4051E long $09FB385B long $051111D4 long $028B0D43 long $0145D7E1 long $00A2F61E long $00517C55 long $0028BE53 long $00145F2F long $000A2F98 long $000517CC long $00028BE6 long $000145F3 long $0000A2FA long $0000517D long $000028BE long $0000145F long $00000A30 long $00000518 dx long 0 dy long 0 cx long 0 cy long 0 ca long 0 t1 long 0 t2 long 0 '' Variables for the gyro routines p1 long 0 pT long 0 ' Pointer to Temperature in hub ram prX long 0 ' Pointer to X rotation in hub ram prY long 0 ' Pointer to Y rotation in hub ram prZ long 0 ' Pointer to Z rotation in hub ram paX long 0 ' Pointer to X accel in hub ram paY long 0 ' Pointer to Y accel in hub ram paZ long 0 ' Pointer to Z accel in hub ram paRX long 0 ' Pointer to X accel angle in hub ram paRY long 0 ' Pointer to Y accel angle in hub ram iT long 0 ' Interim temperature value irX long 0 ' Interim rX value irY long 0 ' Interim rY value - These values are temp storage before drift compensation irZ long 0 ' Interim rZ value iaX long 0 ' Interim aX value iaY long 0 ' Interim aY value iaZ long 0 ' Interim aZ value iaRX long 0 ' Interim aX value iaRY long 0 ' Interim aY value i2cWordReadMask long %10000000_00000000 i2cWordMask long $ffff0000 loopDelay long 80_000_000 / 200 loopCount long 0 '' Variables for dealing with drift / division tempOffset long 15000 drift long 0 divisor long 0 dividend long 0 resultShifted long 0 signbit long 0 divCounter long 0 '' Variables for i2c routines i2cTemp long 0 i2cCount long 0 i2cValue long 0 i2cDevID long 0 i2cAddr long 0 i2cDataSet long 0 ' Minumum data setup time (ticks) i2cClkLow long 0 ' Minimum clock low time (ticks) i2cClkHigh long 0 ' Minimum clock high time (ticks) i2cPause long 0 ' Pause before re-fetching next operation i2cTestCarry long 1 ' Used for setting the carry flag '' Local variables for low level I2C routines gyroSCL long 0 ' Bit mask for SCL gyroSDA long 0 ' Bit mask for SDA i2cSCL long 0 ' Bit mask for SCL i2cSDA long 0 ' Bit mask for SDA i2cTime long 0 ' Used for timekeeping i2cData long 0 ' Data to be transmitted / received i2cMask long 0 ' Bit mask for bit to be tx / rx i2cBitCnt long 0 ' Number of bits to tx / rx FIT 496INSTANT GRATIFICATION!!!!
Works 100%. Demo code works 100%. And it is running on i2c.
I am glad I spent the $30 to try this little guy out. When it comes to producing my own circuit I will just get the $8 MS5607. But still $8 vs $2 it is more expensive than the BMP180, the extra few bucks makes it worth it. In retrospect, the module should only be $15 or $20 at the most.
BMP085 demo - Archive.zip