Shop OBEX P1 Docs P2 Docs Learn Events
OSEPP Compass on Propeller I2C — Parallax Forums

OSEPP Compass on Propeller I2C

waymond91waymond91 Posts: 15
edited 2013-02-26 13:19 in Propeller 1
Hello All!
I have an OSEPP brand compass module (based of HMC5883L chip) that I need to connect to the propeller quick start via the I2C bus. Osepp has a demo code for the arduino <wire.h> library here :

http://osepp.com/learning-centre/start-here/compass-sensor-module/

Looks like this code simply writes bytes to specific registers within the sensor to set it in different modes and to read the compass values. I am using the Basic_I2C_Driver from the the i2cobject version 2 to communicate with the compass:

http://obex.parallax.com/objects/251/

Now when I look at the propeller quickstart board pinout, it seems like SCL is on 29, and SDA is on 28 (which does not agree with the i2c object). But when I used the i2c bus to communicate with altimeter module it seemed to work with SDA on 29 and SLC on 28. So I suppose this is correct.

quickstart_pinout.PNG


When I ran the demo app (included with the object above ^^^) with the default pins (SDA on 29, SCL on 28) it reported that it detected two I2C objects(I don't know why two, maybe the eeprom on the baord?? it did run through an eeprom demo). So it seems as though it found my compass somehow.

However, when I run this simple test, the propeller always reports the compass as missing:
CON
  _clkmode      = xtal1 + pll16x
  _xinfreq      = 5_000_000
    
  i2cSCL        = 28
'  i2cSDA        = 29 


  COMPASS  = $1E


' debug - USE onboard pins
  pcDebugRX       = 31
  pcDebugTX       = 30


  ' serial baud rates  
  pcDebugBaud     = 115200    
  
VAR
  long  i2cAddress, i2cSlaveCounter


OBJ
  i2cObject      : "basic_i2c_driver"
  debug          : "Debug_PC"


pub Start
    ' start the PC debug object
    debug.startx(pcDebugRX,pcDebugTX,pcDebugBaud)
  
    ' setup i2cobject
    i2cObject.Initialize(i2cSCL)


    ' pause 5 seconds
    repeat 10
        debug.putc(".")
        waitcnt((clkfreq/2)+cnt)
    debug.putc(13)
  
    ' i2c state
    debug.strln(string("I2C Demo (v2)!"))


    if i2cObject.devicePresent(i2cSCL,COMPASS) == true
       debug.strln(string("COMPASS Present"))
    else
       debug.strln(string("COMPASS Missing"))      
       waitcnt(clkfreq*3+cnt)

I know this address is correct because I have had this module working on the arduino and beaglebone before. I have tried this configuration with and without 4.7k pullup resistors on the SCL and SDA lines. Maybe I need to configure the chip into continous write mode before I can sense it on the i2c bus??? I am not sure.

It seems to write a byte on the i2c bus using this object I simply need to pass it the (scl line, device address, the register address)?

Just to make referencing a little easier I will include the basic_i2c_driver object :
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


PUB Initialize(SCL) | SDA              ' An I2C device may be left in an
   SDA := SCL + 1                      '  invalid state and may need to be
   outa[SCL] := 1                       '   reinitialized.  Drive SCL high.
   dira[SCL] := 1
   dira[SDA] := 0                       ' Set SDA as input
   repeat 9
      outa[SCL] := 0                    ' Put out up to 9 clock pulses
      outa[SCL] := 1
      if ina[SDA]                      ' Repeat if SDA not driven high
         quit                          '  by the EEPROM


PUB Start(SCL) | SDA                   ' SDA goes HIGH to LOW with SCL HIGH
   SDA := SCL + 1
   outa[SCL]~~                         ' Initially drive SCL HIGH
   dira[SCL]~~
   outa[SDA]~~                         ' Initially drive SDA HIGH
   dira[SDA]~~
   outa[SDA]~                          ' Now drive SDA LOW
   outa[SCL]~                          ' Leave SCL LOW
  
PUB Stop(SCL) | SDA                    ' SDA goes LOW to HIGH with SCL High
   SDA := SCL + 1
   outa[SCL]~~                         ' Drive SCL HIGH
   outa[SDA]~~                         '  then SDA HIGH
   dira[SCL]~                          ' Now let them float
   dira[SDA]~                          ' If pullups present, they'll stay HIGH


PUB Write(SCL, data) : ackbit | SDA
'' Write i2c data.  Data byte is output MSB first, SDA data line is valid
'' only while the SCL line is HIGH.  Data is always 8 bits (+ ACK/NAK).
'' SDA is assumed LOW and SCL and SDA are both left in the LOW state.
   SDA := SCL + 1
   ackbit := 0 
   data <<= 24
   repeat 8                            ' Output data to SDA
      outa[SDA] := (data <-= 1) & 1
      outa[SCL]~~                      ' Toggle SCL from LOW to HIGH to LOW
      outa[SCL]~
   dira[SDA]~                          ' Set SDA to input for ACK/NAK
   outa[SCL]~~
   ackbit := ina[SDA]                  ' Sample SDA when SCL is HIGH
   outa[SCL]~
   outa[SDA]~                          ' Leave SDA driven LOW
   dira[SDA]~~


PUB Read(SCL, ackbit): data | SDA
'' Read in i2c data, Data byte is output MSB first, SDA data line is
'' valid only while the SCL line is HIGH.  SCL and SDA left in LOW state.
   SDA := SCL + 1
   data := 0
   dira[SDA]~                          ' Make SDA an input
   repeat 8                            ' Receive data from SDA
      outa[SCL]~~                      ' Sample SDA when SCL is HIGH
      data := (data << 1) | ina[SDA]
      outa[SCL]~
   outa[SDA] := ackbit                 ' Output ACK/NAK to SDA
   dira[SDA]~~
   outa[SCL]~~                         ' Toggle SCL from LOW to HIGH to LOW
   outa[SCL]~
   outa[SDA]~                          ' Leave SDA driven LOW


PUB ReadPage(SCL, devSel, addrReg, dataPtr, count) : ackbit
'' Read in a block of i2c data.  Device select code is devSel.  Device starting
'' address is addrReg.  Data address is at dataPtr.  Number of bytes is count.
'' The device select code is modified using the upper 3 bits of the 19 bit addrReg.
'' Return zero if no errors or the acknowledge bits if an error occurred.
   devSel |= addrReg >> 15 & 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)          
   Start(SCL)                          ' Reselect the device for reading
   ackbit := (ackbit << 1) | Write(SCL, devSel | Recv)
   repeat count - 1
      byte[dataPtr++] := Read(SCL, ACK)
   byte[dataPtr++] := Read(SCL, NAK)
   Stop(SCL)
   return ackbit


