#include  <msp430x42x0.h>   
SCL           EQU   0x0020                  ; I2C line setup
SDA           EQU   0x0010
D1            EQU   3965	            ; correction const for TEMP
C2            EQU   5871300                 ; correction const for HUMI
C1            EQU   14939840	            ;  -"-

; SHT15 interface                               adr   command  r/w
MEASURE_TEMP  EQU   0x03 	            ;	000   0001 	1
MEASURE_HUMI  EQU   0x05 	            ;	000   0010 	1
STATUS_REG_W  EQU   0x06 	            ;	000   0011 	0
STATUS_REG_R  EQU   0x07 	            ;	000   0011 	1
RESET_SEN     EQU   0x1e 	            ;	000   1111 	0


;------------------------------------------------------------------------------
            ORG     0A000h                  ; program start for MSP430F4260
;------------------------------------------------------------------------------
RESET       mov.w   #300h, SP               ; initialize stack pointer
            mov.w   #WDTPW+WDTHOLD, &WDTCTL ; stop WDT
            bis.b   #XCAP14PF, &FLL_CTL0    ; set load capacitance for xtal
            mov.b   #LCDON + LCD3MUX + LCDFREQ_128, &LCDACTL ; 3-mux, ACLK/96
            mov.b   #0x0F, &LCDAPCTL0       ; assign s0-s13 to LCD
            bis.b   #LCD2B, &LCDAVCTL0      ; 1/2 bias mode

            clr.b   &P6OUT                  ; configure all pins for output
            mov.b   #0xFF, &P6DIR
            clr.b   &P5OUT
            mov.b   #0x10, &P5DIR           ; configure COM3 for output
            mov.b   #0x0C, &P5SEL           ; assign COM1 & COM2 pins to LCD
            clr.b   &P1OUT                  ; preset SCL=0 and SDA=1
            mov.b   #0xEF, &P1DIR           ; enable input at P1:4
 
            mov.b   #7, R15                 ; 7 LCD memory bytes to clear
            clr.b   LCDMEM-1(R15)           ; clear display
            dec.b   R15      
            jnz     $-6              

            mov.b   #0x27, &BTCTL           ; basic timer1 setup ACLK/2^(16)
            clr.b   &BTCNT1                 ; clear counters
            clr.b   &BTCNT2
            bis.b   #BTIE, &IE2             ; enable timer interrupt

            mov.w   #3000, R15              ; 15ms power-on delay
            call    #delay
	    call    #soft_reset_SHT15
            mov.w   #3000, R15              ; another 15ms delay is required
            call    #delay                  ; after every soft reset of SHT15

            call    #start_SHT15
            mov.b   #STATUS_REG_W, R10      ; activate status reg for writing
            call    #write_SHT15
            mov.b   #1, R10                 ; set 12/8 bit T/H resolution
            call    #write_SHT15

            clr.w   R7                      ; start with measuring TEMP
loop        bit.b   #BIT0, R7               ; measure TEMP if bit 0 of R7 is 0
            jnz     humi                    ; otherwise, measure HUMI 
            
temp        call    #get_TEMP1              ; request TEMP conversion
            clr.b   &BTCNT1                 
            mov.b   #245, &BTCNT2           ; sleep for 80 msec
            bis.w   #LPM3 | GIE, SR         ; enter LPM3 mode (sleep)
            
            call    #get_TEMP2              ; R10 = TEMP*100 
            call    #temp2BCD               ; compute BCD in R4
            call    #display                ; display temp
            jmp     sleep
  
humi        call    #get_HUMI1              ; request HUMI conversion
            clr.b   &BTCNT1                 
            mov.b   #253, &BTCNT2           ; sleep for 20 msec
            bis.w   #LPM3 | GIE, SR         ; enter LPM3 mode (sleep)
            
            call    #get_HUMI2              ; R10 = HUMI  
            call    #humi2BCD               ; compute BCD in R4
            call    #display                ; display humi

sleep       xor.b   #BIT0, R7               ; switch to the other mode
            bis.w   #LPM3 | GIE, SR         ; enter LPM3 mode (sleep)
            bis.w   #LPM3 | GIE, SR         ; do it again 3 times to acieve
            bis.w   #LPM3 | GIE, SR         ; a 8 sec delay between the
            bis.w   #LPM3 | GIE, SR         ; screen updates
            jmp     loop


