;Copyright 2004 Richard Cappels, projects@cappels.org
;Program Name: VLFCW -Make 181.818181818181...kHz from 4 Mhz crystal 

;vlfcw040711B	Changed some macros to subroutines.

;Reload and prescale values
.equ	XmtTimerReload	= $BC	;Timer 0 reload value for T
.equ	RcvTimerReload	= $EF	;Timer 0 reload value for T/4
.equ	RecThresh	=  40	;Minimum number of counts to detect carrier.

.equ	Timer0Prescale	= $03	;Timer 0 prescaler selector

.equ	delaytime	= 20	;Waiting time after transmit mode before receiving.


;Four callable routines are available. One register isnot saved, RFByte, which is
;used to transfer the data between the RF routines and calling routines and is
;to be a high register (r16-r31). It needs to be delcared as such in program calling this file..
;Calling other routines may result in modification of other registers. 
;	
;SendRFByte	(subroutine)
;Sends contents of RFChar via RF. Modifies RFChar.

;
;ReceiveRFByte	(subroutine)
;Waits for start bit on RF channel for 63.75 bit times. Returns with carry set and 
;data in RFChar if character received. Returns with carry clear if no byte received.

	
;		
;PostXmitDelay	;(macro)	;Wait for antenna to stop ringing from xmit.
;Use this delay after transmitting if listening is to follow. The delay allows
;ringing in the antenna to die down so that the ringing is not misatken as data.


;PostRCVDelay	;(macro)	;Wait for far end receiver to recover.	
;Use this after receiving data, before sending to give the receiver associated
;with the transmitter that just sent data to recover.	
;	
;
;
;
;
;
;
;
;
;
;
;Reference circuit:
;AT90S2313 microcontroller with 4 MHz clock.

;A resonant loop antennat tuned to 182 kHz is connected across the comparitor intputs, PORTB,0
; and PORTB,0.

;One such resonant circuit is 14 turns of #30 wire on 5.5 cm in diameter, air core, brought into
;resonance with a .033 uf capacitor in parallel with it.

;BPORTB,1 is also connected to the tap on a 2:1 resistive voltage devider. Both resistors in the 
;devider are of the same vlaue and may range from about 220 Ohms to 1 k Ohms each.

;The voltage devider may be power from the microcontroller's positive power supply, or optionally,
;powered from one of its output pins PORTB,2 has been designated for this purpose. Powering
;from an output pin allows power reduction during sleep.

;PORTB,3 is intended to drive an activity indicator LED. It goes high briefly while transmitting
;and receiving data over the RF link.


;*************Code for calling file found below .exit command, below*****************

;//////////////BEGIN BASIC RF COUPLER ROUTINES\\\\\\\\\\\\\\\
	
	
.macro	pushall

	push	r2	;	
	push	r18		;
	push	r17		;
	push	r19;		
					
.endmacro											
						
					
.macro	popall					
	pop	r19;		;Temporaty storage of status register
	pop	r17		;;General purpose scratch register
	pop	r18		;General purpose scratch register.
	pop	r2	;	;Comparitor interrupt counters
											
.endmacro											
											



PostXmitDelay:
	ldi	r18,delaytime
	rcall	delay
	ret



PostRCVDelay:
	ldi	r18, 2 * delaytime
	rcall	delay
	ret	
	
	
	
delay:					;Delay - load 00 into r18 for max delay, 01 for minimum delay.
					;r18 and r17 destroyed.
lptrf1:	clr	r17
lptrf12:	dec	r17
	brne	lptrf12
	dec	r18
	brne	lptrf1
	ret
	

ReceiveRFByte:				;Receive a byte by RF and put into RFChar
					;Returs with carry set if data received, otherwise cleared.
	pushall				;Save  working registers on stack
	ldi 	r18,Timer0Prescale	;Initaize prescaler.
	out 	TCCR0, r18
	ldi 	r18, RcvTimerReload	;Initialize counter.
	out 	TCNT0,r18
	ldi 	r18, $02		;Enable interrupts TIMSK.
	out 	TIMSK,r18

	clr	r2			;Zero comparitor interrupt counter.
	ldi	r17,0b00001011		;Comparitor setup: enable interrupt on positive edge.
	out	ACSR,r17

	clr	r17			;Clear start bit test counter.
	
wfsbrf1:					;Wait for start bit.
	rcall	QCDrf1			;Sample for 1/4 bit time.
	dec	r17			;See if too many consecutive unsuccessful samples.
	breq	bailrf1
	
	mov	r18,r2
	cpi	r18,RecThresh		;Check number of carrier cycles against threshold.
	brmi	wfsbrf1
	
	rcall	QCDrf1			;Wait T/4.
	rcall	QCDrf1			;Wait T/4.

	ldi	r17,8			;Set number of bits: 8 data.
