;;;
;;; stepper.asm
;;; by Neil Gershenfeld <neilg@cba.mit.edu>
;;; heavily modified by Raffi Krikorian <raffi@media.mit.edu>
;;;
;;; drive a motor controller from jameco (part number 117954) to the left
;;; for a given number of clicks, then back to the right for the same number
;;; of clicks.

        
.include "tn15def.inc"          ; include the file specific to the attiny15

;;;
;;; DEFINITIONS
;;; 
        
;;; define certain registers to be temporary storage locations 
.def temp0 = R16                
.def temp1 = R17
.def temp2 = R18
.def temp3 = R19
.def temp4 = R20
        
;;; some constants that we are going to be using in the code
.equ on_count = 20              ; the length of time the "pulse" is on
.equ off_count = 5              ; the length of time the "pulse" is off
.equ pulse_count = 20           ; how many times to actually pulse each port

;;; and map the wires going to the stepper controller to some variables that we
;;; are going to be using in the codebase
.equ brown_motor = PB2
.equ black_motor = PB1
.equ yellow_motor = PB0
.equ orange_motor = PB3


;;;
;;; CODE SEGMENT
;;; 
        
.cseg                           ; start the code segment at memory location 0.  
.org 0                          ; because the reset vector places us here, the
rjmp main                       ; first thing is to jump to the main block


;;;
;;; the generic function to pulse a specific stepper motor port
;;;
;;; given a PB number in temp3 that we want to pulse, this function pulses that
;;; motor port (using PWM to current limit).  this function is called by the
;;; corresponding pulse_brown, pulse_black, etc., blocks
;;; 
pulse_motor:
        ;; convert the temp3 into a bit value that we want to manipulate.  b/c
        ;; it is just a number in R19, we actually want to bit shift that value
        ;; over
        ldi temp0, 0x01         ; put a bit in temp0
_pm_shift_loop:
        dec temp3               ; decrement the number of shifts that we have to
        brmi _pm_shift_loop_done ; do, and if we are negative (-1) we are done
        lsl temp0               ; shift the bit over
        rjmp _pm_shift_loop
_pm_shift_loop_done:
        mov temp3, temp0        ; temp3 <- temp0
        in temp4, PORTB         ; temp4 <- PORTB
        or temp4, temp3         ; PORTB <- PORTB | temp3 (turn on the motor bit)
        in temp3, PORTB         ; temp3 <- PORTB (like temp4 w/ motor bit off)

        ;; now start the loop for the actual pulsing that we are going to do
        ldi temp0, pulse_count  ; temp0 <- pulse_count
_pm_loop_0:
        ldi temp1, pulse_count  ; temp1 <- pulse_count
_pm_loop_1:
        ldi temp2, on_count     ; temp2 <- on_count
        out PORTB, temp4        ; turn on the motor bit in PORTB
_pm_on:
        dec temp2               ; temp2 <- temp2 - 1
        brne _pm_on             ; if temp2 != 0, then goto _pm_on

        ldi temp2, off_count    ; temp2 <- off_count
        out PORTB, temp3        ; turn off the motor bit in PORTB
_pm_off:
        dec temp2               ; temp2 <- temp2 - 1
        brne _pm_off            ; if temp2 != 0, then goto _pm_off

        dec temp1               ; temp1 <- temp1 - 1
        brne _pm_loop_1         ; if temp1 != 0, then goto _pm_loop_1
        
        dec temp0               ; temp0 <- temp0 - 1
        brne _pm_loop_0         ; if temp0 != 0, then goto _pm_loop_0

        ret                     ; return out of this function

        
;;;
;;; pulse the yellow motor controller port
;;; 
pulse_yellow:
        ldi temp3, yellow_motor ; temp3 <- value yellow_motor
        rcall pulse_motor       ; call pulse_motor to pulse the yellow port
        ret

        
;;;
;;; pulse the black motor controller port
;;; 
pulse_black:
        ldi temp3, black_motor  ; temp3 <- value black_motor
        rcall pulse_motor       ; call pulse_motor to pulse the black port
        ret

        
;;;
;;; pulse the brown motor controller port
;;; 
pulse_brown:
        ldi temp3, brown_motor  ; temp3 <- value brown_motor
        rcall pulse_motor       ; call pulse_motor to pulse the brown port
        ret


;;;
;;; pulse the orange motor controller port
;;; 
pulse_orange:
        ldi temp3, orange_motor ; temp3 <- value orange_motor
        rcall pulse_motor       ; call pulse_motor to pulse the orange port
        ret

        
;;;
;;; the function to step the stepper to the right by one click
;;;
;;; this just pulses the appropriate stepper.  remember to drive a stepper motor
;;; you have to drive one of the windings, then the other winding, then drive
;;; the windings in the opposite directions.  if you are driving a stepper that
;;; you don't know anything about, you can determine which are connected by
;;; taking a multimeter and probing for the connected lines.
;;; 
step_right:
        rcall pulse_brown       
        rcall pulse_yellow
        rcall pulse_black
        rcall pulse_orange
        ret

        
;;;
;;; drive the stepper in the other direction
;;;
;;; see step_right to for a small discussion on how to drive a stepper.
;;; 
step_left:
        rcall pulse_brown
        rcall pulse_orange
        rcall pulse_black
        rcall pulse_yellow
        ret

        
;;;
;;; the main block
;;;
;;; this block simply sits in a loop and moves the stepper to the right a bunch
;;; of clicks, and then moves to back to the left a bunch of clicks
;;; 
main:
        ;; clock the processor as fast as it can go -- this is pretty much safe
        ;; because we are not going to be communicating or synchronizing with
        ;; another processor.  if we were to be worrying about that, then
        ;; we would just leave this line out as the processor would load the
        ;; calibration byte into this location.
        ldi temp0, 0xFF
        out OSCCAL, temp0

        ;; now we have to configure the "direction" of the I/O pins.  remember,
        ;; setting a bit to 1 in the DDRB (the data direction register) will
        ;; make the corresponding pin an output.  if the bit is a 0, the
        ;; corresponding pin is an input.
        ;;
        ;; we want to make bits 0->3 all 1's (PB0, PB1, PB2, and PB3).  that
        ;; means that we are loading a 0x0F into DDRB.  this is because, in
        ;; binary, 0x0F represents 0b00001111 (with the most significant bit
        ;; being the left most bit)
        ldi temp0, 0x0F
        out DDRB, temp0

        ;; now we just have a loop which moves the stepper to the right 8 times,
        ;; then moes the stepper to the left 8 times.  over and over and over.
loop:   
        rcall step_right
        rcall step_right
        rcall step_right
        rcall step_right
        rcall step_right
        rcall step_right
        rcall step_right
        rcall step_right
        rcall step_left
        rcall step_left
        rcall step_left
        rcall step_left
        rcall step_left
        rcall step_left
        rcall step_left
        rcall step_left
        rjmp loop               ; and jump back to the loop label to start again