' {$STAMP BS2}
' {$PBASIC 2.5}

'How TO Use:
' o With power initially off, connect VIN TO 5VDC (the same voltage
'   powering the sTAMP).  Connect GND TO Vss.
'
' o Connect P0, P1, AND P2 ON the Stamp directly TO the CS, DATA, AND CLK
'   pins ON the Digital 3-Axis Accelerometer module.
'
' o Power ON the Stamp.  Download AND run this code ON the Stamp.
'
' o Acceleration values will stream back TO the computer, AND can be viewed
'   on the DEBUG terminal.
'
' o The offset values FOR each axis can be calibrated by placing the device
'   ON a flat horizontal surface AND adjusting the corresponding constants
'   UNTIL the values FOR each axis READ (WHILE in 2g mode):
'        X = 0   (0g)
'        Y = 0   (0g)
'        Z = 63  (+1g)
'   The values already present are FOR demonstration purposes AND can
'   be easily modified TO fine tune your own device. Keep in mind that
'   the offset values are in 1/2 Bit increments, so FOR example, TO offset
'   an axis by 5 counts, the corresponding offset would need TO be increased
'   by a value of 10.  See the MMA7455L device datasheet FOR more
'   information.

'Offset values FOR each axis:
XCal      CON 25    'VAR Word
YCal      CON 50    'VAR word
ZCal      CON 0     'VAR Word

CLKPin    PIN 0     ' Clock Pin
DATAPin   PIN 1     ' Data Pin
CSPin     PIN 2     ' Chip Select Pin

XOUTL     CON $00   ' 10 bits output value X LSB             XOUT[7]  XOUT[6]  XOUT[5]  XOUT[4]  XOUT[3]  XOUT[2]  XOUT[1]  XOUT[0]
XOUTH     CON $01   ' 10 bits output value X MSB             --       --       --       --       --       --       XOUT[9]  XOUT[8]
YOUTL     CON $02   ' 10 bits output value Y LSB             YOUT[7]  YOUT[6]  YOUT[5]  YOUT[4]  YOUT[3]  YOUT[2]  YOUT[1]  YOUT[0]
YOUTH     CON $03   ' 10 bits output value Y MSB             --       --       --       --       --       --       YOUT[9]  YOUT[8]
ZOUTL     CON $04   ' 10 bits output value Z LSB             ZOUT[7]  ZOUT[6]  ZOUT[5]  ZOUT[4]  ZOUT[3]  ZOUT[2]  ZOUT[1]  ZOUT[0]
ZOUTH     CON $05   ' 10 bits output value Z MSB             --       --       --       --       --       --       ZOUT[9]  ZOUT[8]
XOUT8     CON $06   ' 8 bits output value X                  XOUT[7]  XOUT[6]  XOUT[5]  XOUT[4]  XOUT[3]  XOUT[2]  XOUT[1]  XOUT[0]
YOUT8     CON $07   ' 8 bits output value Y                  YOUT[7]  YOUT[6]  YOUT[5]  YOUT[4]  YOUT[3]  YOUT[2]  YOUT[1]  YOUT[0]
ZOUT8     CON $08   ' 8 bits output value Z                  ZOUT[7]  ZOUT[6]  ZOUT[5]  ZOUT[4]  ZOUT[3]  ZOUT[2]  ZOUT[1]  ZOUT[0]
STATUS    CON $09   ' Status registers                       --       --       --       --       --       PERR     DOVR     DRDY
DETSRC    CON $0A   ' Detection source registers             LDX      LDY      LDZ      PDX      PDY      PDZ      INT1     INT2
TOUT      CON $0B   ' "Temperature output value" (Optional)  TMP[7]   TMP[6]   TMP[5]   TMP[4]   TMP[3]   TMP[2]   TMP[1]   TMP[0]
'         CON $0C   ' (Reserved)                             --       --       --       --       --       --       --       --
I2CAD     CON $0D   ' I2C device address I                   2CDIS    DAD[6]   DAD[5]   DAD[4]   DAD[3]   DAD[2]   DAD[1]   DAD[0]
USRINF    CON $0E   ' User information (Optional)            UI[7]    UI[6]    UI[5]    UI[4]    UI[3]    UI[2]    UI[1]    UI[0]
WHOAMI    CON $0F   ' "Who am I" value (Optional)            ID[7]    ID[6]    ID[5]    ID[4]    ID[3]    ID[2]    ID[1]    ID[0]
XOFFL     CON $10   ' Offset drift X value (LSB)             XOFF[7]  XOFF[6]  XOFF[5]  XOFF[4]  XOFF[3]  XOFF[2]  XOFF[1]  XOFF[0]
XOFFH     CON $11   ' Offset drift X value (MSB)             --       --       --       --       --       XOFF[10] XOFF[9]  XOFF[8]
YOFFL     CON $12   ' Offset drift Y value (LSB)             YOFF[7]  YOFF[6]  YOFF[5]  YOFF[4]  YOFF[3]  YOFF[2]  YOFF[1]  YOFF[0]
YOFFH     CON $13   ' Offset drift Y value (MSB)             --       --       --       --       --       YOFF[10] YOFF[9]  YOFF[8]
ZOFFL     CON $14   ' Offset drift Z value (LSB)             ZOFF[7]  ZOFF[6]  ZOFF[5]  ZOFF[4]  ZOFF[3]  ZOFF[2]  ZOFF[1]  ZOFF[0]
ZOFFH     CON $15   ' Offset drift Z value (MSB)             --       --       --       --       --       ZOFF[10] ZOFF[9]  ZOFF[8]
MCTL      CON $16   ' Mode control                           LPEN     DRPD     SPI3W    STON     GLVL[1]  GLVL[0]  MOD[1]   MOD[0]
INTRST    CON $17   ' Interrupt latch reset                  --       --       --       --       --       --       CLRINT2  CLRINT1
CTL1      CON $18   ' Control 1                              --       THOPT    ZDA      YDA      XDA      INTRG[1] INTRG[0] INTPIN
CTL2      CON $19   ' Control 2                              --       --       --       --       --       DRVO     PDPL     LDPL
LDTH      CON $1A   ' Level detection threshold limit value  LDTH[7]  LDTH[6]  LDTH[5]  LDTH[4]  LDTH[3]  LDTH[2]  LDTH[1]  LDTH[0]
PDTH      CON $1B   ' Pulse detection threshold limit value  PDTH[7]  PDTH[6]  PDTH[5]  PDTH[4]  PDTH[3]  PDTH[2]  PDTH[1]  PDTH[0]
PW        CON $1C   ' Pulse duration value                   PD[7]    PD[6]    PD[5]    PD[4]    PD[3]    PD[2]    PD[1]    PD[0]
LT        CON $1D   ' Latency time value                     LT[7]    LT[6]    LT[5]    LT[4]    LT[3]    LT[2]    LT[1]    LT[0]
TW        CON $1E   ' Time window for 2nd pulse value        TW[7]    TW[6]    TW[5]    TW[4]    TW[3]    TW[2]    TW[1]    TW[0]
'         CON $1F   ' (Reserved)                             --       --       --       --       --       --       --       --