nbrf1:

	sbi	LEDOutPort,LEDOutPin
	
	rcall	QCDrf1			;Wait T/4.
	rcall	QCDrf1			;Wait T/4.
	rcall	QCDrf1			;Wait T/4.
	clr	r2
	rcall	QCDrf1			;Sample for 1/4 bit time <== use this sample
	
	
	mov	r18,r2
	cpi	r18,RecThresh		;Set carry true if threshold exceeded.
	brpl	oirf1
	clc
	rjmp	zeinrf1
oirf1:	sec
zeinrf1:	ror	RFChar		;Get carry into lsb of RFChar.
	
	dec	r17
	brne	nbrf1

	sec				;Data received - set carry flag
rcxtrf1:
	ldi	r18,0
	out	TCCR0,r18		;Turn off timer0 interrupt
	out	ACSR,r18		;Turn off Comparitor interrupt	
	cbi	LEDOutPort,LEDOutPin			
	popall
	ret
bailrf1:clc				;No data received - clear carry and return	
	rjmp	rcxtrf1	
	
	

SendRFByte:				;Shift byte in RFChar out through RF channel.
					;RFChar changed by routine.
	pushall				;Save all working registers except RFChar.
	sbi	LEDOutPort,LEDOutPin	;For indication purposes

	ldi 	r18,Timer0Prescale	;Initaize prescaler
	out 	TCCR0, r18
	ldi 	r18, XmtTimerReload	;Initialize counter 
	out 	TCNT0,r18
	ldi 	r18, $02		;Enable interrupts TIMSK
	out 	TIMSK,r18
	ldi	r17,11		;Set number of bits:1 start, 8 data, 2 stop
	sec				;Start bit					
nxbtrf1:
	brcs	bitsonerf1	
	rcall	szerorf1	
	rjmp	iwzrf1
bitsonerf1:
	sbi	RFSigDDR,RFSigPin 	;Set signal output pin to output.
	rcall	SendOnerf1
	cbi	RFSigDDR,RFSigPin 	;Set signal output pin to input.
iwzrf1:
	lsr	RFChar			;Shift next bit into carry.
	dec	r17			;Decrement bit counter.
	brne	nxbtrf1			;If not all done, then continue.
	out	TCCR0,RFChar		;(RFChar was cleared by shifting.)	
	cbi	RFSigPort,RFSigPin 	;Set signal output low (no pullup).
	cbi	LEDOutPort,LEDOutPin
	popall				;Restore all working registes except RFChar.
	ret


szerorf1:				;Send no carrier for for one bit time.
	ldi 	r18, XmtTimerReload	;Initialize counter 
	out 	TCNT0,r18
WaitNotSend:
	rjmp	WaitNotSend		;Do nothing but wait for interrupt to yank out of loop.




SendOnerf1:				;Send carrier for T us
	ldi 	r18, XmtTimerReload	;Initialize counter 
	out 	TCNT0,r18		;Send carrier until next interruput
MakeRF1:				;Make 181.8181 Mhz
	sbi	RFSigPort,RFSigPin	;Output High sbi and cbi are 2 clock instructions.
	sbi	RFSigPort,RFSigPin	
	sbi	RFSigPort,RFSigPin
	sbi	RFSigPort,RFSigPin
	sbi	RFSigPort,RFSigPin
	nop				;(need this nop for timing)

	cbi	RFSigPort,RFSigPin	;Output Low
	cbi	RFSigPort,RFSigPin
	cbi	RFSigPort,RFSigPin
	cbi	RFSigPort,RFSigPin
	nop
	rjmp	MakeRF1			;Interrupt will yank out of loop.
	


QCDrf1:				;Send no carrier for T/3 us
	ldi 	r18, RcvTimerReload	;Initialize counter 
	out 	TCNT0,r18
WaitHere1:
	rjmp	WaitHere1		;Send no carrier until next interruput



timer0service:				;Return to routine that called interrupted routine. The processor 
					;must be in a subroutine when this interrupt occurs!  Disable 
					;the timer the rest of the time.
	pop	r18
	pop	r18
	reti				;Return from interrupt.to routine before interrupt
	
	
comparitorservice:			;Increment r18 upon comparitor interrupt.	
	in	r19,sreg		;Save status register.
	inc	r2		;Increment SigCount.
	out	sreg,r19		;Restore status register.
	reti				;Return from interrupt. Total of 7 cycles including the return.
	
