;***************************************************************************
; Application:  Led flasher
; Author:       Dan Williams
; Date:         
; Assembler:    AVR Studio 4.07.
; Target:       Atmel ATtiny13.
;***************************************************************************
;------ objective -----
;PB0  PWM1   
;PB1  PWM2   
;PB2  ANA2   
;PB3  SC
;PB4  SD
;PB5  ANA1  
;
;---- this test -----
;PB0  LED1
;PB1  LED2
;PB2  LED3
;PB3  SC
;PB4  SD
;PB5  LED4
;
;****************************************************************************

.device ATtiny13 

; ------------- Memory locations ---------------
;
;  .def bar =r01 ; one byte ram location
;
; ----------------------------------------------

; R 0 ->15 are gen. purp.

.def A          = r16    
.def B          = r17            ; and logic instructions
.def C          = r18
.def D          = r19

.def curstate   = r20
.def laststate  = r21
.def _R         = r22
.def bitcount   = r23
.def i2cstat    = r24
.def curbyte    = r25
.def _V         = r26
.def _w         = r27
.def _X         = r28
.def _Y         = r29
.def _Z         = r30


;cant use r25 -> r31

; ------------- Equates ------------------

.equ TRUE    = 1
.equ FALSE   = 0

.equ INPUT   = 0
.equ OUTPUT  = 1

; --- Port Directions ---
.equ PB0DIR  = OUTPUT
.equ PB1DIR  = OUTPUT
.equ PB2DIR  = OUTPUT
.equ PB3DIR  = INPUT
.equ PB4DIR  = INPUT
.equ PB5DIR  = OUTPUT

; --- Initial port state ---
.equ INPB0   = 0
.equ INPB1   = 0
.equ INPB2   = 0
.equ INPB3   = 0
.equ INPB4   = 0
.equ INPB5   = 0

; --- Port Names ---
.equ LED1    = 0  ; start /  stop
.equ LED2    = 1  ; 1 / 0
.equ LED3    = 2  ; 
.equ SC      = 3  
.equ SD      = 4  
.equ LED4    = 5  ; RESET

; --- amalgimate ---

.equ INITDIR   = ((PB5DIR<<DDB5)|(PB4DIR<<DDB4)|(PB3DIR<<DDB3)|(PB2DIR<<DDB2)|(PB1DIR<<DDB1)|(PB0DIR<<DDB0))
.equ INITSTATE = ((INPB5<<PORTB5)|(INPB4<<PORTB4)|(INPB3<<PORTB3)|(INPB2<<PORTB2)|(INPB1<<PORTB1)|(INPB0<<PORTB0))

; --- flags for i2cstat ---

.equ SELECTED  = 0
.equ DIRECTION = 1
.equ   SEND      = 0
.equ   RECIEVE   = 1
.equ BYTETYPE  = 2
.equ   ADDRESS   = 0
.equ   DATA      = 1
.equ DOACK     = 3
.equ BUFFER    = 4
.equ   EMPTY     = 0
.equ   FULL      = 1
.equ _e1       = 5
.equ _f1       = 6
.equ _g1       = 7


;========================| SYSTEM VECTORS |===========================
;
.cseg                                   ;CODE segment
.org 0x0000
    rjmp    init   ; RESET 
    reti           ; EXT_INT0  
    rjmp    event  ; PCINT0   (pin change)
    reti           ; TIM0_OVF  
    reti           ; EE_RDY  
    reti           ; ANA_COMP  
    reti           ; TIM0_COMPA  
    reti           ; TIM0_COMPB  
    reti           ; WATCHDOG  
    reti           ; ADC  

;=============================| MAIN |================================
;


.org 0x000A
init:   
        ; Set up stack
        ldi     A,   low(RAMEND)        ; load low address of ram to R16...
        out     SPL, A               ; Set Stack Pointer to top of RAM

        ; Disable interrupts
        cli        

        ; Set up io ports
        ldi   A,    INITSTATE
        out   PORTB, A
        ldi   A,    INITDIR
        out   DDRB,  A

        rcall irq_init
        
        ;Enable interrupts
        sei   


MainLoup:
     
        rjmp    MainLoup                ; go back and do it all over again


;========================| SUBROUTINES |==============================
;



irq_init:
   ; Interrupt on any edge
   ldi  A, 0x01     
   out  MCUCR, A
   ; Enable pin change inturrupt
   ldi  A, 0x20  
   out  GIMSK, A  
   ; Enable interrupts for PortB 3 and 4
   ldi  A, 0x18  
   out  PCMSK, A 
 ret


event:
;--- state detect
  clr   curstate
    
  ;bit copy data -> curstate:0   
  sbic  PINB, SD   ; is data not clear
    sbr  curstate, (1<<0)
  
  ;bit copy clock -> curstate:1   
  sbic  PINB, SC   ; is clock not clear
    sbr  curstate, (1<<1)
  
  ;lookup = laststate | curstate
  ;laststate = curstate >> 2
  bst   laststate, 0
  bld   curstate,  2
  bst   laststate, 1
  bld   curstate,  3
  
  ; laststate = curstate
  mov   laststate, curstate
  
  ;if lookup = 8  then call clock0 ; falling clock edge while data low *ALSO* ack *ALSO* sending nextbit
  cpi  curstate, 8
    breq  clock0 
  ;if lookup = 11 then call stop    ; data went high while clock high
  cpi  curstate, 11
    breq  stop 
  ;if lookup = 13 then call clock1 ; falling clock edge while data high *ALSO* sending nextbit
  cpi  curstate, 13
    breq  clock1 
  ;if lookup = 14 then call start   ; data went low while clock high
  cpi  curstate, 14
    breq  start 
  rjmp  irqdone

;---------
  
stop:
  cbi  PORTB, LED1  
  rjmp irqdone

;----------

start:
  sbi  PORTB, LED1
  clr  bitcount
  rjmp irqdone 

;---------

clock0:
  sbrs  i2cstat, DOACK
  rjmp databit
      ; clear the ack
      cbr i2cstat, (1<<DOACK) ; clear our flag
      cbi DDRB, SD           ; back to input
      rjmp irqdone  
  
databit:  
  clc
  rjmp  dobit
  
;----------- 
 
clock1:
  sec
  ;rjmp  dobit

;----------

dobit:
  rol  curbyte
  inc  bitcount
  cpi  bitcount, 8 ; if bitcount != 8 return
  brne irqdone
   ;rjmp havebyte

;----------
   
havebyte:
 ; test against our address 
  cpi curbyte, 0xDA 
    
  ; set the "selected" led  
  breq bitset
    cbi  PORTB, LED2
bitset:       
  brne bitclear
    sbi  PORTB, LED2
bitclear:  

doack:
; set 'doing ack' = true
  sbr i2cstat, (1<<DOACK)
  cbi PORTB, SD  ; set data low.
  sbi DDRB, SD   ; output it.
  ;rjmp irqdone
;---------        

irqdone:
  reti
