XAccel    VAR Word  ' Variables to store incoming RAW data from the accelerometer
YAccel    VAR Word
ZAccel    VAR Word

Xrot      VAR Byte  ' Variables to store New Binary Radian
Yrot      VAR Byte
Zrot      VAR Byte
OldXrot   VAR Byte  ' Variables to store Old Binary Radian
OldYrot   VAR Byte
OldZrot   VAR Byte

Address   VAR Word  ' Variables for reading and writing data to the accelerometer
SendData  VAR Byte
ReceiveData VAR Byte

Temp1     VAR Word  ' Temp variables
Temp2     VAR Word
Temp3     VAR Word

Chr       VAR Byte  'Variables used for Gages ; Chr = defines the Character used to draw with
X         VAR Byte  '                             X = Drawing position
Y         VAR Byte  '                             Y = Drawing position

Xc        CON 12    'Constants used for Gages ; Xc = X Center
Yc        CON 6     '                         ; Yc = Y Center
Xs        CON 12    '                         ; Xs = X Size     Note: The X Size must be twice the Y Size in order to resemble a circle
Ys        CON 6     '                         ; Ys = Y Size           because of the aspect ratio of the characters displayed on the screen.

'
'         MCTL - Mode control register
'   +---------------------------------------+
'   ¦ D7 ¦ D6 ¦ D5 ¦ D4 ¦ D3 ¦ D2 ¦ D1 ¦ D0 ¦
'   +----+----+----+----+----+----+----+----¦
'   ¦ -- ¦DRPD¦SPI3¦STON¦GLVL¦GLVL¦MODE¦MODE¦
'   +---------------------------------------+
'
'
'   D7       - don't care          0
'
'   D6(DRPD) - DATA ready status   0 - OUTPUT TO INT1 PIN
'                                  1 - is NOT OUTPUT TO INT1 PIN
'
'   D5(SPI3W)- Wire Mode           0 - SPI is 4-wire mode
'                                  1 - SPI is 3-wire mode
'
'   D4(STON) - Self Test           0 - NOT enabled
'                                  1 - enabled
'
'   D3(GLVL[1]) - g-SELECT        00 - 8g ; 16 LSB/g in 8-Bit format
'   D2(GLVL[0]) - g-SELECT        10 - 4g ; 32 LSB/g in 8-Bit format
'                                 01 - 2g ; 64 LSB/g in 8-Bit format
'
'                                         ; Note: When reading g in 10-Bit
'                                         ;       format, resolution is fixed
'                                         ;       at 64 LSB/g
'                   10-Bit g register
'   +-------------------------------------------------+
'   ¦ D9 ¦ D8 ¦ D7 ¦ D6 ¦ D5 ¦ D4 ¦ D3 ¦ D2 ¦ D1 ¦ D0 ¦
'   +-------------------------------------------------+
'   ¦<------------------------------------->¦            ; These 8 bits are READ in 8g mode
'        ¦<------------------------------------->¦       ; These 8 bits are READ in 4g mode
'             ¦<------------------------------------->¦  ; These 8 bits are READ in 2g mode
'
'   D1(MODE[1]) - Mode SELECT     00 - Standby
'   D0(MODE[0]) - Mode SELECT     01 - Measurement
'                                 10 - Level Detection
'                                 11 - Pulse Detection

