Shop OBEX P1 Docs P2 Docs Learn Events
i2c Nothing Works!!! - Page 2 — Parallax Forums

i2c Nothing Works!!!

24

Comments

  • zlantzzlantz Posts: 136
    edited 2014-02-09 20:55
    T Chap wrote: »
    Why not read AA and AB in that order?

    AA AB
    AC AD
    AE AF

    ok then,
          ac1 := i2c.readLocation(bmpSCL, bmpAddr, $AA)  ' 1B
          ac1 |= i2c.readLocation(bmpSCL, bmpAddr, $AB) << 8  ' 1B
          ac2 := i2c.readLocation(bmpSCL, bmpAddr, $AC)  ' FB
          ac2 |= i2c.readLocation(bmpSCL, bmpAddr, $AD) << 8  ' FB
          ac3 := i2c.readLocation(bmpSCL, bmpAddr, $AE)  ' C7
          ac3 |= i2c.readLocation(bmpSCL, bmpAddr, $AF) << 8  ' C7
          ac4 := i2c.readLocation(bmpSCL, bmpAddr, $B0)  ' 84
          ac4 |= i2c.readLocation(bmpSCL, bmpAddr, $B1) << 8  ' 84
          ac5 := i2c.readLocation(bmpSCL, bmpAddr, $B2)  ' 61
          ac5 |= i2c.readLocation(bmpSCL, bmpAddr, $B3) << 8  ' 61
          ac6 := i2c.readLocation(bmpSCL, bmpAddr, $B4)  ' 49
          ac6 |= i2c.readLocation(bmpSCL, bmpAddr, $B5) << 8  ' 49
                 
          b1 := i2c.readLocation(bmpSCL, bmpAddr, $B6)   ' 19
          b1 |= i2c.readLocation(bmpSCL, bmpAddr, $B7) << 8   ' 19
          b2 := i2c.readLocation(bmpSCL, bmpAddr, $B8)   ' 00
          b2 |= i2c.readLocation(bmpSCL, bmpAddr, $B9) << 8   ' 00
                 
          mb := i2c.readLocation(bmpSCL, bmpAddr, $BA)   ' 80
          mb |= i2c.readLocation(bmpSCL, bmpAddr, $BB) << 8   ' 80
          mc := i2c.readLocation(bmpSCL, bmpAddr, $BC)   ' D1
          mc |= i2c.readLocation(bmpSCL, bmpAddr, $BD) << 8   ' D1
          md := i2c.readLocation(bmpSCL, bmpAddr, $BE)   ' 0A
          md |= i2c.readLocation(bmpSCL, bmpAddr, $BF) << 8   ' 0A
    

    results are identical to other method:

    new new other new values.jpg
    813 x 681 - 69K
  • T ChapT Chap Posts: 4,223
    edited 2014-02-09 21:11
    How do you know if the values are correct?
  • zlantzzlantz Posts: 136
    edited 2014-02-09 21:18
    T Chap wrote: »
    How do you know if the values are correct?

    that is what I would like to know. How am I suppose to know if the code is working right? The bmp's datasheet shows way different values for all of those that i get.
    bmp example.jpg
    1024 x 764 - 73K
  • T ChapT Chap Posts: 4,223
    edited 2014-02-09 21:25
    OK, MSB is first, so bitshift AA then OR AB. I have no idea what this module does. However, in that screenshot, I am not clear on whether you should be getting a signed value instead. Which would require something like AA bitshift left 24, the Shift Arithmetic Right 16. Then OR AB. Maybe someone else can give better advice on this.
          ac1 := i2c.readLocation(bmpSCL, bmpAddr, $AA)  <<  24' 1B
          ac1  ~>= 16   ' shift arith right
          ac1 |= i2c.readLocation(bmpSCL, bmpAddr, $AB)   ' 1B
    

    You will need to study the manual further to find out what is the purpose of the calibration data. My guess is that each module is calibrated with some baseline info stored for future use. In that screen shot, some of the values are not signed, so you can do what you were already doing on AC4 5 6 but correct the MSB/LSB thing.
    ac4 := i2c.readLocation(bmpSCL, bmpAddr, $B0) << 8
    ac4 |= i2c.readLocation(bmpSCL, bmpAddr, $B1)
  • Clive WakehamClive Wakeham Posts: 152
    edited 2014-02-09 21:27
    I had issues with a I2C device previously. Tried everything I knew and a few others. I thought maybe the device was faulty.
    I finally in the end got out a magnifying glass and looked at the markings on the case, and then realised that it wasn't the I2C device I thought it was, so I was addressing the wrong device.
    Somehow the distributor I was using sent me the wrong RTC, same manufacturer but different model, and of course different addresses, memory and functions.

    I had to re-do the whole Spin object I wrote to get it to work since the memory and functions were different.
    You live and learn.
  • zlantzzlantz Posts: 136
    edited 2014-02-09 22:06
    T Chap wrote: »
    OK, MSB is first, so bitshift AA then OR AB. I have no idea what this module does. However, in that screenshot, I am not clear on whether you should be getting a signed value instead. Which would require something like AA bitshift left 24, the Shift Arithmetic Right 16. Then OR AB. Maybe someone else can give better advice on this.
          ac1 := i2c.readLocation(bmpSCL, bmpAddr, $AA)  <<  24' 1B
          ac1  ~>= 16   ' shift arith right
          ac1 |= i2c.readLocation(bmpSCL, bmpAddr, $AB)   ' 1B
    

    You will need to study the manual further to find out what is the purpose of the calibration data. My guess is that each module is calibrated with some baseline info stored for future use. In that screen shot, some of the values are not signed, so you can do what you were already doing on AC4 5 6 but correct the MSB/LSB thing.
    ac4 := i2c.readLocation(bmpSCL, bmpAddr, $B0) << 8
    ac4 |= i2c.readLocation(bmpSCL, bmpAddr, $B1)

    ac1 becomes 7159 using your code above.
    ac4 becomes 33810

    as for the calibration data, it is used in the second part of the pressure & temp math to calculate the true temperature & true pressure, which is just simple math. i can follow that part fine.

    its just a matter of getting the right values from the device. the datasheet says the Chip ID is 0x55 and that is how you check that your communications are working properly.
  • Cluso99Cluso99 Posts: 18,069
    edited 2014-02-10 03:41
    @Cluso99: Don't start something you can't finish, there are too many things to point out that you may as well design a new pcb in the process :) Even the placement and designators of the connectors. Now if those with little pcb/hardware experience would post their proposed design to the forum beforehand then the design could be vetted and produced with some confidence.
    Better to mention some of ghe major problems than be silent, especially when they could be the cause.
    The eeprom is quite a forgiving chip, but analog chips are not so forgiving of poor designs including power.
    It is quite possible the problems are not software.
  • zlantzzlantz Posts: 136
    edited 2014-02-10 10:06
    Cluso99 wrote: »
    Better to mention some of ghe major problems than be silent, especially when they could be the cause.
    The eeprom is quite a forgiving chip, but analog chips are not so forgiving of poor designs including power.
    It is quite possible the problems are not software.

    Every Sensor I am using is Digital. I have an analog pressure sensor, but requires much higher voltages than my batteries supply (16 volts needed, only 7v available)

    I am pretty confident that it is in the software. My MPU-6050 works with a PASM i2c Driver 100%, but it dont work with the spin i2c driver.
  • JonnyMacJonnyMac Posts: 9,107
    edited 2014-02-10 10:58
    I am pretty confident that it is in the software. My MPU-6050 works with a PASM i2c Driver 100%, but it dont work with the spin i2c driver.

    Most I2C devices will tolerate clock speeds lower than their stated max (400kHz in this case) -- perhaps this is an exception.
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-02-10 11:22
    zlantz wrote: »
    Every Sensor I am using is Digital. I have an analog pressure sensor, but requires much higher voltages than my batteries supply (16 volts needed, only 7v available)

    I am pretty confident that it is in the software. My MPU-6050 works with a PASM i2c Driver 100%, but it dont work with the spin i2c driver.

    The interface is digital, but internally all of these sensors are analog and need a steady power supply. You are correct though that these modules mostly all have a power supply filter capacitor on board, so there is less need for you to include one outside. Extra never hurts.

    Power supply, a case in point. Last week I had to troubleshoot a system where the digital interface was working but the analog portion was not. Here is a 'scope shot of the i2c transaction. Lots of runt pulses. Even so, the i2c was reading and setting the internal registers. It turned out that there was a cold solder joint on the power pin to the chip (a tiny DFN), so the power to the chip was parasite power through the pullup resistors. A fine tip and solder corrected the problem.
    Upper red trace SDA, lower yellow trace SCL.
    D040.png



    A 'scope and a logic analyzer such as the #32314 Saleae that Parallax sells can be invaluable to see exactly what is going on.
    640 x 480 - 7K
  • zlantzzlantz Posts: 136
    edited 2014-02-10 16:27
    JonnyMac wrote: »
    I've done a bunch of projects with I2C, never having a lick of trouble.

    I agree with Peter that you may want stiffer pull-ups on your I2C buss with the devices being off-board.

    As you may not know Tachyon like Peter does, I wrote a little I2C scanner in Spin (that uses my driver). Running on the PAB the only device address that responds is the boot EEPROM ($A0). You don't have to use the EEPROM buss with my driver; you may specify any two pins.

    So I had success with your scanner in finding both the MPU & BMP on the same i2c bus, so I did a little code mod & added in the BMP_Read function. I believe the values are correct, (MB) is the same value as the datasheet & others are fairly close.

    A problem I think that is happening is how I merged the 3 values (up = up1 + up2 + up3). I dont quite understand bitshifting & the <<, >>, ~>=, etc. functions and how they are used to get the full 16 or 32 bit value into one (myVal).

    Also by using readlocation vs readlocation16 the ouptut values change completely.

    Here is what I did to the code:
    '' =================================================================================================
    ''
    ''   File....... jm_i2c_scan.spin
    ''   Purpose.... 
    ''   Author..... Jon "JonnyMac" McPhalen
    ''               Copyright (c) 2014 Jon McPhalen
    ''               -- see below for terms of use
    ''   E-mail..... jon@jonmcphalen.com
    ''   Started.... 
    ''   Updated.... 09 FEB 2014
    ''
    '' =================================================================================================
    
    
    con { timing }
    
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000                                          ' 5MHz crystal
    
      CLK_FREQ = ((_clkmode - xtal1) >> 6) * _xinfreq               ' system freq as a constant
      MS_001   = CLK_FREQ / 1_000                                   ' ticks in 1ms
      US_001   = CLK_FREQ / 1_000_000                               ' ticks in 1us
    
    
    con { io pins }
    
      RX1 = 31                                                      ' programming / terminal
      TX1 = 30
      
      SDA = 29                                                      ' eeprom / i2c
      SCL = 28
    
      MPUsda  = 8       ' All I2C Sensors on SAME Bus
      MPUscl  = 9
    
      BMPSCL   = 12   
      BMPSDA   = 13
    
      I2C_SDA = 10
      I2C_SCL = 11  
    
    con
    
      #0, LSBFIRST, MSBFIRST
      
    
    con { pst formatting }
    
       #1, HOME, GOTOXY, #8, BKSP, TAB, LF, CLREOL, CLRDN, CR
      #14, GOTOX, GOTOY, CLS
    
    
      bmpAddr = $EE
      mpuAddr = $D0
    
    obj
    
      term : "fullduplexserial"
      i2c  : "jm_i2c_Mod"
     
    
    var
    
     ' MPU-9150 $D0 %1101_0000
     ' BMP-180  $EE %1110_1110  
    
      long ac1, ac2, ac3, ac4, ac5, ac6, b1, b2, mb, mc, md, id
      long UT, UP, oss
     
    
    pub main | addr, check
    
      term.start(RX1, TX1, %0000, 115_200)
      i2c.setupx(I2C_SCL, I2C_SDA)
    
      ' open PST, enable, then press a key
      
      repeat
        term.rxflush
        term.rx
         
        'term.tx(CLS)
        term.str(string("I2C Scanner", CR, CR))
         
        repeat addr from %0000_0010 to %1111_1110 step %10            ' ignore r/w bit
          ihex2(addr)
          repeat 3
            term.tx(" ")
          ibin8(addr)
          repeat 3
            term.tx(" ")
            
          i2c.start
          check := i2c.write(addr)
          i2c.stop
          if (check == i2c#ACK)
            term.str(string("Yes", CR))
          else
            term.str(string("No", CR))
    
    
          if addr == $EE            ' BMP Found
            Read_BMP
    
          if addr == $D0            ' MPU Found
            Read_MPU
                          
          pause(50)
         
    
    Pri Read_BMP | v1, v2, v3, up1, up2, up3, ut1, ut2, read16
        
          {
          Table 5: Calibration Coefficients
                      BMP180 reg adr
          Parameter   MSB        LSB
            AC1       0xAA       0xAB
            AC2       0xAC       0xAD
            AC3       0xAE       0xAF
            AC4       0xB0       0xB1
            AC5       0xB2       0xB3
            AC6       0xB4       0xB5
            B1        0xB6       0xB7
            B2        0xB8       0xB9
            MB        0xBA       0xBB
            MC        0xBC       0xBD
            MD        0xBE       0xBF
          }
    
        ' i2c.readLocation(SCL,device_address, register)
    
        read16 := 0
        
        ' // Read Calibration Coefficients
        if read16 == 0
          ac1 := i2c.readLocation(bmpAddr, $AA) << 8 
          ac1 |= i2c.readLocation(bmpAddr, $AB)
    
          'ac1 := i2c.readLocation(bmpAddr, $AA)  <<  24
          'ac1  ~>= 16   ' shift arith right
          'ac1 |= i2c.readLocation(bmpAddr, $AB)   
          
          ac2 := i2c.readLocation(bmpAddr, $AC) << 8 
          ac2 |= i2c.readLocation(bmpAddr, $AD)  
          ac3 := i2c.readLocation(bmpAddr, $AE) << 8 
          ac3 |= i2c.readLocation(bmpAddr, $AF) 
    
          ac4 := i2c.readLocation(bmpAddr, $B0) << 8 
          ac4 |= i2c.readLocation(bmpAddr, $B1) 
          
          ac5 := i2c.readLocation(bmpAddr, $B2) << 8 
          ac5 |= i2c.readLocation(bmpAddr, $B3)  
          ac6 := i2c.readLocation(bmpAddr, $B4) << 8 
          ac6 |= i2c.readLocation(bmpAddr, $B5) 
                 
          b1 := i2c.readLocation(bmpAddr, $B6) << 8   
          b1 |= i2c.readLocation(bmpAddr, $B7) 
          b2 := i2c.readLocation(bmpAddr, $B8) << 8   
          b2 |= i2c.readLocation(bmpAddr, $B9) 
                 
          mb := i2c.readLocation(bmpAddr, $BA) << 8  
          mb |= i2c.readLocation(bmpAddr, $BB) 
          mc := i2c.readLocation(bmpAddr, $BC) << 8  
          mc |= i2c.readLocation(bmpAddr, $BD)    
          md := i2c.readLocation(bmpAddr, $BE) << 8  
          md |= i2c.readLocation(bmpAddr, $BF) 
    
        elseif read16 == 1
          ac1 := i2c.readLocation16(bmpAddr, $AA)  ' 1B
          ac2 := i2c.readLocation16(bmpAddr, $AC)  ' FB
          ac3 := i2c.readLocation16(bmpAddr, $AE)  ' C7
          ac4 := i2c.readLocation16(bmpAddr, $B0)  ' 84
          ac5 := i2c.readLocation16(bmpAddr, $B2)  ' 61
          ac6 := i2c.readLocation16(bmpAddr, $B4)  ' 49
           
          b1 := i2c.readLocation16(bmpAddr, $B6)   ' 19
          b2 := i2c.readLocation16(bmpAddr, $B8)   ' 00
           
          mb := i2c.readLocation16(bmpAddr, $BA)   ' 80
          mc := i2c.readLocation16(bmpAddr, $BC)   ' D1
          md := i2c.readLocation16(bmpAddr, $BE)   ' 0A
           
        id := i2c.readLocation(bmpAddr, $D0)   ' 55     *** Should = 0x55
         
        waitcnt((clkfreq / 4) + cnt)
    
        term.str(string("AC1: "))
        term.hex(ac1, 2)
        term.str(string("  "))
        term.dec(ac1)
        term.tx(13)
        term.str(string("AC2: "))
        term.hex(ac2, 2)
        term.str(string("  "))
        term.dec(ac2)    
        term.tx(13)
        term.str(string("AC3: "))
        term.hex(ac3, 2)
        term.str(string("  "))
        term.dec(ac3)    
        term.tx(13)
        term.str(string("AC4: "))
        term.hex(ac4, 2)
        term.str(string("  "))
        term.dec(ac4)    
        term.tx(13)
        term.str(string("AC5: "))
        term.hex(ac5, 2)
        term.str(string("  "))
        term.dec(ac5)    
        term.tx(13)
        term.str(string("AC6: "))
        term.hex(ac6, 2)
        term.str(string("  "))
        term.dec(ac6)    
        term.tx(13)                    
    
        term.str(string("B1: "))
        term.hex(b1, 2)
        term.str(string("  "))
        term.dec(b1)    
        term.tx(13)
        term.str(string("B2: "))
        term.hex(b2, 2)
        term.str(string("  "))
        term.dec(b2)    
        term.tx(13)
    
        term.str(string("MB: "))
        term.hex(mb, 2)
        term.str(string("  "))
        term.dec(mb)    
        term.tx(13)
        term.str(string("MC: "))
        term.hex(mc, 2)
        term.str(string("  "))
        term.dec(mc)    
        term.tx(13)
        term.str(string("MD: "))
        term.hex(md, 2)
        term.str(string("  "))
        term.dec(md)
        term.tx(13)        
    
        term.str(string("ID: "))
        term.hex(id, 2)
        term.str(string("  "))
        term.dec(id)    
        term.tx(13)
        
        'term.str(string("bmpAddr: "))
        'term.hex(bmpAddr | 1, 2)        ' 0 = EE, 1 = EF
        'term.tx(13)
        
        ' // Read Uncompressed Temperature Value
        ' Write 0x2E into reg 0xF4, wait 4.5ms
        ' Read reg 0xF6 (MSB), 0xF7 (LSB)
    
        i2c.writeLocation(bmpAddr, $F4, $2E)       ' Temperature  0x2E  4.5
        waitcnt((clkfreq / 222) + cnt)             ' 4.5ms
        ut1 := i2c.readLocation16(bmpAddr, $F6)
        ut2 := i2c.readLocation16(bmpAddr, $F7) 
    
        'UT := i2c.readLocation16(bmpAddr, i2c#OneAddr|$F6)
        UT := i2c.readLocation16(bmpAddr, $F6)
        
        term.str(string("UT: "))
        term.dec(UT)
        term.str(string("  "))
        term.hex(ut1, 2)
        term.str(string("  "))
        term.hex(ut2, 2)
        term.str(string("  "))    
        term.dec(ut1 + ut2)
        term.tx(13)
        
        ' // Read Uncompressed Pressure Value
        ' Write 0x34+(oss<<6) into reg 0xF4, wait #.#ms
        ' Read reg 0xF6 (MSB), 0xF7 (LSB), 0xF8 (XLSB)
    
        'i2c.writeLocation(bmpAddr, $F4, $34 + (oss<<6))
    
        ' i2c.readLocation(SCL,device_address, register)
        ' i2c.writeLocation(SCL,device_address, register, value) 
        
        if oss == 0
          i2c.writeLocation(bmpAddr, $F4, $34)     ' Pressure (oss = 0)  0x34  4.5
          waitcnt((clkfreq / 222) + cnt)                         ' 4.5ms    
        elseif oss == 1
          i2c.writeLocation(bmpAddr, $F4, $74)     ' Pressure (oss = 1)  0x74  7.5
          waitcnt((clkfreq / 133) + cnt)                         ' 7.5ms    
        elseif oss == 2
          i2c.writeLocation(bmpAddr, $F4, $B4)     ' Pressure (oss = 2)  0xB4  13.5
          waitcnt((clkfreq / 74) + cnt)                          ' 13.5ms   
        elseif oss == 3
          i2c.writeLocation(bmpAddr, $F4, $F4)     ' Pressure (oss = 3)  0xF4  25.5
          waitcnt((clkfreq / 39) + cnt)                          ' 25.5ms
    
        up1 := i2c.readLocation16(bmpAddr, $F6)
        up2 := i2c.readLocation16(bmpAddr, $F7)
        up3 := i2c.readLocation16(bmpAddr, $F8)         
        
        term.str(string("UP: "))
        term.hex(up1 + up2 + up3, 6)
        term.str(string("  "))
        term.dec(up1 + up2 + up3)    
        term.tx(13)
        term.str(string("UP 123 Hex: "))  
        term.hex(up1, 2)
        term.str(string("  "))
        term.hex(up2, 2)
        term.str(string("  "))
        term.hex(up3, 2)
        term.tx(13)        
        term.str(string("UP 123 Dec: "))  
        term.dec(up1)
        term.str(string("  "))
        term.dec(up2)
        term.str(string("  "))
        term.dec(up3)
        term.tx(13)        
    
    
        ' // Calculate True Temperature
    
        ' // Calculate True Pressure
    
    
        waitcnt(clkfreq + cnt)
    
        
    Pri Read_MPU
    
    con
    
      { ------------- }
      {  B A S I C S  }
      { ------------- }
    
    
    pub ihex2(value)
    
      term.tx("$")
      term.hex(value, 2)
    
    
    pub ibin8(value)
    
      term.tx("%")
      term.bin(value >> 4, 4)
      term.tx("_")
      term.bin(value & $0F, 4)
      
    
    con
    
      { ------------- }
      {  B A S I C S  }
      { ------------- }
    
    
    pub pause(ms) | t
    
    '' Delay program in milliseconds
    
      if (ms < 1)                                                   ' delay must be > 0
        return
      else
        t := cnt - 1776                                             ' sync with system counter
        repeat ms                                                   ' run delay
          waitcnt(t += MS_001)
        
    
    pub high(pin)
    
    '' Makes pin output and high
    
      outa[pin] := 1
      dira[pin] := 1
    
    
    pub low(pin)
    
    '' Makes pin output and low
    
      outa[pin] := 0
      dira[pin] := 1
    
    
    pub toggle(pin)
    
    '' Toggles pin state
    
      !outa[pin]
      dira[pin] := 1
    
    
    pub input(pin)
    
    '' Makes pin input and returns current state
    
      dira[pin] := 0
    
      return ina[pin]
    
    
    dat { license }
    
    {{
    
      Terms of Use: MIT License
    
      Permission is hereby granted, free of charge, to any person obtaining a copy of this
      software and associated documentation files (the "Software"), to deal in the Software
      without restriction, including without limitation the rights to use, copy, modify,
      merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
      permit persons to whom the Software is furnished to do so, subject to the following
      conditions:
    
      The above copyright notice and this permission notice shall be included in all copies
      or substantial portions of the Software.
    
      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
      INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
      PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
      HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
      CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
      OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    
    }}
    

    and
    '' =================================================================================================
    ''
    ''   File....... jm_i2c.spin
    ''   Purpose.... Low-level I2C routines (requires pull-ups on SCL and SDA)
    ''   Author..... Jon "JonnyMac" McPhalen
    ''               Copyright (c) 2009-2013 Jon McPhalen
    ''               -- elements inspired by code from Mike Green
    ''   E-mail.....  
    ''   Started.... 28 JUL 2009
    ''   Updated.... 07 APR 2013
    ''
    '' =================================================================================================
    
    
    con { fixed io pins }
    
      RX1    = 31                                                   ' programming / debug port
      TX1    = 30
      
      EE_SDA = 29                                                   ' eeprom
      EE_SCL = 28
    
     
    con
    
      #0, ACK, NAK
    
    
    var
    
      long  scl                                                     ' buss pins
      long  sda
        
    
    pub setup
    
    '' Setup I2C using Propeller EEPROM pins
    
      setupx(EE_SCL, EE_SDA)
             
    
    pub setupx(sclpin, sdapin)
    
    '' Define I2C SCL (clock) and SDA (data) pins
    
      longmove(@scl, @sclpin, 2)                                    '  copy pins
      dira[scl] := 0                                                '  float to pull-up
      outa[scl] := 0                                                '  write 0 to output reg
      dira[sda] := 0
      outa[sda] := 0
    
      repeat 9                                                      ' reset device
        dira[scl] := 1
        dira[scl] := 0
        if (ina[sda])
          quit
      
        
    pub wait(id) | ackbit
    
    '' Waits for I2C device to be ready for new command
    
      repeat
        start
        ackbit := write(id)
      until (ackbit == ACK)
    
    
    pub start
    
    '' Create I2C start sequence
    '' -- will wait if I2C buss SDA pin is held low
    
      dira[sda] := 0                                                ' float SDA (1)
      dira[scl] := 0                                                ' float SCL (1)
      repeat while (ina[scl] == 0)                                  ' allow "clock stretching"
    
      dira[sda] := 1                                                ' SDA low (0)
      dira[scl] := 1                                                ' SCL low (0)
    
      
    pub write(i2cbyte) | ackbit
    
    '' Write byte to I2C buss
    '' -- leaves SCL low
    
      i2cbyte := (i2cbyte ^ $FF) << 24                              ' move msb (bit7) to bit31
      repeat 8                                                      ' output eight bits
        dira[sda] := i2cbyte <-= 1                                  ' send msb first
        dira[scl] := 0                                              ' SCL high (float to p/u)
        dira[scl] := 1                                              ' SCL low
    
      dira[sda] := 0                                                ' relase SDA to read ack bit
      dira[scl] := 0                                                ' SCL high (float to p/u)  
      ackbit := ina[sda]                                            ' read ack bit
      dira[scl] := 1                                                ' SCL low
    
      return (ackbit & 1)
    
    
    pub read(ackbit) | i2cbyte
    
    '' Read byte from I2C buss
    
      dira[sda] := 0                                                ' make sda input
    
      repeat 8
        dira[scl] := 0                                              ' SCL high (float to p/u)
        i2cbyte := (i2cbyte << 1) | ina[sda]                        ' read the bit
        dira[scl] := 1                                              ' SCL low
                                 
      dira[sda] := !ackbit                                          ' output ack bit 
      dira[scl] := 0                                                ' clock it
      dira[scl] := 1
    
      return (i2cbyte & $FF)
    
    
    pub stop
    
    '' Create I2C stop sequence 
    
      dira[sda] := 1                                                ' SDA low
      dira[scl] := 0                                                ' float SCL
      repeat
      until (ina[scl] == 1)                                         ' hold for clock stretch
      
      dira[sda] := 0                                                ' float SDA
    
    
     ' // -------------------- Extras --------------------
    
     
    PUB ReStart                ' SDA goes HIGH to LOW with SCL HIGH
       outa[SDA]~~                         ' Initially drive SDA HIGH
       dira[SDA]~~
       outa[SCL]~~                         ' Initially drive SCL HIGH
       'waitcnt(clkfreq / I2CDelay + cnt)
       outa[SDA]~                          ' Now drive SDA LOW
       'waitcnt(clkfreq / I2CDelay + cnt)
       outa[SCL]~                          ' Leave SCL LOW
    
    PUB devicePresent(deviceAddress) : ackbit
      ' send the deviceAddress and listen for the ACK
       Start
       ackbit := Write(deviceAddress | 0)
       Stop
       if ackbit == ACK
         return true
       else
         return false
    
    PUB readLocation(device_address, register) : value
        start                    ' 1. Send a start sequence
        write(device_address | 0) ' 2. Send 0xC0 ( I2C address of the CMPS03 with the R/W bit low (even address)
        write(register)           ' 3. Send 0x01 (Internal address of the bearing register)  
        start                    ' 4. Send a start sequence again (repeated start) 
        write(device_address | 1) ' 5. Send 0xC1 ( I2C address of the CMPS03 with the R/W bit high (odd address) 
        value := read(NAK)        ' 6. Read data byte from CMPS03 
        stop                     ' 7. Send the stop sequence. 
        return value                  ' ^- Copied From (http://www.robot-electronics.co.uk/acatalog/I2C_Tutorial.html)
         
    PUB writeLocation(device_address, register, value)
        start                    ' 1. Send a start sequence         
        write(device_address)     ' 2. Send the I2C address of the slave with the R/W bit low (even address) 
        write(register)           ' 3. Send the internal register number you want to write to     
        write(value)              ' 4. Send the data byte      5. [Optionally, send any further data bytes]                   
        stop                     ' 6. Send the stop sequence.
            
    PUB readLocation16(device_address, register) : value
        start
        write(device_address | 0)
        write(register)
        restart
        write(device_address | 1)  
    
        'value := read(SCL,ACK)
        'value <<= 8
    
        value := read(ACK)
        value |= read(ACK) << 8
    
        'readkeyvar := i2c2.i2cRead(i2cSCL2, 0)        'read first bit field 0 - 7
        'readkeyvar |= i2c2.i2cRead(i2cSCL2, 0) << 8   'read second bit field 8 - 15
            
        value |= (read(NAK) & $ff)
        stop
        return value
         
    PUB readLocation24(device_address, register) : value
        start
        write(device_address | 0)
        write(register)
        restart
        write(device_address | 1)  
        value := read(ACK)
        value <<= 8
        value |= (read(ACK) & $ff)
        value <<= 8
        value |= (read(NAK) & $ff)
        stop
        return value
         
      
    
    dat
    
    {{
    
      Terms of Use: MIT License
    
      Permission is hereby granted, free of charge, to any person obtaining a copy of this
      software and associated documentation files (the "Software"), to deal in the Software
      without restriction, including without limitation the rights to use, copy, modify,
      merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
      permit persons to whom the Software is furnished to do so, subject to the following
      conditions:
    
      The above copyright notice and this permission notice shall be included in all copies
      or substantial portions of the Software.
    
      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
      INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
      PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
      HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
      CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
      OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
    
    }}
    

    and the results for the BMP test, which appear correct (assuming).

    you can see it detected both sensors fine ($D0 & $EE):
    jmac 2 sens.jpg
    807 x 976 - 93K
  • zlantzzlantz Posts: 136
    edited 2014-02-10 16:43
    I have a uni-t scope & 2 logic analyzers (that dont work (no software to support them)).

    I know I am having power issues on that pcb. in fact, it just went on the fritz this morning and will program the eeprom fine, but the output is about 1 time every 3 seconds, and the data is all 0's. But when I scoped the power rail its a good clean 3.30v.

    I have a second pcb that I have switched to for testing the i2c sensors.

    Edit: Now that I have switched to new pcb, I am able to get values from the MPU-9150 using the mpu6050 driver! Thanks to JonnyMac for an extremely simple i2c driver & i2c Scanner... I just modified the scanner code to read the sensors when they were detected. The Power issue quite probibly was the culpret.
  • Cluso99Cluso99 Posts: 18,069
    edited 2014-02-10 17:38
    Good news. You may recall I noticed your board did not have power connected to one of the 4 prop power pins - the one next to the xtal. Have you fixed this? This is extremely important - you can kill the props PLL (and perhaps other problems) if all 4 power and ground pins of the prop are not connected properly, and decoupled properly.
  • zlantzzlantz Posts: 136
    edited 2014-02-10 17:50
    Cluso99 wrote: »
    Good news. You may recall I noticed your board did not have power connected to one of the 4 prop power pins - the one next to the xtal. Have you fixed this? This is extremely important - you can kill the props PLL (and perhaps other problems) if all 4 power and ground pins of the prop are not connected properly, and decoupled properly.

    Yes, my other pcb the VCC next to xtal is connected, however, due to the fact that I am not ordering my pcb's but etching myself, I have found it difficult to pack everything on the pcb & still connect all 4 power connections. 3 has been typical, but with the xtal vcc connected. I have been assuming it is fine being that they are internally connected. I have updated my pcb in DipTrace now.
  • Cluso99Cluso99 Posts: 18,069
    edited 2014-02-11 05:15
    zlantz wrote: »
    Yes, my other pcb the VCC next to xtal is connected, however, due to the fact that I am not ordering my pcb's but etching myself, I have found it difficult to pack everything on the pcb & still connect all 4 power connections. 3 has been typical, but with the xtal vcc connected. I have been assuming it is fine being that they are internally connected. I have updated my pcb in DipTrace now.
    IT IS NOT FINE IF ALL 4 POWER PINS ARE NOT CONNECTED TOGETHER. SAME APPLIES TO THE 4 GROUND PINS. AND THEY MUST HAVE DECOUPLING CAPACITORS AS CLOSE TOTHE PINS AS POSSIBLE. This isn't an option,it's mandatory. Otherwise you willget unpredictable results.

    You aregetting unpredictable results, so fixthis first before you damage the prop chip, providing you haven't already!
  • zlantzzlantz Posts: 136
    edited 2014-02-11 10:34
    Cluso99 wrote: »
    IT IS NOT FINE IF ALL 4 POWER PINS ARE NOT CONNECTED TOGETHER. SAME APPLIES TO THE 4 GROUND PINS. AND THEY MUST HAVE DECOUPLING CAPACITORS AS CLOSE TOTHE PINS AS POSSIBLE. This isn't an option,it's mandatory. Otherwise you willget unpredictable results.

    Im a little confused as to why parallax dont follow this procedure too well they own selves then.

    I do have an old prop demo board that has since died, and I have based my circuits on its circuit:

    http://www.rayslogic.com/propeller/DemoSched.gif

    There is only one capacitor as close to the pins as possible and that is the 1uf across the vdd & gnd with boen & resn in between them, other than that, there is only 1 more cap connected to the prop chip and that is over on the power supply's output, far from the chip.

    http://www.rayslogic.com/propeller/DemoPhoto.jpg

    The only thing I have done different is leave one power pin unconnected.
  • JonnyMacJonnyMac Posts: 9,107
    edited 2014-02-11 10:49
    The only thing I have done different is leave one power pin unconnected.


    While there are missing decoupling caps on the Demo Board, all of the the power pins are connected.

    I'm sure you're frustrated at the moment -- best to let go of that and just follow the good guidance you're getting: decoupling caps on EVERY IC (don't count on what others have or have not done), and make sure all power connections are in fact connected.

    Parallax promted the QuickStart board as a reference design; note that it has bypass caps on on power connections to the Propeller. There isn't one on the EEPROM, probably because it is so close to the cap on one side of the Propeller.
  • zlantzzlantz Posts: 136
    edited 2014-02-11 14:09
    JonnyMac wrote: »
    I'm sure you're frustrated at the moment -- best to let go of that and just follow the good guidance you're getting

    As frustrating as it is, I am doing just that. I have updated my pcb design with caps & all power's connected. I have also added resistors inline to all of my servo io's.

    I came across this today:

    http://longhornengineer.com/github/Appnotes_Propeller_LQFP-QFN-44/Layout.png

    I am going to update my pcb's to this basic layout, it looks like a winner.


    As for my sensors, I spent many hours last night reading the datasheet and trying relentlessly to get the mpu-9150 to give me the magnetometer data. I can follow the mpu6050 pasm driver (tho i dont know pasm at all) well enough to add config settings that are not currently available, and how the read sensors method works. But I have no clue how to retrieve the data that is being passed around in the asm code. I would like to be able to connect a bmp085/bmp180 and/or HMC5883 to the aux cl/da lines & read it with the mpu (master mode), then read the data from ext_sens_00 threw ext_sens_11 registers, which are sequential from the accelerometer (gyro - temp - accel - mag - bmp).
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2014-02-11 14:50
    zlantz wrote: »
    As frustrating as it is, I am doing just that. I have updated my pcb design with caps & all power's connected. I have also added resistors inline to all of my servo io's.

    I came across this today:

    http://longhornengineer.com/github/Appnotes_Propeller_LQFP-QFN-44/Layout.png

    I am going to update my pcb's to this basic layout, it looks like a winner.


    As for my sensors, I spent many hours last night reading the datasheet and trying relentlessly to get the mpu-9150 to give me the magnetometer data. I can follow the mpu6050 pasm driver (tho i dont know pasm at all) well enough to add config settings that are not currently available, and how the read sensors method works. But I have no clue how to retrieve the data that is being passed around in the asm code. I would like to be able to connect a bmp085/bmp180 and/or HMC5883 to the aux cl/da lines & read it with the mpu (master mode), then read the data from ext_sens_00 threw ext_sens_11 registers, which are sequential from the accelerometer (gyro - temp - accel - mag - bmp).

    That pcb layout looks too basic, for instance it has the big pad under the chip that is grounded yet none of the Prop's grounds connect directly to it? Of course it's not a real design, it doesn't have any I/O connected etc. The other issue I have with many designs is the insistence in using big gull wing HC49 crystals, this is the most sensitive part of any design and it's hung out like a mainsail. There are plenty of cheap cylindrical and proper SMD crystals that do not cause this problem. BTW, as I said previously, a little Forth would have solved your little problem in very little time...... however this course has proved far more entertaining.
  • Duane C. JohnsonDuane C. Johnson Posts: 955
    edited 2014-02-11 15:52
    Hi Peter;
    That pcb layout looks too basic, for instance it has the big pad under the chip that is grounded yet none of the Prop's grounds connect directly to it?
    Actually that square in the center is connected to the nearly full ground plane.
    The top layer is RED and the bottom layer is GREEN.
    A combination of the top and bottom layers form a nearly full ground plane.
    The top is stitched to the bottom by a bunch of vias.

    Duane J
  • zlantzzlantz Posts: 136
    edited 2014-02-11 15:57
    as I said previously, a little Forth would have solved your little problem in very little time...... however this course has proved far more entertaining.

    I am self-taught hobbyist entrepreneur. I haven't had any formal classes on electronics either, tho I should have & had the chances. I am aware pretty much every design I have needs some updates, and I try to fix them as I become aware of them. So thanks for all the input on things that need fixed, it is greatly appreciated. I have learned more from my own errors than anything else.

    It is entertaining for me as well, as not being schooled in electronics, this is an excellent learning experience. How could one learn anything without first trying?
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2014-02-11 16:42
    Hi Peter;
    Actually that square in the center is connected to the nearly full ground plane.
    The top layer is RED and the bottom layer is GREEN.
    A combination of the top and bottom layers form a nearly full ground plane.
    The top is stitched to the bottom by a bunch of vias.

    Duane J

    The top layer fill inside/under the Prop is connected to ground on the bottom plane but the ground pins from the Prop should/could be connected to the fill directly.
    Here's an example of a complete PCB to illustrate what I tend to do.
    FSR PCB.png

    In this case this PCB is fairly compact and I have elected to have the center fill connected to VDD and the bottom plane to ground.
    1013 x 932 - 63K
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2014-02-11 16:52
    zlantz wrote: »
    I am self-taught hobbyist entrepreneur. I haven't had any formal classes on electronics either, tho I should have & had the chances. I am aware pretty much every design I have needs some updates, and I try to fix them as I become aware of them. So thanks for all the input on things that need fixed, it is greatly appreciated. I have learned more from my own errors than anything else.

    It is entertaining for me as well, as not being schooled in electronics, this is an excellent learning experience. How could one learn anything without first trying?
    Exactly, so we have to be ready to try things that we don't know. I come across problems like this all the time and I just know that before I had a Forth for the Prop that many things would not work and it wasn't easy to find out exactly why not or what it "saw". Forth is not just a language, it's the whole interactive operating environment for and on the Prop, it's my eyes and ears, my tools, which makes very short work of any annoying problems such as you have been facing.

    The "entertaining" thing is a little bit of a dig I admit at conventional means vs this unconventional means and how much it has dragged out. It's a bit like batch processing with punched cards, submitting them and getting the results back that don't work but still scratching your head as to why vs an interactive real-time terminal. Yes, we interact with the PC when we use a conventional compiler but the "punched cards" that it produces doesn't interact with us.
  • Cluso99Cluso99 Posts: 18,069
    edited 2014-02-11 17:39
    The sample layout you referenced does not have a ground connected next to the xtal. Since this is a general layout, that may be ok, but it's a mandatory connection for the prop. This is a major bug!!!

    I place a ground plane/layer under the prop connecting to all 4 prop ground pins. I place a 3v3 plane on the underside of the pcb under the prop with 4 100nF caps for decoupling. The 3v3 is fed via a single point which has a 10uF bulk cap between it and the ground feed. I also have a ground plane under the xtal, connected to the ground pin beside the xtal. This ground plane is isolated from the rest of the ground plane. This circuit reliably overclocks to 104MHz and I have tested to ~112MHz.

    Currently you have way too many unknowns. You have to ensure the basics are met first. Otherwise you will go round endless circles and ultimately give up, which would be a bad thing. Obviously you have to take suggestions and weed them out. Some of them will be misleading, and some plain wrong. You have to decide which order to test. And that is part of learning too.

    Do you have a DIP Prop? If so, then it is easy to put one on a breadboard to start with. Put a 100nF (0.1uF) and a 10uF tantalum across each set of power pins. Connect BOE, and a xtal, and 3v3 and you have a reliable circuit to begin experimenting with. Now you can plug in your various I2C board and test them. Just download with a propplug (no need for an eeprom). If you don't have a propplug but have a USB to serial (TTL) dongle, you can add the additional resistors, cap and transistor to your breadboard.
  • zlantzzlantz Posts: 136
    edited 2014-02-11 18:37
    Cluso99 wrote: »
    The sample layout you referenced does not have a ground connected next to the xtal. Since this is a general layout, that may be ok, but it's a mandatory connection for the prop. This is a major bug!!!

    I place a ground plane/layer under the prop connecting to all 4 prop ground pins. I place a 3v3 plane on the underside of the pcb under the prop with 4 100nF caps for decoupling. The 3v3 is fed via a single point which has a 10uF bulk cap between it and the ground feed. I also have a ground plane under the xtal, connected to the ground pin beside the xtal. This ground plane is isolated from the rest of the ground plane. This circuit reliably overclocks to 104MHz and I have tested to ~112MHz.

    Currently you have way too many unknowns. You have to ensure the basics are met first. Otherwise you will go round endless circles and ultimately give up, which would be a bad thing. Obviously you have to take suggestions and weed them out. Some of them will be misleading, and some plain wrong. You have to decide which order to test. And that is part of learning too.

    Do you have a DIP Prop? If so, then it is easy to put one on a breadboard to start with. Put a 100nF (0.1uF) and a 10uF tantalum across each set of power pins. Connect BOE, and a xtal, and 3v3 and you have a reliable circuit to begin experimenting with. Now you can plug in your various I2C board and test them. Just download with a propplug (no need for an eeprom). If you don't have a propplug but have a USB to serial (TTL) dongle, you can add the additional resistors, cap and transistor to your breadboard.


    The missing power connection is the +3.3v next to the xtal (on that design & fixed in latest), also, there is a copper pour that is on the pcb that is not in the picture.

    I do have a few dip prop's laying around, however, I would still have to etch a pcb to use it. It will be just as easy to etch a smd pcb that can be used as well as tested with, and will save a few $$$ in materials. The latest will use 2 prop chips that talk to eachother via 2-wire serial (100% working already).

    As for testing, I am using a different pcb now that has been upgraded from this one. Resistors on io's & extra caps on power pins. One power pin is still not connected (Pin 18 VCC) (the whole side of the ic is not used) & will be fixed on all future pcb's. (the down-side to learning from experience)
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2014-02-11 19:22
    That "reference" pcb seems to have been updated with the ground connection on pin 27 but seems to have missed the point of why bypass caps might be necessary. The tiny 0402 bypass cap C3 which is connected to pin 30 seems to have it's connection to pin 27 all up around the crystal rather than direct through the ground plane and the center pad has not been utilized either. In all reality you would only need one bypass cap if all Prop power and ground pins had an intimate connection but because in many designs they don't then that is why it is "recommended" to use one on each side. Far better that it had the grounds connected to that center pad then dot the I's and cross the T's and make no sense.
  • Duane C. JohnsonDuane C. Johnson Posts: 955
    edited 2014-02-11 19:51
    Hi Peter;
    The top layer fill inside/under the Prop is connected to ground on the bottom plane but the ground pins from the Prop should/could be connected to the fill directly.
    Yes, I agree totally.
    While that wasn't a bad board it certainly could have benefited by the extra direct connection of the grounds to that center square fill.

    Duane J
  • zlantzzlantz Posts: 136
    edited 2014-02-11 20:19
    Hi Peter;
    Yes, I agree totally.
    While that wasn't a bad board it certainly could have benefited by the extra direct connection of the grounds to that center square fill.

    Duane J

    This is how I have done it with my other pcb's. I just dont have an image of them right at the moment so I snatched one off the internet.
  • r.daneelr.daneel Posts: 96
    edited 2014-02-11 23:28
    The top layer fill inside/under the Prop is connected to ground on the bottom plane but the ground pins from the Prop should/could be connected to the fill directly.

    Why is that? Aren't they connected to ground anyway? Why do they need to be connected to the fill directly? This is a genuine question - I'm a software person and only have a superficial understanding of electronics. Isn't ground ground? Or is there a problem with long(ish) traces (or wires) to ground?
  • Cluso99Cluso99 Posts: 18,069
    edited 2014-02-12 01:02
    zlantz wrote: »
    ...
    As for testing, I am using a different pcb now that has been upgraded from this one. Resistors on io's & extra caps on power pins. One power pin is still not connected (Pin 18 VCC) (the whole side of the ic is not used) & will be fixed on all future pcb's. (the down-side to learning from experience)
    Am I wasting my time??? Don't you get it - you MUST HAVE ALL 4 POWER PINS CONNECTED TOGETHER, AND ALL 4 GROUND PINS CONNECTED !!! Run a wire link.
Sign In or Register to comment.