;//////////////////////////////////// procedures
;       _____         ________
; DATA:      |_______|
;           ___     ___
; SCK : ___|   |___|   |______
start_SHT15				    ; start condition for SHT15
            bic.b   #SDA, &P1DIR	    ; start with SDA=1 and SCL=0
	    bic.b   #SCL, &P1OUT
	    nop				    ; delay slot
	    bis.b   #SCL, &P1OUT            ; set clock high
	    bis.b   #SDA, &P1DIR	    ; set dala low
	    nop	
	    bic.b   #SCL, &P1OUT	    ; set clock low
	    jmp	    $+2			    ; 5 us delay		
	    jmp	    $+2
	    nop
	    bis.b   #SCL, &P1OUT	    ; set clock high again
	    nop
	    bic.b   #SDA, &P1DIR	    ; release data line	
	    nop
	    bic.b   #SCL, &P1OUT            ; set clock low
	    ret

;       _____________________________________________________         ________
; DATA:                                                      |_______|
;          _    _    _    _    _    _    _    _    _        ___     ___
; SCK : __| |__| |__| |__| |__| |__| |__| |__| |__| |______|   |___|   |______
reset_SHT15				    ; reset sensor interface	
	    mov.b   #9, R15                 ; pulse counter
	    bis.b   #SCL, &P1OUT            ; set clock high
	    nop             
	    bic.b   #SCL, &P1OUT            ; ... and low
	    dec.w   R15
	    jnz     $-16   
	    call    #start_SHT15
	    ret

soft_reset_SHT15
	    call    #reset_SHT15
	    mov.b   #RESET_SEN, R10
	    call    #write_SHT15
	    ret

;---------------------------------------------------------------------------
write_SHT15				    ; write a byte in R10 to SHT15
	    bic.b   #SDA, &P1DIR	    ; make sure that DATA=1 and CLK=0 
	    bic.b   #SCL, &P1OUT	
	    mov.b   #8, R15                 ; initialize bit counter

w_loop      rlc.b   R10			    ; get the leftmost data bit
	    jc      $+8
	    bis.b   #SDA, &P1DIR            ; set 0 on data line
	    jnc     $+8
	    bic.b   #SDA, &P1DIR	    ; set 1 on data line
	    bis.b   #SCL, &P1OUT	    ; raise clock up
	    jmp     $+2			    ; short delay
	    jmp	    $+2
	    nop
	    bic.b   #SCL, &P1OUT	    ; ... and low
	    dec.w   R15
	    jnz	    w_loop		    ; repeat this 8 times

	    bic.b   #SDA, &P1DIR	    ; release the data line	
	    jmp	    $+2			    ; let slave respond for ACK
	    jmp	    $+2
	    jmp	    $+2
	    bis.b   #SCL, &P1OUT	    ; clock up
 	    jmp     $+2			    ; slave responds OK (hopefully)
	    bic.b   #SCL, &P1OUT	    ; clock down
	    ret

;---------------------------------------------------------------------------
read_SHT15				    ; read byte from SHT15 in R10
            bic.b   #SDA, &P1DIR	    ; make sure that DATA=1 and CLK=0 
	    bic.b   #SCL, &P1OUT	
	    mov.b   #8, R15                 ; initialize bit counter

r_loop      bis.b   #SCL, &P1OUT	    ; clock up  
            bit.b   #SDA, &P1IN             ; received bit -> C-bit
            rlc.b   R10                     ; shift it into R10
            bic.b   #SCL, &P1OUT	    ; clock down
            nop
	    dec.w   R15
	    jnz	    r_loop		    ; repeat this 8 times

            tst.b   R13                     ; R13 = ACK
            jnz     $+8
            bis.b   #SDA, &P1DIR            ; send ACK signal
            bis.b   #SCL, &P1OUT	    ; raise clock up
	    jmp     $+2			    ; short delay
	    jmp	    $+2
	    nop
	    bic.b   #SCL, &P1OUT	    ; ... and low           
            bic.b   #SDA, &P1DIR            ; release the data line
	    ret