Main:
  Address = MCTL: SendData = %01100101: GOSUB DataOut  'Set the Mode control register
                                                         'DATA ready status is NOT OUTPUT TO INT1 PIN
                                                         '3-wire SPI mode
                                                         'Self Test NOT enabled
                                                         '+/-2g sensitivity mode
                                                         'Measurement mode

  Address = XOFFL: SendData = XCal& $FF: GOSUB DataOut 'Write X-Axis Calibration Value ; LOWBYTE
  Address = XOFFH: SendData = XCal >> 8: GOSUB DataOut '                               ; HIGHBYTE

  Address = YOFFL: SendData = YCal& $FF: GOSUB DataOut 'Write Y-Axis Calibration Value ; LOWBYTE
  Address = YOFFH: SendData = YCal >> 8: GOSUB DataOut '                               ; HIGHBYTE

  Address = ZOFFL: SendData = ZCal& $FF: GOSUB DataOut 'Write Z-Axis Calibration Value ; LOWBYTE
  Address = ZOFFH: SendData = ZCal >> 8: GOSUB DataOut '                               ; HIGHBYTE

  DEBUG CLS                                           'Clear Display
  GOSUB TextField                                     'Draw TEXT field (stationary TEXT that does not get updated)
  GOSUB DrawGages                                     'Draw the Gages used for X,Y, and Z rotation indicators

ReadDataLoop:
  Address = XOUT8:GOSUB DataIn                        'Read in X-Axis Acceleration Value
  XAccel = ReceiveData|($FF00*ReceiveData.BIT7)          'Sign extend the two's complement byte so
                                                         'negative numbers can be properly displayed

  Address = YOUT8:GOSUB DataIn                        'Read in Y-Axis Acceleration Value
  YAccel = ReceiveData|($FF00*ReceiveData.BIT7)          'Sign extend the two's complement byte so
                                                         'negative numbers can be properly displayed

  Address = ZOUT8:GOSUB DataIn                        'Read in Z-Axis Acceleration Value
  ZAccel = ReceiveData|($FF00*ReceiveData.BIT7)          'Sign extend the two's complement byte so
                                                         'negative numbers can be properly displayed

  Xrot = YAccel ATN ZAccel                            'Calculate and Display X_Rotation
  DEBUG CRSRXY,38,10,DEC (Xrot*45)/32,"  "
  IF OldXrot<>Xrot THEN                               'No sense redrawing needle if nothing has changed
     Temp1 = OldXrot: Chr = 32:Temp3 = 6:GOSUB DrawNeedle       'First Blank-out Old Needle position
     Temp1 = Xrot   : Chr = 42:Temp3 = 6:GOSUB DrawNeedle       'Then Re-draw New Needle position
     OldXrot = Xrot
  ENDIF

  Yrot = ZAccel ATN XAccel                            'Calculate and Display Y_Rotation
  DEBUG CRSRXY,38,23,DEC (Yrot*45)/32,"  "
  IF OldYrot<>Yrot THEN                               'No sense redrawing needle if nothing has changed
     Temp1 = OldYrot: Chr = 32:Temp3 = 19:GOSUB DrawNeedle      'First Blank-out Old Needle position
     Temp1 = Yrot   : Chr = 42:Temp3 = 19:GOSUB DrawNeedle      'Then Re-draw New Needle position
     OldYrot = Yrot
  ENDIF

  Zrot = XAccel ATN YAccel                            'Calculate and Display Z_Rotation
  DEBUG CRSRXY,38,36,DEC (Zrot*45)/32," "                                                              'down's z
  IF OldZrot<>Zrot THEN                               'No sense redrawing needle if nothing has changed
     Temp1 = OldZrot: Chr = 32:Temp3 = 32:GOSUB DrawNeedle      'First Blank-out Old Needle position
     Temp1 = Zrot   : Chr = 42:Temp3 = 32:GOSUB DrawNeedle      'Then Re-draw New Needle position
     OldZrot = Zrot
  ENDIF

  DEBUG CRSRXY,50,3, SDEC XAccel, "  ",               'Display the RAW X, Y, and Z Accelerometer values      up
        CRSRXY,50,4, SDEC YAccel, "  ",
        CRSRXY,50,5, SDEC ZAccel, "  "

  GOTO ReadDataLoop

