;----------------------------------------------------------------------
;
; 
;	Program:	mixer_lo.asm
;
;	Function:	programs the PLL for the 2.5GHz fixed LO in
;			the mixer module of the RF generator
;
;	Author:		Herbert Dingfelder, DL5NEG
;
;	Hardware:	AT90S1200 with RCEN-Bit set to enable
;			(runs on internal RC-Osc. without crystal)
;			PLL IC is a National Semiconductor LMX2320
;
;	Historie:	- Based on complete_beacon.asm from 21.02.2001
;			- CW call-sign sending taken out of the code
;			- 17.10.2001 comments tranlated in to english
;			- 18.10.2001 continue comments translation and
;			             major cleanup
;			- 19.10.2001 final test in simulator
;
;----------------------------------------------------------------------

; Functionality of this software:
; At power-on the software waits for a moment to make sure that the
; supply voltage at the PLL is stable. Then it sends the programing
; bits that sets the PLL (LMX2320) to 2.500 GHz (Rref=13MHz). The 
; programing is done via the (software emulated) 3wirebus interface. 
; After the job is done the processor is put into sleep mode to reduce 
; the current consumption and the interference to a minimum.

; Note: Remember that the EEPROM data must be loaded to the processor
; separately. (A .epp file is created by the assembler. This must be
; also be sent to the traget with the programer.)

; Note: AVR Studio shows a warning when this code is assembled. This
; warning is not justified! It warns that there is a odd number of
; values in the .db command. Since this .db is in the .cseg (EEPROM)
; part of the code this is absolutely ok. The EEPROM is organized
; in single bytes so there is no need to have an even number of values
; per .db command.



;**** Includes ****
.include "1200def.inc"	; Hardware is a AT90S1200

;**** Definitions (names for used registers) ****
.def EEdat = r0
.def EEadr = r16
.def dummy = r17
.def data  = r18
.def len   = r19
.def pa    = r20
.def temp  = r21

;**** Aliases for better code readability ****
.equ PLL_BUS       = PORTB  ; Bits 0-2 of Port B are used as
.equ PLL_BUS_DIR   = DDRB   ; data, clock, enable lines for the
			    ; 3wirebus interface

.equ DATA	   = 0	    ; these are the lines on the 3wire-bus	
.equ CLK	   = 1	    ; to the PLL and the corresponding bits	
.equ LE		   = 2	    ; on port B

;**** All code from here on is for the program memory (the flash) ****
.CSEG



;+++++++++++++++++++++++++ Main program +++++++++++++++++++++++++++++++

	ldi temp, 0b00000111	; set Bit 0-2 of the PLL-BUS as output
	out PLL_BUS_DIR, temp	; (they form the 3wirebus to the PLL)
	
	ldi pa, 7		; wait for 7*66ms=462ms to make sure that
	rcall pause		; the supply voltage at the PLL is stable
				
	rcall prog_pll		; program the PLL

	rcall cpu_sleep		; put the CPU into sleep mode

end:				; endless loop (just in case the CPU
	rjmp end		; wakes up for some reason)
			


;------------------------- EEread --------------------------------------

; Fetches one byte from the EEPROM. The register EEadr is used as a
; pointer and contains the address in the EEPROM that shall be read.
; The read value is stored in the register EEdat. This routine can
; be generally used whenever one byte shall be read from the EEPROM.
EEread:

	sbic EECR, EEWE		; wait until the EEPROM is ready to respond
	rjmp EEread

	out EEAR, EEadr		; put the address that shall be read into
				; the EEPROM address register

	sbi EECR, EERE		; set the EEPROM read-strobe 
	
	in EEdat, EEDR		; read the data value

	ret			; return to the main program



