All pastes #772605 Raw Edit

Unnamed

public text v1 · immutable
·published 2007-11-13 22:40 UTC
rendered paste body
TCNT = 0x100E
OUT_PORT = 0x1008
DATA_RATE = 1000 ; bits per second
TOC_COUNT = 1000 ; 2000000 / DATA_RATE / 2
TOC3 = 0x101A
TCTL1 = 0x1020
TFLG1 = 0x1023

MOTORS = 0x7000
LEFT_FORWARD   = 0b00100000
LEFT_BACKWARD  = 0b00100010
RIGHT_FORWARD  = 0b00010000
RIGHT_BACKWARD = 0b00010001
OFF = 0x0
RIGHT_ANGLE_TIME = 16

CMD_START_RECEIVE = 0b1 ; 1
CMD_STOP_RECEIVE = 0b10 ; 2
CMD_FORWARD = 0b100 ; 4
CMD_BACKWARD = 0b101 ; 5
CMD_TURN_LEFT = 0b110 ; 6
CMD_TURN_RIGHT = 0b111 ; 7
CMD_ROTATE_LEFT = 0b1000 ; 8
CMD_ROTATE_RIGHT = 0b1001 ; 9
CMD_DRAW_SQUARE = 0b1010 ; 10
CMD_DRAW_SHAPE = 0b1011 ; 11
CMD_WAIT = 0b00001100 ; 12


TCTL2 = 0x1021 ;[edg4b, edg4a, edg1a, edg1b, edg2b, edg2a, edg3b, edg3a]
TMSK1 = 0x1022 ;[7, 6, 5, 4, 3, IC1, IC2, IC3]
TFLG1 = 0x1023 ;[7, 6, 5, 4, 3, IC1F, IC2F, IC3F]
TIC3DATA = 0x1014
TIC3VECTOR = 0xBFEA
IN_PORT = 0x1000
IN_PORT_MASK = 1



MY_ADDRESS = 0b101

;==================
; READ-ONLY DATA
;==================
.section .rodata

; header: slave address, master address, data length, reserved, reserved, reserved
samplePacket: .byte 0b00001000, 0, samplePacketEnd-samplePacketData, 0, 0, 0
; data
samplePacketData: .byte CMD_START_RECEIVE, CMD_FORWARD, 15, CMD_BACKWARD, 15
;.byte CMD_TURN_RIGHT, 10, CMD_TURN_LEFT, 10, CMD_ROTATE_RIGHT, 15, CMD_ROTATE_LEFT, 15
	;.byte CMD_DRAW_SQUARE, CMD_WAIT, 20, CMD_DRAW_SHAPE

	.byte CMD_FORWARD, 1
	.byte CMD_WAIT, 1
	.byte CMD_FORWARD, 1
	.byte CMD_WAIT, 1
	.byte CMD_FORWARD, 1
	.byte CMD_WAIT, 1
	
	
	.byte CMD_STOP_RECEIVE
samplePacketEnd:

myAddress: .byte MY_ADDRESS


;==================
; DATA
;==================
.section .data
time: .byte 20 			; an argument to the wait subroutine
startReceiveMode: .byte 0 	; boolean for "are we in Start Receive mode?"
doCommandMode: .byte 0 		; boolean for "should we be doing commands?"


rbInsertionPointer: .word ringBuffer
rbExtractionPointer: .word ringBuffer
rbCount: .byte 0 	; how many command-time pairs are in the ring buffer



receiving: .byte 0 		; boolean - are we currently receiving data?
lastTIC: .word 0 			; what was the last TIC value
mask: .byte 0b10000000 		; which bit are we on?
byteCount: .byte 0		; how many bytes have we received?

;==================
; UNINITIALIZED
;==================
.section .bss

; The packet contains all the bytes sent in one packet.
; The receiver ISR puts the bytes here.
; It is the job of decodePacket to move command-time pairs to the ring buffer
thePacket: rmb 261 ; max packet size is 261 bytes

; The ring buffer has ONLY command-time pairs. If a DrawSquare or DrawShape is received, the decodePacket fakes a time
ringBuffer: rmb 200 ; reserve 200 bytes for ring buffer
ringBufferEnd:






;==================
; TEXT
;==================
.section .text

