OSEPP Compass on Propeller I2C
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.

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:
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 :
Any clues as to what I am doing wrong???
Thanks
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.

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
