;***************************************************************************
; Application:  Bit bang'in pwm
; Author:       Dan Williams
; Date:         feb 2 2004
; Assembler:    GAVRASM
; Target:       Atmel ATtiny13.
;***************************************************************************
;
;
;****************************************************************************

;.device ATtiny13 ; gavrasm
.include "m32def.inc"


; ------------- 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 PWMTemp2   = r20
.def PWMC2       = r21
.def PWMTemp1   = r22
.def PWMC1       = r23
.def PWMRamp    = r24
;.def _U         = 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  = INPUT
.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 PWMOut1   = 0  ; description
.equ PWMOut2   = 1  ; 
.equ THING2    = 2  ; 
.equ THING3    = 3  ;
.equ THING4    = 4  ;
.equ THING5    = 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))



;========================| SYSTEM VECTORS |===========================
;
.cseg                                   ;CODE segment
.org 0x0000
    rjmp    init   ; RESET 
    reti           ; EXT_INT0  
    reti           ; 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

        ; Init variales and subsystems
   ;     rcall pwm_init
   ;     rcall adc_init
        
        ;Enable interrupts
        sei   

        ldi  PWMC1, 0x3F    ;25%
        ldi  PWMC2, 0xBF    ;75%
MainLoup:
     
       ; copy data
   ;  IN  A, ADCH               ; copy data from adc
   ;  OUT OCR0A, A              ; to pwm
     
     rcall wait
     rcall bb_pwm_service
     
        rjmp    MainLoup                ; go back and do it all over again


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

; bit banged pwm 
bb_pwm_service:
  
   inc PWMRamp                    ; push up the ramp
   brne  ch1                      ; go test the first channel if were not at 0         
                  
     mov   PWMTemp1, PWMC1         ; copy new value to buffer
     cpse  PWMRamp, PWMTemp1      ; if duty not equal to 0% 
       sbi   PORTB, PWMOut1       ; turn the channel on
     
     mov   PWMTemp2, PWMC2         ; copy new value to buffer
     cpse  PWMRamp, PWMTemp2      ; if duty not equal to 0% 
       sbi   PORTB, PWMOut2       ; turn the channel on

  ch1:
    cpi    PWMTemp1, 0xFF         ; skip if duty 100%
    breq   ch2
      cp     PWMTemp1, PWMRamp    ; compare, 
      brne   ch2                  ; if not equal, do next channel
        cbi    PORTB, PWMOut1 ; else, turn channel off

  ch2:
    cpi    PWMTemp2, 0xFF         ; skip if duty 100%
    breq   ch3
      cp     PWMTemp2, PWMRamp    ; compare, 
      brne   ch3                  ; if not equal, do next channel
        cbi    PORTB, PWMOut2 ; else, turn channel off    
  ch3:
  bb_pwm_done:
 ret


wait:    
        ldi     B, 1              ; load count1 with decimal 200

d1:
        ldi     C, 1              ; load count2 with decimal 200

d2:
        ldi     D, 20

d3:
        dec     D
        brne    d3
        dec     C                  ; decrement count2
        brne    d2                 ; loop if not zero              
        dec     B                  ; decrement count1 if count2 is zero
        brne    d1                 ; do inside loop again if count2 nz
        ret
    



