.global _start
_start:
	lds #_stack
	
	ldaa #0b00000011 		; set both edges on edg3
	staa TCTL2

	ldaa #1
	staa TMSK1 			; set enable TIC3

	ldaa #1 			; clear interrupt flag
	staa TFLG1


	; set up jump table entry
	ldx #0x00E2
	ldaa #0x7E
	staa 0,x
	ldy #theISR
	sty 1,x

	ldx #theISR
	stx TIC3VECTOR
	
	
	
	; set DDRD for transmitting
	ldaa #0b00111111
	staa 0x1009
	ldaa #255
	staa OUT_PORT 		; quiet voltage is high



	cli
	

	9:
	ldaa 0x7FFF
	anda #0b10000000
	bne 1f
	      ; execute this code if the start button is pressed
	      ; send some data
		jsr sendZero 	; start bit
		ldx #samplePacket
		ldab #(samplePacketEnd-samplePacket)
		2:
		ldaa 0,x
		jsr sendByte
		inx
		decb
		bne 2b
		jsr sendOne		; stop bit
		jsr sendOne 	; stop bit
		
		3: 			; debounce loop
		ldaa 0x7FFF
		anda #0b10000000
		beq 3b
		jsr wait100ms
	1:
	
	ldaa 0x7FFF
	anda #0b01000000
	bne 4f
	       ; execute this code if the stop button is pressed
	       ldaa #1
	       staa doCommandMode ; no need to debounce this one
	4:
	
	
	jsr doCommand 		; do a command, if there is one, and if 						;  doCommmandMode!=0
	jsr stopMotors
	
	bra 9b 			; loop forever
	
	
	
	
; The interrupt subroutine	
theISR:
	sei
	ldaa receiving
	bne 1f
	; this is the start edge we just got
	ldaa #0x76
	staa receiving
	ldaa #0
	staa byteCount
	ldaa #0b10000000
	staa mask
	bra theISRPreExit
	1:
	
	; not the start edge
	ldd TIC3DATA
	subd lastTIC 		; thisTIC - lastTIC -> D
	cmpa #6 ; if A<6 then D<1536 and this edge is not a bit
	bge 2f
	bra theISRExit 		; throw away this edge
	2:
	
	; it is a bit
	ldab byteCount
	ldx #thePacket
	abx ; get x to point to the byte
	ldaa mask
	cmpa #0b10000000
	bne 101f
	clra
	staa 0,x 			; if it is a new byte, clear it
	101:
	ldab IN_PORT
	andb #IN_PORT_MASK
	beq 3f
	
	; it is a 1

	ldaa 0,x
	oraa mask
	staa 0,x
	bra 4f
	3:
	
	; it is a 0
	ldaa 0,x
	oraa mask
	eora mask
	staa 0,x
	4:
	
	; adjust the mask
	ldaa mask
	clc
	rora
	bcc 5f 			; if the mask was not 0000 0001
	ldaa #0b10000000 		; the mask was 1 reset to 1000 0000
	ldab byteCount 		; and increment the byte count
	incb
	stab byteCount
	5:
	staa mask
	
	
	; if the packet is complete call decodePacket
	ldab byteCount
	cmpb #3 			; byte three is the data length
	blo 6f 			; packet obiously not complete
	ldx #thePacket
	ldaa 2,x			; Data length -> A
	adda #6			; packet length -> A
	suba byteCount
	bne 6f 			; packet not complete
	
	; check if we've gotten two stop bits
	;ldab byteCount
	;ldx #thePacket
	;abx
	;ldaa 0,x
	;cmpa #0xC0
	ldaa mask
	anda #0b00100000
	beq 6f
	
	; OK, we have a whole packet
	ldaa #0
	staa receiving
	staa byteCount
	ldaa #0b10000000
	staa mask
	jsr decodePacket
	
	6:
	
	
	theISRPreExit:
	ldx TIC3DATA
	stx lastTIC
	
	theISRExit:
	ldaa TFLG1
	oraa #1
	staa TFLG1
	rti
	

sendByte:
	;byte is in A
	bita #0b10000000
	beq 1f
	jsr sendOne
	bra 2f
	1:
	jsr sendZero
	2:
	
	bita #0b01000000
	beq 3f
	jsr sendOne
	bra 4f
	3:
	jsr sendZero
	4:
	
	bita #0b00100000
	beq 5f
	jsr sendOne
	bra 6f
	5:
	jsr sendZero
	6:

      bita #0b00010000
	beq 7f
	jsr sendOne
	bra 8f
	7:
	jsr sendZero
	8:
	
	bita #0b00001000
	beq 9f
	jsr sendOne
	bra 10f
	9:
	jsr sendZero
	10:
	
	bita #0b00000100
	beq 11f
	jsr sendOne
	bra 12f
	11:
	jsr sendZero
	12:
	
	bita #0b00000010
	beq 13f
	jsr sendOne
	bra 14f
	13:
	jsr sendZero
	14:
	
	bita #0b00000001
	beq 15f
	jsr sendOne
	bra 16f
	15:
	jsr sendZero
	16:
	
	rts

	