;---------------------------------------------------------------------------
get_TEMP1   call    #start_SHT15	    ; measure TEMP
	    mov.b   #MEASURE_TEMP, R10
	    call    #write_SHT15	    ; send command to sensor
            ret
            
get_TEMP2   bit.b   #SDA, &P1IN	            ; wait for the end of measurement
	    jnz	    $-6
	    clr.b   R13			    ; send ACK signal
            call    #read_SHT15             ; get MSB in R10
            mov.b   R10, R11                ; and save it in R11
            swpb    R11                     ; place MSB on its proper place
	    inc.b   R13			    ; prapare to send NACK signal
            call    #read_SHT15             ; get LSB in R10
            add.w   R11, R10                ; merge MSB and LSB in R10
            rla.w   R10                     ; normalize TEMP so that
            rla.w   R10                     ; R10 = TEMP*100
            sub.w   #D1, R10                ; correct temp
            mov.w   R10, R11                ; copy TEMP to R11              
	    ret

;---------------------------------------------------------------------------
get_HUMI1   call    #start_SHT15            ; measure relative humidity	
	    mov.b   #MEASURE_HUMI, R10
	    call    #write_SHT15	    ; send command to sensor
            ret
            
get_HUMI2   bit.b   #SDA, &P1IN	            ; wait for the end of measurement
	    jnz	    $-6
	    clr.b   R13			    ; send ACK signal
            call    #read_SHT15             ; get MSB in R10 (not used)
            mov.b   R10, R12                ; save MSB in R12
            swpb    R12
            clr.w   R12                     ; MSB is not used in 8-bit mode
	    inc.b   R13			    ; prapare to send NACK signal
            call    #read_SHT15             ; get LSB in R10
            add.w   R12, R10                ; merge MSB and LSB
            mov.w   R10, R12                ; copy HUMI value to R12
            ret

;---------------------------------------------------------------------------
temp2BCD    mov.w   R10, R14                ; copy input number
            bit.w   #BITF, R14         
            jz      check_up
            inv.w   R14                     ; negate number if it is negative
            inc.w   R14
            cmp.w   #1000, R14              ; display "-___" if TEMP is below
            jl      check_up                ; -9.9C
            mov     #0xAAAA, R4
            ret
            
check_up    cmp     #10000, R14             ; exit if the number exceeds 9999
            jl      process
            mov     #0xBBBB, R4             ; display "^^^^"
            ret

process     clr.w   R4                      ; storage for 4-digit BCD
            mov.b   #16, R15                ; loop cnt = # of bits

b2b_loop    rla.w   R14                     ; use decimal addition
            dadd.w  R4, R4                  ; operation to convert R14
            dec.b   R15                     ; into BCD
            jnz     b2b_loop     
            bit.w   #BITF, R10
            jz      $+6
            add.w   #0xA000, R4             ; add the minus sign
            ret

;---------------------------------------------------------------------------
humi2BCD
            rla.w   R10         
            rla.w   R10
            rla.w   R10
            rla.w   R10                     ; R10 = SO_RH*16

step1       ; linearization of HUMI by using a custom second degree polynomial
            mov.w   #22934, R9              ; 22934 is two upper bytes of
            sub.w   R10, R9                 ; 5871300
            swpb    R9
            mov.w   R9, R8
            and.w   #0xFF00, R8
            and.w   #0x00FF, R9
            add.w   #196, R8                ; 196 = 5871300 mod 256;  R9:R8 = 
            add.w   R10, R8                 ; 5871300 - 4096*HUMI + 16*HUMI

            mov.w   R12, R10                ; R10 = SO_RH
            clr.w   R13                     ; multiply R9:R8 by R12 and place
            clr.w   R14                     ; the result in R14:R13
            mov.b   #8, R15                 ; counter setup
mult_step1  rrc.b   R12
            jnc     $+6
            add.w   R8, R13                 ; add multiplicand to the result
            addc.w  R9, R14                 ; (32-bit operation)
            rla.w   R8                      ; shift the multiplicand
            rlc.w   R9
            dec.b   R15                     ; decrement the counter
            jnz     mult_step1              ; and proceed

            sub.w   #LWRD C1, R13           ; subtract C1 from R14:R13
            subc.w  #HWRD C1, R14         
            
            cmp.b   #10, R10               ; process special cases of HUMI
            jeq     $+8
            cmp.b   #11, R10
            jne     step2
            sub.w   #LWRD 10000000, R13     ; subtract 10^6 for HUMI=40 or 41
            subc.w  #HWRD 10000000, R14     ; R14:R13 = RH_lin*10^7