PUB ReadByte(SCL, devSel, addrReg) : data
'' Read in a single byte of i2c data.  Device select code is devSel.  Device
'' starting address is addrReg.  The device select code is modified using the
'' upper 3 bits of the 19 bit addrReg.  This returns true if an error occurred.
   if ReadPage(SCL, devSel, addrReg, @data, 1)
      return -1


PUB ReadWord(SCL, devSel, addrReg) : data
'' Read in a single word of i2c data.  Device select code is devSel.  Device
'' starting address is addrReg.  The device select code is modified using the
'' upper 3 bits of the 19 bit addrReg.  This returns true if an error occurred.
   if ReadPage(SCL, devSel, addrReg, @data, 2)
      return -1


PUB ReadLong(SCL, devSel, addrReg) : data
'' Read in a single long of i2c data.  Device select code is devSel.  Device
'' starting address is addrReg.  The device select code is modified using the
'' upper 3 bits of the 19 bit addrReg.  This returns true if an error occurred.
'' Note that you can't distinguish between a return value of -1 and true error.
   if ReadPage(SCL, devSel, addrReg, @data, 4)
      return -1


PUB WritePage(SCL, devSel, addrReg, dataPtr, count) : ackbit
'' Write out a block of i2c data.  Device select code is devSel.  Device starting
'' address is addrReg.  Data address is at dataPtr.  Number of bytes is count.
'' The device select code is modified using the upper 3 bits of the 19 bit addrReg.
'' Most devices have a page size of at least 32 bytes, some as large as 256 bytes.
'' Return zero if no errors or the acknowledge bits if an error occurred.  If
'' more than 31 bytes are transmitted, the sign bit is "sticky" and is the
'' logical "or" of the acknowledge bits of any bytes past the 31st.
   devSel |= addrReg >> 15 & 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)
  start(SCL)
  write(SCL,device_address | 1)  
  value := read(SCL,NAK)
  stop(SCL)
  return value     

Any clues as to what I am doing wrong???
Thanks
465 x 211 - 129K
Sign In or Register to comment.