Shop OBEX P1 Docs P2 Docs Learn Events
BMP085 i2c Problems... — Parallax Forums

BMP085 i2c Problems...

zlantzzlantz Posts: 136
edited 2014-04-03 13:10 in Propeller 1
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:
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)
{{
&#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
&#9474;                                                    TERMS OF USE: MIT  License                                                   &#9474;                                                            
&#9500;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9508;
&#9474;Permission  is hereby granted, free of charge, to any person obtaining a copy of  this software and associated documentation    &#9474; 
&#9474;files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,    &#9474;
&#9474;modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software&#9474;
&#9474;is furnished to do so, subject to the following conditions:                                                                   &#9474;
&#9474;                                                                                                                              &#9474;
&#9474;The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.&#9474;
&#9474;                                                                                                                              &#9474;
&#9474;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE          &#9474;
&#9474;WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR         &#9474;
&#9474;COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,   &#9474;
&#9474;ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                         &#9474;
&#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
}}



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

  • ChrisGaddChrisGadd Posts: 310
    edited 2013-09-11 11:46
    I don't know what to make of the signal on the clock line; the SCL and SDA lines should both have pull-up resistors to 3.3V and any devices on the bus should only pull them low for a 0-bit or release the line (allowing them to float to 3.3V) for a 1-bit.
    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
  • zlantzzlantz Posts: 136
    edited 2013-09-12 07:29
    Could it be possible that because i am not using pins 28 & 29 for i2c that it is causing not to work? my i2c is on 8 & 9, and when i set the correct values for scl & sda no data gets sent, but if i use the wrong values ie 11 & 10 or 8 & 7, etc it displays 0 or i2cscan says found 127 devices. if i use the correct values, no data is sent, no serial out is displayed on propterm.


    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 ????
  • Mike GreenMike Green Posts: 23,101
    edited 2013-09-12 07:38
    The Prop can do I2C on any pair of I/O pins. Basic_I2C_Driver is written to use adjacent I/O pins as described in the comments at the beginning of the Spin source file. SCL is the pin # specified when you call it and SDA is the next higher numbered I/O pin. Perhaps you have the BMP085 wired to the wrong I/O pins?
  • zlantzzlantz Posts: 136
    edited 2013-09-12 07:55
    my SDA is one Lower IO pin, i havent tried re-soldering it (shouldnt have to), ive just done the software swap. and no, ive checked that about 20 times (wrong io pins), plus ive swapped the pins in the software just to be sure. its not just the bmp085, ive got 7 mlx90615's that dont work either (i2c).

    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?
  • zlantzzlantz Posts: 136
    edited 2013-09-12 08:49
    ive tried every combination of bmp address i have & scl/sda pin combos as well, when i use prop sda/scl on 28/29, it will tell me no bmp85 found on $77, but when i use the bmp's pins (8 & 9 or 9 & 8) nothing is displayed, it dont make it to " fds.str(string(" Device Found...")) " that i added in to see where it was locking up. fyi on pins 28 & 29 it dont get past "scanning for other devices"

    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)
    
    
  • Mike GreenMike Green Posts: 23,101
    edited 2013-09-12 09:30
    As I've mentioned before, Basic_I2C_driver is written to have SCL on one I/O pin (the one specified) and SDA on the next higher numbered I/O pin. If you're going to change this, you have to modify Basic_I2C_Driver and, whenever you do that, you run the risk of doing it wrong. The EEPROM I2C bus has SCL on I/O pin 28 and SDA on I/O pin 29. That seems to work for you. The ObEx driver objects work when wired up correctly. It sounds like you have two main choices: 1) Wire up the BMP085 the way the code expects with SCL on pin 8 and SDA on pin 9; 2) Carefully modify the driver objects so the SDA pin number is SCL-1 instead of SCL+1, then specify the SCL pin as #9 when you call the driver object. You can modify the driver objects to expect SCL and SDA as separate parameters as it looks like you've done, but the burden is on you to check that you've done that properly. Since it doesn't work, there's obviously an error there since Basic_I2C_Driver works with a variety of I2C devices.
  • ChrisGaddChrisGadd Posts: 310
    edited 2013-09-12 10:15
    The polling routine should only run if it fails to detect a device at $77, in which case no message would mean that something was found, however it could also mean there's a problem with the bus. For instance, it'll hang if the SDA and SCL lines aren't idling high through pull-up resistors, you mentioned you have a scope so check this. Could also mean that it was found on the bus, but that the EEPROM couldn't be read like I was trying. First goal should simply be to see if the device answers when called, so here's a modified polling routine that'll poll every address:
     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.
  • zlantzzlantz Posts: 136
    edited 2013-09-12 11:52
    just tried that code, on my bmp085 it hangs between i2c.start & device_id++ because it never makes it to finished. but when i set to eeprom sda scl (to test with prop's eeprom) it will make it to finished, but nothing is found.

    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.
  • zlantzzlantz Posts: 136
    edited 2013-09-12 19:17
    still cant get ANY i2c code working, even testing against my eeprom. everything locks up in the i2c.command.

    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.
  • ChrisGaddChrisGadd Posts: 310
    edited 2013-09-13 05:43
    I hate to suggest this as you said you checked the io pins twenty times, but have you tried verifying it with code with your scope, or even a LED, attached? Something extremely basic like this.
    dira[8..9]~~
    repeat
      !outa[8..9]
      waitcnt(cnt + clkfreq / 2)
    
    I only suggest that because the polling routine works perfectly for me. I attached every I2C device I have, EEPROM, clock, gyro, accelerometer, altimeter, IO expander, plus a slave object and a multi-master object running in other cogs, and it detected every one of them. 10K-ohm pull-ups are what I use. What kind of board are you using? This driver won't work with the EEPROM on the prop demo board as it only has a pull-up on SDA.
  • zlantzzlantz Posts: 136
    edited 2013-09-13 07:47
    its a custom etch pcb, i also have a smd version, both are giving me problems with i2c, but nothing else.
  • SapiehaSapieha Posts: 2,964
    edited 2013-09-13 08:14
    Hi.

    I don't see any pull up resistors on I2C traces.

    You need think I2C are open collector that need's that






    zlantz wrote: »
    Attachment not found.

    its a custom etch pcb, i also have a smd version. both are giving me problems with i2c, but nothing else.
  • zlantzzlantz Posts: 136
    edited 2013-09-13 08:23
    connections.jpg


    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)
    508 x 331 - 42K
  • zlantzzlantz Posts: 136
    edited 2013-09-13 08:26
    IMG_20130913_085446_461.jpg
    IMG_20130913_092132_818.jpg


    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...
    1024 x 577 - 52K
    1024 x 577 - 56K
  • zlantzzlantz Posts: 136
    edited 2013-09-13 09:24
    and now i have yanked my smd pcb out of my heli and tested its i2c (also pins 8 & 9) and it has a clean square wave on both pins, so i started over with it....

    Still same problems, no data, etc, etc.
  • zlantzzlantz Posts: 136
    edited 2013-09-14 13:33
    No other ideas as to why i am having these issuse with i2c? I even tried a differend propeller chip / pcb all together & still having same issues.

    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.
  • ChrisGaddChrisGadd Posts: 310
    edited 2013-09-14 18:01
    I noticed in your circuit layout that you're not using any bypass caps on the supply lines, might be a problem depending on how noisy your power supply is. Also noticed, before you changed the picture, that you only have a pull-up resistor on the SDA line to your EEPROM and not SCL, which is why my driver wouldn't work there. Did you have anything plugged into your I2C header when you were scoping the square waves? Check for shorts caused by incomplete etching between traces and shorts caused by soldering. Might have damaged it by soldering, but if you were using a low temperature it could also be a cold solder joint. As for testing the I2C bus, the I2C routines link in my sig contains a I2C slave demo that uses a master object in one cog to talk to a slave object running in another cog.
  • zlantzzlantz Posts: 136
    edited 2013-09-14 19:12
    Aye, yes, they are there, i have 2 caps on each vreg plus i put a cap directly on the bmp085 across the power connectors. my eeprom is following the propeller manual's method, one pullup of 10k on sda.

    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:
    {{
    &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
    &#9474; I2CScan 1.0                              &#9474;
    &#9474; Author: Tim Moore                        &#9474;               
    &#9474; Copyright (c) 2008> Tim Moore            &#9474;               
    &#9474; See end of file for terms of use.        &#9474;                
    &#9474; Based on code by James Burrows           &#9474;                
    &#9474;                                          &#9474;                
    &#9474; Modified to support SMBus timing         &#9474;                
    &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
    }}
    
    CON
      _clkmode = xtal1 + pll16x                  ' System clock &#8594; 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
    
    {{
    &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
    &#9474;                                                   TERMS OF USE: MIT License                                                  &#9474;                                                            
    &#9500;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9508;
    &#9474;Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation    &#9474; 
    &#9474;files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,    &#9474;
    &#9474;modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software&#9474;
    &#9474;is furnished to do so, subject to the following conditions:                                                                   &#9474;
    &#9474;                                                                                                                              &#9474;
    &#9474;The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.&#9474;
    &#9474;                                                                                                                              &#9474;
    &#9474;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE          &#9474;
    &#9474;WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR         &#9474;
    &#9474;COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,   &#9474;
    &#9474;ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                         &#9474;
    &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
    }}
    

    OScope i2c BMP085:


    BAROMETRO SCL:

    IMG_20130914_200627_757.jpg



    BAROMETRO SDA:

    IMG_20130914_200642_393.jpg



    i2cScan SCL:

    IMG_20130914_200744_234.jpg



    i2cScan SDA:

    IMG_20130914_200804_586.jpg





    OScope Readings i2c UnPlugged:

    BAROMETRO SDA Line (SCL was High 3.3v):
    IMG_20130914_195410_023.jpg



    read REGISTERS SDA line (SCL was High):
    IMG_20130914_195441_072.jpg



    i2cScan SCL:
    IMG_20130914_195542_643.jpg



    i2cScan SDA:
    IMG_20130914_195610_430.jpg
    1024 x 577 - 56K
    1024 x 577 - 52K
    1024 x 577 - 52K
    1024 x 577 - 53K
    1024 x 577 - 56K
    1024 x 577 - 50K
    1024 x 577 - 53K
    1024 x 577 - 54K
  • zlantzzlantz Posts: 136
    edited 2013-09-14 19:24
    Here is the Return from your i2c Slave Demo:

    PST Return.jpg
    903 x 686 - 87K
  • zlantzzlantz Posts: 136
    edited 2013-09-14 21:31
    So i re-tried the i2c Slave, but on pins 8 & 9 instead of the default 28 & 29 & it worked!!!! One step closer. I am about to solder a connecter onto the mpu-6050 board & see if it works with the i2c pasm driver. i have also a mpu-6050.spin that "should" work out of the box.

    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).

    PST Return 2.jpg
    907 x 687 - 77K
  • zlantzzlantz Posts: 136
    edited 2013-09-14 22:25
    MPU-6050 Works! just a little mod to the MPU-6050.spin i had found (had to change the address) and boom xyz accel & gyro data.

    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   496
    
    
  • zlantzzlantz Posts: 136
    edited 2014-04-03 12:33
    So after spending not just hours or days, but weeks trying to get this little module to output something worth a damn. It "kinda" works. It shows data, but the Temp & Pressure are constantly on the move, NEVER stationary. I have finally given up and decided to try the parallax altimeter module that supports the MS5607 pressure sensor.

    INSTANT 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.
  • ChrisGaddChrisGadd Posts: 310
    edited 2014-04-03 13:10
    Well, if you wanna give the BMP085 another go, the attached program gives me steady, believable readings, though I haven't yet monitored it to see how well it tracks.

    BMP085 demo - Archive.zip
Sign In or Register to comment.