step2       ; temperature compensation of the HUMI value
            mov.w   R11, R8                 ; R11 = TEMP*100
            clr.w   R9
            sub.w   #2500, R8               ; R8 = TEMP*100 - 2500
            subc.w  #0, R9                  ; R9:R8 = sign extended R8

            swpb    R10                     ; R10 = SO_RH = HUMI
            clrc
            rrc.w   R10                     ; R10 = HUMI*128
            add.w   #1000, R10              ; R10 = 1000 + HUMI*128

            mov.b   #16, R15                ; setup for 16x16 multiplication
            clr.w   R5                      ; of R9:R8 by R10
            clr.w   R4                      ; R5:R4 is the result
mult_step2  rrc.w   R10
            jnc     $+6
            add.w   R8, R4
            addc.w  R9, R5
            rla.w   R8
            rlc.w   R9
            dec.b   R15
            jnz     mult_step2
            
            add.w   R4, R13                 ; add temp comp term to R14:R13
            addc.w  R5, R14                 ; R14:R13 = RT_true*10^7
            bit.w   #BITF, R14              ; if the resulting value is < 0
            jz      $+8                     ; replace it with 1
            mov.w   #0x100, R4
            ret

            mov.w   #-1, R10
div107      inc.w   R10                     ; divide R14:R13 by 10^7
            sub.w   #LWRD 10000000, R13     ; R10 is the integer part
            subc.w  #HWRD 10000000, R14     ; of the resulting humidity
            jge     div107

            cmp.b   #100, R10               ; if the value exceeds 100
            jl      $+8                     ; replace it with 99 in BCD
            mov.w   #0x0990, R4
            ret
            
            clr.w   R4                      ; storage for 4-digit BCD
            mov.b   #8, R15                 ; loop cnt = # of bits
b2b_loop2   rla.b   R10                     ; use decimal addition
            dadd.b  R4, R4                  ; operation to convert R10
            dec.b   R15                     ; into BCD
            jnz     b2b_loop2     
            rla.w   R4
            rla.w   R4
            rla.w   R4
            rla.w   R4
	    ret
            
;---------------------------------------------------------------------------
display     swpb    R4                      ; display BCD in R4
            mov.b   R4, R14
            mov.b   R4, R15
            swpb    R4                      ; restore R4
            rrc.b   R14
            rrc.b   R14
            rrc.b   R14
            and.b   #0x1e, R14              
            add.w   #digit1, R14            ; R14 = address of the 1st digit
            and.b   #0x0F, R15
            rla.b   R15
            add.w   #digit2, R15            ; R15 = address of the 2nd digit
            mov.b   @R14+, &LCDM1           ; load the 1st digit 
            mov.b   @R14, &LCDM4            ; and clean the place for the 2nd
            add.b   @R15+, &LCDM1           ; load the 2nd digit
            mov.b   @R15, &LCDM5
            
            mov.b   R4, R14                 ; extract the 3rd digit
            rrc.b   R14
            rrc.b   R14
            rrc.b   R14
            and.b   #0x1e, R14
            mov.b   R14, R15
            clrc
            rrc.b   R15                             
            add     R15, R14                ; R14 *= 3
            add     #digit3, R14            ; R14 = address of the 3rd digit
            mov.b   @R14+, &LCDM7           ; load the 3rd digit and the
            mov.b   @R14+, &LCDM6           ; trailing letter C
            mov.b   @R14, &LCDM2
            
            bit.b   #BIT0, R7               ; postprocessing
            jz      end_disp
            xor.b   #0x70, &LCDM6           ; change letter from C to H
            xor.b   #0x50, &LCDM2
            bit.w   #0x0F00, R4             ; turn off leading 0 for HUMI
            jnz     $+12  
            clr.b   &LCDM5
            bic.b   #0xF0, &LCDM1
            ret
end_disp    bis.b   #BIT5, &LCDM1           ; turn on decimal point
            ret

;---------------------------------------------------------------------------             
delay       dec.w   R15                     ; the delay loop takes 5 CPU cycles             
            nop
            tst.w   R15
            jnz     delay
            ret            
            