;-------------------------- pause --------------------------------------------
; Waits for certain time, depending on the register pa. One value in pa
; refers to one overflow of the 8-Bit timer with a prescaler of 256.
; => t= (1/fq) * 256 * 256 with fq = crystal frequency
; Since the hardware in this case is a AT90S1200 running on the internal
; RC oscillator, fq is 1MHz (roundabout, the RC osc. is not that stable)
; 	-> t = 66ms * pa
pause:
	
	ldi temp, 0b00000100	; set the prescaler to 256
	out tccr0, temp

	in temp, tifr		; reset the overflow bit of the counter
	sbr temp, exp2(tov0)
	out tifr, temp

	clr temp		; reset the counter
	out tcnt0, temp
	
cwait:	in temp, tifr		; when tcnt0 produces an overflow, tov0 will be set
	sbrs temp, tov0		; -> this loop runs until that overflow occurs
	rjmp cwait

	dec pa			; now the timer has produced an overflow, 
	brne pause		; count down the register pa and run the counter
				; again until pa is down to zero
	
	ret			; return to the main program
	


;------------------------- CPU sleep -----------------------------------
; puts the CPU into sleep mode (including shutoff of the XCO)
cpu_sleep:

	in dummy, MCUCR		; read the current control register setting
	sbr dummy, exp2(SE)	; sleepmode enable (not yet switched on)
	sbr dummy, exp2(SM)	; select 'power down' as sleepmodus
	out MCUCR, dummy	; write back the control register
	sleep			; switch on the sleepmode 
				; (sleep is obviously ignored in the simulator
				; but in practice is works just fine
	ret			; return (the CPU should not make it to this
				; point, just in case it wakes up for some
				; reason)



;-------------------------- Prog PLL------------------------------------
; programs the PLL with the datas that are stored in the EEPROM
prog_pll:

	ldi EEadr, PLLDATA	; load pointer with the first EEPROM address

prog_word_loop_start:

	rcall EEread		; read the EEPROM data from the address
				; that is pointed to by the pointer

	sbrc EEdat,1		; jump to end of this loop if
	rjmp prog_word_end	; bit 1 in the read value is set, i.e.
				; if it was the end-mark (which is 2 or 6)

	out PLL_BUS, EEdat	; output the data on PLL_BUS, (bit 0)

	sbi PLL_BUS, CLK	; set CLOCK bit on the PLL_BUS   (clock high)
	cbi PLL_BUS, CLK	; reset CLOCK bit on the PLL_BUS (clock low again)

	inc EEadr		; set the pointer to the next address

	rjmp prog_word_loop_start ; go to loop start for the next bit 

prog_word_end:

	sbi PLL_BUS, LE		; set LOADENABEL bit on PLL_BUS (load enable high)
	cbi PLL_BUS, LE		; reset LOADENABLE bit on PLL_BUS (load enable low)

	inc EEadr		; put the pointer to the next bit (which would be the
				; first bit of the next program word, provided there is
				; another word)
				
	sbrs EEdat, 2		; if bit 2 was set in the latest EEPROM value then
	rjmp prog_word_loop_start ; this was the last program word and we will not jump
				; upwards, otherwise we do for the next word

	ret			; return to the main program



; ----- and here are the datas for the PLL that will be stored in the EEPROM --------

; These are the datas for the PLL. For each bit that shall be send to the PLL
; we use one byte (set to 0 or 1). As a mark for the end of a complete programm
; word we use the value 2, i.e. whenever we want the strobe line on the 3wirebus
; (also called LE for load enable) to go high, we put a 2 in the EEPROM data string.
; If we want to mark the end of all data in the EEPROM we use a 6 instead of a 2.
 
;**** All code from here on is for the EEPROM ****
.ESEG

PLLDATA:
	.db 1,0,0,0,0,0,0,0,0,0,0,1,1,0,1,1,2	    ; Ref. 1MHz at 13MHz fq
	.db 0,0,0,0,0,1,0,0,1,1,1,0,0,0,0,1,0,0,0,6 ; 2500 MHz at 250kHz Ref.