;//////////////END BASIC RF COUPLER ROUTINES\\\\\\\\\\\\\\\	
			
	
	

.exit






;******************** Below is code for the calling file *****************************.

;Inlcude the code below in the calling file. It may be customized. Copy the code from here
;to ".exit" into the calling document. 
	

;Copyright 2004 Richard Cappels, projects@cappels.org
;Program Name: VLFCW -Make 181.818181818181...kHz from 4 Mhz crystal 


;////////////////// START OF INITIALIZATION CODE \\\\\\\\\\\\\\\\\\\\\\\\\

.include "2313def.inc"		;Include file in same directory as project.


.equ	RFSigPort	= PORTB	;Port output signal is to appear on.
.equ	RFSigDDR	= DDRB	;Data Direction Register for signal output
.equ	RFSigPin	= 0	;Pin output signal is to appear on.

.equ	LEDOutPort	= PORTB	;Indicator LED
.equ	LEDOutDDR	= DDRB
.equ	LEDOutPin	= 3

.equ	CompPlusPort	= PORTB	;Comparitor noninverting input (input 0)
.equ	CompPlusDDR	= DDRB
.equ	CompPlusPin	= 0

.equ	BridgePowerPort	= PORTB	;Power for bridging resistors
.equ	BridgePowerDDR	= DDRB
.equ	BridgePowerPin	= 2


.def	temp		= r18	;General purpose scratch register.

.def	RFChar		= r16	;RF character I/O buffer


;definition of I/O
;B0	+ comparitor input - Antenna Signal
;B1	- comparitor input - Antenna reference
;B2	Bridge power		
;B3	LED (high to turn LED on)	.	
;B4	Receive/Xmit application (for test purposes)	
;B5	(not assigned - configure as INPUT with weak pullup)	
;B6	(not assigned - configure as INPUT with weak pullup)	
;B7	(not assigned - configure as INPUT with weak pullup)	


;D0	Reserved FOR UART RECEIVE - input has weak pullup
;D1	Reserved FOR UART TRANSMIT - output.
;D2	(not assigned - configure as INPUT with weak pullup)
;D3	(not assigned - configure as INPUT with weak pullup)
;D4	(not assigned - configure as INPUT with weak pullup)
;D5	(not assigned - configure as INPUT with weak pullup)
;D6	(not assigned - configure as INPUT with weak pullup)
;D7	(not assigned - configure as INPUT with weak pullup)


.cseg
	
.ORG $0000				;Initializaton code
	rjmp start
.ORG $0006 
	rjmp timer0service		;Timer/counter compare interrupt
.ORG $000A
	rjmp comparitorservice		;Service comparitor interupt

.include	"vflcw2313.inc"		;Load VLFCW routines


;Four callable routines are available. One register isnot saved, RFByte, which is
;used to transfer the data between the RF routines and calling routines and is
;to be a high register (r16-r31). It needs to be delcared as such in program calling this file..
;Calling other routines may result in modification of other registers. 
;	
;SendRFByte	(subroutine)
;Sends contents of RFChar via RF. Modifies RFChar.

;
;ReceiveRFByte	(subroutine)
;Waits for start bit on RF channel for 63.75 bit times. Returns with carry set and 
;data in RFChar if character received. Returns with carry clear if no byte received.

	
;		
;PostXmitDelay	;(macro)	;Wait for antenna to stop ringing from xmit.
;Use this delay after transmitting if listening is to follow. The delay allows
;ringing in the antenna to die down so that the ringing is not misatken as data.


;PostRCVDelay	;(macro)	;Wait for far end receiver to recover.	
;Use this after receiving data, before sending to give the receiver associated
;with the transmitter that just sent data to recover.	
;	



start:
   
	ldi	r16,RAMEND		;Initialize Stack Pointer.
	out	spl,r16
					;Set PORTD.
	ldi	temp,0b00000010		
	out	DDRD,temp
	ldi	temp,0b10111111
	out	PORTD,temp
	
					;Set PORTB.
	ldi	temp,0b00000000		
	out	DDRB,temp
	ldi	temp,0b11110100
	out	PORTB,temp		
	
	
	sbi	BridgePowerDDR,BridgePowerPin	;Turn on bridge power
	sbi	LEDOutDDR,LEDOutPin	;Make LED so an output pin.
	sei				;ENABLE THE INTERRUPTS
	
	
	
;////////////////// END OF INITIALIZATION CODE \\\\\\\\\\\\\\\\\\\\\\\\\
	
	
.exit