;--------------------------------------------------------------------------            
digit1      DW      0                       ; do not display leading 0
            ;DW      0x3505                  ; digit 0
            DW      0x0005                  ; digit 1
            DW      0x7401                  ; digit 2
            DW      0x7005                  ; digit 3
            DW      0x4105                  ; digit 4
            DW      0x7104                  ; digit 5
            DW      0x7504                  ; digit 6
            DW      0x1005                  ; digit 7
            DW      0x7505                  ; digit 8
            DW      0x7105                  ; digit 9
            DW      0x4000                  ; the "-" symbol
            DW      0x1000                  ; the "^" symbol
            
digit2      DW      0x3550                  ; digit 0 
            DW      0x0050                  ; digit 1 
            DW      0x7410                  ; digit 2
            DW      0x7050                  ; digit 3
            DW      0x4150                  ; digit 4
            DW      0x7140                  ; digit 5
            DW      0x7540                  ; digit 6
            DW      0x1050                  ; digit 7  
            DW      0x7550                  ; digit 8
            DW      0x7150                  ; digit 9
            DW      0x2000                  ; the "_" symbol
            DW      0x1000                  ; the "^" symbol

digit3      DB      0x35                    ; digit 0 (LCDM7 part for C)
            DB      0x35                    ; digit 0 (LCDM6 part for C)
            DB      0x05                    ; digit 0 (LCDM2 part for C)
            DB      0x05                    ; digit 1 (LCDM7 part for C)
            DB      0x30                    ; digit 1 (LCDM6 part for C)
            DB      0x05                    ; digit 1 (LCDM2 part for C)
            DB      0x75                    ; digit 2 (LCDM7 part for C)
            DB      0x34                    ; digit 2 (LCDM6 part for C)
            DB      0x01                    ; digit 2 (LCDM2 part for C)
            DB      0x75                    ; digit 3 (LCDM7 part for C)
            DB      0x30                    ; digit 3 (LCDM6 part for C)
            DB      0x05                    ; digit 3 (LCDM2 part for C)
            DB      0x45                    ; digit 4 (LCDM7 part for C)
            DB      0x31                    ; digit 4 (LCDM6 part for C)
            DB      0x05                    ; digit 4 (LCDM2 part for C)
            DB      0x75                    ; digit 5 (LCDM7 part for C)
            DB      0x31                    ; digit 5 (LCDM6 part for C)
            DB      0x04                    ; digit 5 (LCDM2 part for C)
            DB      0x75                    ; digit 6 (LCDM7 part for C)
            DB      0x35                    ; digit 6 (LCDM6 part for C)
            DB      0x04                    ; digit 6 (LCDM2 part for C)
            DB      0x15                    ; digit 7 (LCDM7 part for C)
            DB      0x30                    ; digit 7 (LCDM6 part for C)
            DB      0x05                    ; digit 7 (LCDM2 part for C)
            DB      0x75                    ; digit 8 (LCDM7 part for C)
            DB      0x35                    ; digit 8 (LCDM6 part for C)
            DB      0x05                    ; digit 8 (LCDM2 part for C)
            DB      0x75                    ; digit 9 (LCDM7 part for C)
            DB      0x31                    ; digit 9 (LCDM6 part for C)
            DB      0x05                    ; digit 9 (LCDM2 part for C)
            DB      0x25                    ; the "_" symbol (LCDM7 & C)
            DB      0x30                    ; the "_" symbol (LCDM6 & C)
            DB      0x00                    ; the "_" symbol (LCDM2 & C)
            DB      0x15                    ; the "^" symbol (LCDM7 & C)
            DB      0x30                    ; the "^" symbol (LCDM6 & C)
            DB      0x00                    ; the "^" symbol (LCDM2 & C)

;---------------------------------------------------------------------------
bt1_ISR     bic.w   #LPM3, 0(SP)            ; return from sleep
            reti             
;------------------------------------------------------------------------------
;           Interrupt Vectors
;------------------------------------------------------------------------------
            ORG     0x0FFE0                 ; basic timer 1 vector
            DW      bt1_ISR

            ORG     0x0FFFE                 ; RESET Vector
            DW      RESET                   ;
            END