' ============================================================================ ' ' File...... SCP1000_test_baro_loop.BS2 ' Purpose... Test function of SCP1000 barometric pressure sensor ' Author.... Paul Hopkins ' E-mail.... ' Started... ' Updated... 09 Nov 2007 ' ' {$STAMP BS2} ' {$PBASIC 2.5} ' ' ============================================================================== ' ' ------------------------------------------------------------------------------ ' Program Description ' ------------------------------------------------------------------------------ ' ' This version initializes the sensor and reads the temperature and pressure ' ' This program tests the SCP1000 barometric pressure sensor from www.vti.fi. ' Sparkfun Electronics (www.sparkfun.com) sells a breakout board with the sensor ' mounted. I used the 3.3v to 5v interface kit from Kronos Robotics to connect ' it to the stamp. ' ' The logic and code was adapted from VTI Technologies Technical Note 46 ' TN46 "C-Code Example For SCP1000-D01 Pressure Sensor" ' ' ------------------------------------------------------------------------------ ' I/O Definitions ' ------------------------------------------------------------------------------ SCK CON 4 ' SCP1000 SPI clock MOSI CON 5 ' SCP1000 Master Out Slave In MISO CON 6 ' SCP1000 Master in Slave Out CSB CON 7 ' SCP1000 SPI Chip Select ' ------------------------------------------------------------------------------ ' Constants ' ------------------------------------------------------------------------------ ' SCP1000 register values with r/w & zero bits RevID CON $00 ' RevID register (read) DataWR CON $01 ' Indirect reg access data (read/write) ADDPtr CON $02 ' Indirect reg access pointer (read/write) Oper CON $03 ' Operation register (read/write) OpStat CON $04 ' Operation status (read/write) Rstr CON $06 ' ASIC software reset (write) Status CON $07 ' ASIC top-level status (read) DataRd8 CON $1F ' Pressure output data (MSB 8-bit) or ' 8-bit data read from EEPROM (read) DataRd16 CON $20 ' Pressure output data (LSB 16-bit) or ' 8-bit data read from indirect reg (read) TempOut CON $21 ' 14-bit temperature output data (read) Cfg CON $00 ' Config register-indirect (read/write) Cfg2 CON $09 ' MISO config (read/write) ' only for SCP1000-D01 ModTest2 CON $2D ' Noise level config - indirect (write) UsrData1 CON $29 ' User Data EEPROM indirect (read/write) UsrData2 CON $2A ' User Data EEPROM indirect (read/write) UsrData3 CON $2B ' User Data EEPROM indirect (read/write) UsrData4 CON $2C ' User Data EEPROM indirect (read/write) Yes CON 1 No CON 0 ' ------------------------------------------------------------------------------ ' Variables ' ------------------------------------------------------------------------------ Delay VAR Byte index VAR Byte ' loop counter RegAddr VAR Byte ' SCP1000 address to read/write NumBits VAR Byte ' number of bits 8 or 16 ioByte VAR Byte result VAR Word ' sensor result indRegAddr VAR Byte ' temp holding for indirect addr indData VAR Byte ' temp holding for indirect data Counter VAR Byte ' counter eeprom VAR Bit ' flag for the indirect routine Temp VAR Word ' holds the temperature value Pres_MSB VAR Byte ' Pressure data MSB (3 bits) Pres_LSB VAR Word ' Pressure data LSB (16 bits) Measure_Mode VAR Byte ' Used to select measurement mode ' 0=high resolution - 17 bit ' 1=high speed - 15bit ' 2=ultra low power - 15bit ' ------------------------------------------------------------------------------ ' Initialization ' ------------------------------------------------------------------------------ DEBUG CLS DEBUG HOME DEBUG "SCP1000 Test Program",CR,CR,"Initializing ..." ' this loop is to give me time to do something before the real program starts FOR index = 1 TO 50 DEBUG "." PAUSE 50 NEXT DEBUG ".",CR,CR NumBits = 8 eeprom = no ioByte = $00 Counter = 0 ' Set measurement mode ' 0 = high resolution - 17 bit ~ 1.8 samples per second ' 1 = high speed - 15bit ~ 9 samples per second ' 2 = ultra low power - 15bit ~ 1 sample per second Measure_Mode = 0 'DEBUG "set CSB & SCK high",CR,CR HIGH CSB ' set outputs HIGH SCK PAUSE 1000 ' Wait a bit for no particular reason ' initialize the SCP1000 GOSUB Initialize ' Read ASIC revision number. See tech note TN59 SCP1000 series ASIC update DEBUG CR,"Get ASIC revision number",CR RegAddr = RevID ' ASIC revision register 'DEBUG "Calling Direct_Read routine",CR GOSUB Direct_Read DEBUG "ASIC rev number = ",DEC Result,CR PAUSE 1000 ' pause a bit to slow things down for debugging 'Read status register DEBUG CR,"Read Status Reg",CR GOSUB Read_Status DEBUG "Status reg = $",HEX2 Result," %",BIN8 Result,CR DEBUG CR,REP "-"\40,CR DEBUG CR,"Start reading temperature and pressure",CR PAUSE 2000 ' pause a bit to slow things down for debugging ' ------------------------------------------------------------------------------ ' Program Code ' ------------------------------------------------------------------------------ Main: ' Start loop. The counter is just for grins Counter = Counter + 1 DEBUG CR,"Count = ", DEC Counter,CR 'Read status register 'DEBUG CR,"Read Status Reg",CR GOSUB Read_Status DEBUG "Status reg = $",HEX2 Result," %",BIN8 Result,CR ' Read temperature ' DEBUG CR,"Read temperature",CR RegAddr = TempOut ' read TEMPOUT register $21 GOSUB Direct_Read ' mask upper bits Temp = Result & %0011111111111111 ' If sign bit is set then invert, add 1 DEBUG "Raw Temp = %",BIN16 Temp, " $", HEX4 Temp," dec:",SDEC Temp,CR IF Temp.BIT13 = 1 THEN Temp = ~Temp ' Invert raw number 'DEBUG " -Temp = %",BIN16 Temp, " $", HEX4 Temp," dec:",SDEC Temp,CR Temp = Temp & %0011111111111111 'DEBUG " -Temp = %",BIN16 Temp, " $", HEX4 Temp," dec:",SDEC Temp,CR Temp = Temp +1 'DEBUG " -Temp = %",BIN16 Temp, " $", HEX4 Temp," dec:",SDEC Temp, CR Temp = Temp * 10/20 ' divide by 20 to get temp in degrees C 'DEBUG " -Temp = %",BIN16 Temp, " $", HEX4 Temp," dec:",SDEC Temp, CR Temp = -Temp DEBUG " -Temp C = %",BIN16 Temp, " $", HEX4 Temp," dec:",SDEC Temp, CR ELSE Temp = Temp * 10/20 ' DIVIDE By 20 to get temp in degrees C DEBUG " +Temp C = %",BIN16 Temp, " $", HEX4 Temp," dec:",SDEC Temp, CR ENDIF ' PAUSE 2000 ' pause a bit to slow things down for debugging 'Read pressure ' DEBUG CR,"Read Pressure",CR RegAddr = DataRd8 ' read pressure MSB (3 bits, mask others) GOSUB Direct_Read Pres_MSB = Result & %00000111 ' DEBUG CR,"Pres MSB = $",HEX2 Pres_MSB," %",BIN8 Pres_MSB,CR RegAddr = DataRd16 ' read GOSUB Direct_Read Pres_LSB = Result DEBUG "Pres MSB = $",HEX2 Pres_MSB," %",BIN8 Pres_MSB,CR DEBUG "Pres LSB = $",HEX4 Pres_LSB," %",BIN16 Pres_LSB,CR DEBUG "Pressure = $",HEX1 Pres_MSB.LOWNIB,HEX4 Pres_LSB IF Measure_Mode = 0 THEN DEBUG " - 17 bit resolution",CR ELSE DEBUG " - 15 bit resolution",CR ENDIF PAUSE 2000 ' pause a bit to slow things down for debugging GOTO Main END ' ------------------------------------------------------------------------------ ' Subroutines ' ------------------------------------------------------------------------------ Direct_Write: '****************************************************************************** ' Direct Write routine '------------------------------------------------ ' 1. Convert the SCP1000 register address to real address by shifting the ' bit pattern to the left by 2 bits and add read/write bit and 0 ' [xxAAAAAA] --> [A A A A A A RW 0] A = address bit ' ' (MSB) A A A A A A RW 0 (LSB) ' | | | *- always zero ' | | *--- Read/Write Bit (read: RW=0, Write: RW=1) ' *---------*------ Register address bits ' 2. Set Read/Write bit to '1' in address byte ' [A A A A A A RW 0] --> [A A A A A A 1 0] ' 3. Set CSB to low ' 4. Send register address byte ' 5. Send register content (data byte - ioByte variable) ' 6. Set CSB to High '------------------------------------------------ ' Note: Set register address and data variables before calling subroutine '****************************************************************************** ' DEBUG "Direct_Write Subroutine",CR ' DEBUG " NumBits = ",DEC NumBits,CR ' DEBUG " RegAddr = $",HEX2 RegAddr," %",BIN8 RegAddr,CR ' DEBUG " ioByte = $",HEX2 ioByte," %",BIN8 ioByte,CR ' shift register address 2 places and insert RW bit ' DEBUG " Shift RegAddr left 2 places",CR RegAddr = RegAddr << 2 ' DEBUG " RegAddr = $",HEX2 RegAddr," %",BIN8 RegAddr,CR ' DEBUG " ORing $02 to address to insert write bit",CR RegAddr = RegAddr | %00000010 ' DEBUG " RegAddr = $",HEX2 RegAddr," %",BIN8 RegAddr,CR ' write out to SCP1000 ' DEBUG " Set CSB low",CR LOW CSB ' set CSB low ' DEBUG " Shift out to SCP1000",CR SHIFTOUT MOSI, SCK, MSBFIRST, [RegAddr] ' send reg address byte PAUSE 100 ' not sure if this is needed SHIFTOUT MOSI, SCK, MSBFIRST, [ioByte] ' send data byte ' DEBUG " Done.",CR PAUSE 100 ' not sure if this is needed ' DEBUG " Set CSB high",CR HIGH CSB 'set CSB high ' DEBUG "End Direct_Write",CR RETURN Direct_Read: '****************************************************************************** ' Direct Read routine '------------------------------------------------ ' 1. Convert the SCP1000 register address to real address by shifting the ' bit pattern to the left by 2 bits and add read/write bit and 0 ' [xxAAAAAA] --> [A A A A A A RW 0] A = address bit ' ' (MSB) A A A A A A RW 0 (LSB) ' | | | *- always zero ' | | *--- Read/Write Bit (read: RW=0, Write: RW=1) ' *---------*------ Register address bits ' 2. Set Read/Write bit to '0' in address byte ' [A A A A A A RW 0] --> [A A A A A A 0 0] ' 3. Set CSB to low ' 4. Send register address byte ' 5. Read data bytes (1 byte or 2 depending on register) ' 6. Set CSB to High '------------------------------------------------ ' NOTE: The word length is determined by the address value. If A[5] equals '1', ' the word length is 16 bits otherwise it is 8. ' (MSB) A[5] A[4] A[3] A[2] A[1] A[0] RW 0 (LSB) ' ' Note: Set register address and clear result variables ' before calling subroutine. SCP1000 data byte(s) will ' be in result variable '****************************************************************************** ' DEBUG "Direct_Read Subroutine",CR ' DEBUG " NumBits = ",DEC NumBits,CR ' DEBUG " RegAddr = $",HEX2 RegAddr," %",BIN8 RegAddr,CR ' DEBUG " Result = $",HEX4 Result," %",BIN16 Result,CR Result = $00 ' clear result variable 'DEBUG "If A[5] is 1 then NumBits = 16 bit otherwise NumBits = 8",CR IF RegAddr.BIT5 = 1 THEN NumBits = 16 ELSE NumBits = 8 ENDIF ' DEBUG " NumBits = ",DEC NUmBits,CR ' DEBUG " Result = $",HEX4 Result," %",BIN16 Result,CR ' shift register address 2 places and insert RW bit ' DEBUG " Shift RegAddr left 2 places",CR RegAddr = RegAddr << 2 ' shift inserts 2 zeros on the right ' DEBUG " RegAddr = $",HEX2 RegAddr," %",BIN8 RegAddr,CR ' write out to SCP1000 ' DEBUG " Set CSB low",CR LOW CSB ' set CSB low ' DEBUG " Shift out register address to SCP1000",CR SHIFTOUT MOSI, SCK, MSBFIRST, [RegAddr] ' send reg address byte PAUSE 10 ' not sure if this is needed ' DEBUG " Shift in data from SCP1000",CR ' SHIFTIN MISO, SCK, MSBPOST, [Result\NumBits] ' read data SHIFTIN MISO, SCK, MSBPRE, [Result\NumBits] ' read data ' DEBUG " Result = $",HEX4 Result," %",BIN16 Result,CR ' DEBUG " Done.",CR PAUSE 100 ' not sure if this is needed ' DEBUG " Set CSB high",CR HIGH CSB 'set CSB high ' DEBUG "End Direct_Read",CR RETURN Indirect_Write: '****************************************************************************** ' Indirect Write routine '------------------------------------------------ ' Indirect write requires 3 Direct_Write operations ' 1. Use Direct_Write to write indirect register address to ADDPtr ($02) ' 2. Use Direct_Write to write data to DataWR ($01) ' 3. Use Direct_Write to write "indirect write" command ($02) to Oper ($03) ' 4. Wait 50ms '------------------------------------------------ ' Note: Set register address and data variables before calling subroutine '****************************************************************************** ' DEBUG "Indirect_Write Subroutine",CR indRegAddr = RegAddr ' save values to temp locations indData = iobyte RegAddr = ADDPtr ' write reg addr to ADDPTR $02 ioByte = indRegAddr ' DEBUG " Write ADDPRT reg",CR GOSUB Direct_Write RegAddr = DataWR ' write reg data to DATAWR $01 ioByte = indData ' DEBUG " Write DATAWR reg",CR GOSUB Direct_Write RegAddr = Oper ' write to OPERATION register IF eeprom = no THEN ioByte = $02 ' write $02 to operations reg ELSE ioByte = $06 ' write $06 for eeprom ENDIF ' DEBUG " Write OPERATION reg",CR GOSUB Direct_Write PAUSE 50 ' DEBUG "End Indirect_Write.",CR RETURN Indirect_Read: '****************************************************************************** ' Indirect Read routine '------------------------------------------------ ' Indirect read requires 3 Direct_Write operations ' 1. Use Direct_Write to write indirect register address to ADDPtr ($02) ' 2. Use Direct_Write to write "read indirect" command ($01) to Oper ($03) ' 3. Wait 10ms ' 4. Use Direct_Read to read 2 bytes from DataRD16 ($20) '------------------------------------------------ ' Note: Set register address variable before calling subroutine. ' Read value is in result variable '****************************************************************************** ' DEBUG "Indirect_Read Subroutine",CR ioByte = RegAddr ' save values to temp locations RegAddr = ADDPtr ' write reg addr to ADDPTR $02 ' DEBUG " Write ADDPRT reg",CR GOSUB Direct_Write REGADDR = Oper ' write to OPERATION register IF eeprom = no THEN ioByte = $01 ' write $01 to operations reg ELSE ioByte = $05 ' write $05 for eeprom ENDIF ' DEBUG " Write OPERATION reg",CR GOSUB Direct_Write PAUSE 10 IF eeprom = yes THEN RegAddr = DataRd8 ELSE RegAddr = DataRd16 ENDIF ' DEBUG " Read DATARD reg",CR GOSUB Direct_Read eeprom = no ' DEBUG "End Indirect_Read.",CR RETURN Read_Status: '****************************************************************************** ' Read status register routine '------------------------------------------------ ' Status register value in result variable '****************************************************************************** 'Read status register RegAddr = Status ' read status register GOSUB Direct_Read RETURN Initialize: '****************************************************************************** ' Initialize SCP1000 routine '------------------------------------------------ ' Reset SCP1000 by writing $01 in register $06 DEBUG "Reset SCP1000 ASIC",CR RegAddr = Rstr ' ASIC software reset register $06 ioByte = $01 ' write a 1 to the reset register to reset device 'DEBUG "Calling Direct_Write routine",CR GOSUB Direct_Write PAUSE 100 ' pause before next operation 'Set low noise operation DEBUG CR,"Set low noise operation",CR RegAddr = ModTest2 ' - write $03 to indirect register ModTest2 $2D ioByte = $03 GOSUB Indirect_Write PAUSE 100 ' wait 100ms ' switch measurement mode - stop active mode before switching ' measurement mode by writing $00 in register $03 ' see section 2.2.2.1 in data sheet DEBUG CR,"Stop OP mode",CR RegAddr = Oper ' reset operation mode - write $00 to op register ioByte = $00 ' write a 1 to the reset register to reset device GOSUB Direct_Write PAUSE 10 ' wait before changing to new mode 'Set SCP1000 measurement mode SELECT Measure_Mode CASE 0 'Set SCP1000 TO HIGH resolution mode - 17 Bit DEBUG CR,"Set high resolution mode - 17 bit",CR RegAddr = Oper ' - write $0A to operation register $03 ioByte = $0A GOSUB Direct_Write PAUSE 50 ' wait 50ms CASE 1 'Set SCP1000 to high speed mode - 15 Bit resolution DEBUG CR,"Set high speed mode - 15 bit resolution",CR RegAddr = Oper ' - write $09 to operation register $03 ioByte = $09 GOSUB Direct_Write PAUSE 50 ' wait 50ms CASE 2 'Set SCP1000 to ultra low power mode - 15 Bit resolution DEBUG CR,"Set ultra low power mode - 15 bit resolution",CR RegAddr = Oper ' - write $0B to operation register $03 ioByte = $0B GOSUB Direct_Write PAUSE 50 ' wait 50ms ENDSELECT 'Read status register DEBUG CR,"Read Status Reg",CR GOSUB Read_Status DEBUG "Status reg = $",HEX2 Result," %",BIN8 Result,CR RETURN