sendOne:
	psha
	pshb
	
	ldaa #0
	staa OUT_PORT
	ldd TCNT
	addd #TOC_COUNT
	std TOC3
	ldaa TFLG1
	oraa #0b00100000
	staa TFLG1
	1:
	ldaa TFLG1
	anda #0b00100000
	beq 1b
	
	
	ldaa #255
	staa OUT_PORT
	ldd TCNT
	addd #TOC_COUNT
	std TOC3
	ldaa TFLG1
	oraa #0b00100000
	staa TFLG1
	2:
	ldaa TFLG1
	anda #0b00100000
	beq 2b
	
	pulb
	pula
	rts

sendZero:
	psha
	pshb

	ldaa #255
	staa OUT_PORT
	ldd TCNT
	addd #TOC_COUNT
	std TOC3
	ldaa TFLG1
	oraa #0b00100000
	staa TFLG1
	1:
	ldaa TFLG1
	anda #0b00100000
	beq 1b


	ldaa #0
	staa OUT_PORT
	ldd TCNT
	addd #TOC_COUNT
	std TOC3
	ldaa TFLG1
	oraa #0b00100000
	staa TFLG1
	2:
	ldaa TFLG1
	anda #0b00100000
	beq 2b

	pulb
	pula
	rts
	
	


decodePacket:
	pshy
	pshx
	psha
	pshb
	
	


	
	
	ldx #thePacket
	ldaa 0,x
	cmpa myAddress
	beq 1f 			; the address is ours
	cmpa #0b00001111
	beq 1f 			; the address is the broadcast address
	bra decodePacketExit 	; this packet is not intended for us


	1: 				; this packet is intended for us

	
	inx
	; don't need to do anything w/ master address for now
	
	inx
	ldab 0,x 			; store data length in B
	
	; next 3 are reserved
	inx
	inx
	inx
	
	
	
	; Hacked in because the start receive must be first if we're not in 	start receive mode
	ldaa startReceiveMode
	bne 9f
	inx 				; if we are not in start mode...
	ldaa 0,x
	cmpa #CMD_START_RECEIVE
	bne decodePacketExit 	; we need to exit if the first byte is not a 						StartReceive command
	dex
	9:
	
	
	; The Main Loop of this subroutine
	; current command is at X+1
	; remaining data length is in B
	
	2:
	inx
	ldaa 0,x ; get command in A
	
	; CASE 1: start receive
	cmpa #CMD_START_RECEIVE
	bne 3f
		ldaa #0
		staa rbCount 		; set count=0
		ldaa #1
		staa startReceiveMode 	; set startReceiveMode = 1
	
		ldy rbInsertionPointer
		sty rbExtractionPointer ; move extraction pointer to insertion 							pointer
		
		decb
		beq decodePacketExit 	; last byte? then exit
		bra 2b ; loop
	3:
	
	; CASE 2: stop receive
	cmpa #CMD_STOP_RECEIVE
	bne 4f
	        ldaa #0
	        staa startReceiveMode ; set startReceiveMode = 0
	        
		decb
		beq decodePacketExit 	; last byte? then exit
		bra 2b 			; loop
	4:
	
	; CASE 3: command-time pair, but not in startReceiveMode
	; TODO this case can be eliminated since the startReceive must come at 	the beginning of a packet
	; WARNING note the CASE 4 pula
	psha
	ldaa startReceiveMode
	bne 5f
	pula
	decb 					; first byte of command-time pair
	inx
	decb 					; second byte of command-time pair
	beq decodePacketExit
	bra 2b ; loop
	
	
	5: 					; CASE 4: command-time pair in 								startReceiveMode WARNING must pula 	from 							case 3
	pula
	
	ldy rbInsertionPointer
	
	staa 0,y 				; store first byte
	
	iny 					; increment insertion pointer
	cpy #ringBufferEnd
	bne 81f
	ldy #ringBuffer
	81:
	
	
	cmpa #CMD_DRAW_SQUARE 		; Pay Attention!!! - we're faking time 							arguments for the two commands that don't 						come with times
	beq noTimeProvided
	cmpa #CMD_DRAW_SHAPE
	beq noTimeProvided
	
	; a time argument is provided by the packed
	decb
	inx
	ldaa 0,x 				; get next byte
	staa 0,y 				; store second byte
	bra 6f
	
	
	; no time argument is provided by the packet, so let's fake it
	noTimeProvided:
	ldaa #20 				; 2 seconds per side should be OK
	staa 0,y 				; store second byte (faked)
	
	
	6:
	
	iny
	cpy #ringBufferEnd
	bne 82f
	ldy #ringBuffer
	82:
	
	sty rbInsertionPointer 		; save moved insertion pointer
	
	ldaa rbCount
	inca
	staa rbCount ; rbCount++
	
	decb
	bne 2b ; more bytes? then loop
	