DataOut:
LOW CSPin                                              'Pull chip select pin low to start transmission
SHIFTOUT DATAPin, CLKPin, MSBFIRST, [(Address|%1000000)<<1] 'Select register Address
SHIFTOUT DATAPin, CLKPin, MSBFIRST, [SendData]         'Write value to Address
HIGH CSPin                                             'End transmission
RETURN

DataIn:
LOW CSPin                                              'Pull chip select pin low to start transmission
SHIFTOUT DATAPin, CLKPin, MSBFIRST, [Address<<1]       'Select register Address
SHIFTIN DATAPin, CLKPin, MSBPRE, [ReceiveData]         'Read value from Address
HIGH CSPin                                             'End transmission
RETURN

TextField:
DEBUG CRSRXY,40,0,"MMA7455 3-Axis Accelerometer BS2 DEMO #2",   'Display all stationary TEXT that does not get updated
      CRSRXY,48,2,"8-Bit 2g Mode ; 64 LSB/g",
      CRSRXY,25,10,"X_Rotation = ",
      CRSRXY,25,23,"Y_Rotation = ",
      CRSRXY,25,36,"Z_Rotation = ",
      CRSRXY,48,3, "X=",
      CRSRXY,48,4, "Y=",
      CRSRXY,48,5, "Z="
RETURN

DrawGages:                                             'Use Sine/Cosine method to draw circles to be used as gages
FOR Temp1 = 0 TO 255 STEP 5
    X = SIN(Temp1)                                     'Get Sine value from Binary RAD
    IF X>128 THEN
       X=255-X                                         'Handles negative numbers for graphing data
       X = Xc - ((X* Xs)/ 128)
    ELSE
       X = Xc + ((X* Xs)/ 128)                         'Handles positive numbers for graphing data
    ENDIF
    Y = COS(Temp1)                                     'Get CoSine value from Binary RAD
    IF Y>128 THEN
       Y=255-Y                                         'Handles negative numbers for graphing data
       Y = Yc - ((Y* Ys)/ 128)
    ELSE
       Y = Yc + ((Y* Ys)/ 128)                         'Handles positive numbers for graphing data
    ENDIF
    DEBUG CRSRXY,X,Y,46                                'Draw all three gages at once   3­Ó¹Ï
    DEBUG CRSRXY,X,Y+13,46
    DEBUG CRSRXY,X,Y+26,46
NEXT
DEBUG CRSRXY,Xc,Yc,42                                'Draw Center of all three gages (Fixed point)  ¹Ï¤º­ìÂI
DEBUG CRSRXY,Xc,Yc+13,42
DEBUG CRSRXY,Xc,Yc+26,42
RETURN

DrawNeedle:
FOR Temp2 = 1 TO 2                                     'Use a derivative of the Sine/Cosine Circle method to draw gage needles
    X = SIN(Temp1+64)                                  'Add 90 Deg to Binary Radian and Get Sine value
    IF X>128 THEN
       X=255-X
       X = Xc - ((X* (Xs*Temp2)/3)/ 128)               'Handles negative numbers for graphing data
    ELSE
       X = Xc + ((X* (Xs*Temp2)/3)/ 128)               'Handles positive numbers for graphing data
    ENDIF
    Y = COS(Temp1+64)                                  'Add 90 Deg to Binary Radian and Get CoSine value
    IF Y>128 THEN
       Y=255-Y
       Y = Temp3 - ((Y* (Ys*Temp2)/3)/ 128)            'Handles negative numbers for graphing data
    ELSE
       Y = Temp3 + ((Y* (Ys*Temp2)/3)/ 128)            'Handles negative numbers for graphing data
    ENDIF
    DEBUG CRSRXY,X,Y,Chr                             'Display Needle by drawing points from the center of the gage out
NEXT
RETURN