;;;
;;; 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