decodePacketExit:
	pulb
	pula
	pulx
	puly
	rts



; If rbCount > 0 this subroutine will
; Pick the command from the ring buffer (1 byte)
; Pick the time from the ring buffer (1 byte)
; Do the command for the amount of time
; rbExtractionPointer += 2
; rbCount--
doCommand:
	pshx
	psha
	pshb
	
	ldaa doCommandMode
	beq doCommandExit 		; if doCommandMode == 0, exit
	
	ldaa rbCount
	beq doCommandExit 		; if count == 0, exit
	
	deca
	staa rbCount ; rbCount--
	
	ldx rbExtractionPointer
	ldaa 0,x ; store command in A
	
	inx
	cpx #ringBufferEnd
	bne 61f
	ldx #ringBuffer
	61:
	
	ldab 0,x ; store time in B
	
	inx
	cpx #ringBufferEnd
	bne 62f
	ldx #ringBuffer
	62:
	
	stx rbExtractionPointer 	; rbExtractionPointer += 2
	stab time 				; pass the time argument to whatever 							function will be called
	
	deca
	bne 1f
	; start receive
	1:
	
	deca
	bne 2f
	; stop receive
	2:
	
	deca
	bne 3f
	; nothing
	3:
	
	deca
	bne 4f
	jsr moveForward
	4:
	
	deca
	bne 5f
	jsr moveBackward
	5:
	
	deca
	bne 6f
	jsr turnLeft
	6:
	
	deca
	bne 7f
	jsr turnRight
	7:
	
	deca
	bne 8f
	jsr rotateLeft
	8:
	
	deca
	bne 9f
	jsr rotateRight
	9:
	
	deca
	bne 10f
	pshx
	ldx #1000
	jsr drawSquare
	pulx
	10:
	
	deca
	bne 11f
	pshx
	ldx #1000
	jsr drawShape
	pulx
	11:
	
	deca
	bne 12f
	jsr stopMotors ; wait command
	jsr wait
	12:
	
	
	
doCommandExit:

	ldaa rbCount
	bne 2001f
	ldaa #0
	staa doCommandMode 		; clear doCommandMode if the ring 							buffer is empty
	2001:
	
	pulb
	pula
	pulx
	rts


stopMotors:
	psha
	ldaa #OFF
	staa MOTORS
	pula
	rts

moveForward:
	psha
	ldaa #(LEFT_FORWARD | RIGHT_FORWARD)
	staa MOTORS
	pula
	
	jsr wait
	
	rts

moveBackward:
	psha
	ldaa #(LEFT_BACKWARD | RIGHT_BACKWARD)
	staa MOTORS
	pula
	
	jsr wait
	
	rts
	
turnLeft:
	psha
	ldaa #(RIGHT_FORWARD)
	staa MOTORS
	pula
	
	jsr wait
	
	rts

turnRight:
	psha
	ldaa #(LEFT_FORWARD)
	staa MOTORS
	pula
	
	jsr wait
	
	rts
	
rotateLeft:
	psha
	ldaa #(LEFT_BACKWARD | RIGHT_FORWARD)
	staa MOTORS
	pula
	
	jsr wait
	
	rts

rotateRight:
	psha
	ldaa #(LEFT_FORWARD | RIGHT_BACKWARD)
	staa MOTORS
	pula
	
	jsr wait
	
	rts


drawSquare:
	psha
	pshb
	pshy


	; do 4 times
	ldaa #4
	1:

	; turn left
	ldy time
	ldab #RIGHT_ANGLE_TIME
	stab time 				; set time
	jsr turnLeft
	sty time 				; restore time

	; drive forward
	jsr moveForward

	deca
	bne 1b


	; return
	puly
	pulb
	pula
	rts


drawShape:
	psha
	pshb
	pshy
	
	
	; do 3 times
	ldaa #3
	1:
	
	; turn left
	ldy time
	ldab #RIGHT_ANGLE_TIME * 120 / 90
	stab time 				; set time
	jsr turnLeft
	sty time 				; restore time

	; drive forward
	jsr moveForward
	
	deca
	bne 1b
	
	
	; return
	puly
	pulb
	pula
	rts
	
	
	

; This subroutine waits for the number of tenths of seconds
; specified by the "time" variable
wait:
	psha
	
	ldaa time
	1:
	jsr wait100ms
	deca
	bne 1b
	
	pula
	rts
	
	
wait100ms:
	pshx
	
	ldx #100
	1:
	bsr wait1ms
	dex
	bne 1b
	
	pulx
	rts
	
        
wait1ms:
	  psha                ; 1 ms wait
        tpa
        psha
        pshx
        ldx     #200
2:      dex
        nop
        nop
        bne     2b
        pulx
        pula
        tap
        pula