ad9850_683.asm
;
;Test till enkel sändare med DDS AD9850 och PIC12F683
;där nycklingen sker med "POWER DOWN" biten
;20130330
;SM7UCZ, Johnny Apell
;prov med 30.72MHz kristall 50% mindre ström
;Det finns mer att göra med programmet
;frekvensen kan "hoppa" 100Hz om potentiometern
;står i kritiskt läge.

;Program för att styra en DDS AD9850
;med hjälp av en potentiometer för frekvensen 3500...3600kHz
;Potentiometrarna läses in med 10 bitar (1024 steg)
;VFO potentiometern har fått en upplösning av 100Hz/steg
;vilket ger 100kHz inställningsområde
;
;AD9850 kan styras i steg om 0.0291Hz... inte jämt delbart med 2 precis!
;
;Test gjord med 30.72MHz klocka  mycket lägre strömförbrukning

;**********************************************************************************
;*****[ Data Storage Reg's ]*****
        CBLOCK  0x20        	; Tilldela registerna olika namn från adressen 0x20
		BitCount	
		Temp		
		A0			
		A1			
		A2		
		A3			
		B0			
		B1			
		B2			
		B3			
		R0			
		R1			
		R2			
		R3			
		R4
		ENDC
								;Tilldela enkilda bitar ett unikt namn

#define		FData				GPIO,2
#define		WClk				GPIO,0
#define		FQud				GPIO,1
#define		TX					GPIO,5


;***************************************************************************************
					; MACRO DEFINITIONS för att banka till de två minnessidorna
BANK0	MACRO
		BCF 		STATUS,RP0 		;Bank 0
		ENDM

BANK1	MACRO
		BSF 		STATUS,RP0 		;Bank 1
		ENDM

;*******************************************************************
					;Macro för multiplikation

; 					Double Precision Multiplication
;
; 					A1 : A0 * B1 : B0 -> R3:R2:R1:R0
;
; 					Standard shift and add.
;					Execution time: 215 to 295 clock cycles.
; 					Code space: 22 locations
;		
; 					Cleaned up and corrected version from Microchip Ap note by BF.
;					Note: Ap note has errors! Additional mods by Scott Dattalo.
; 					A×B=R

					;Macro A × B = R 
mpy16b16: macro
		local 	m1, m2
		clrf 	R3
		clrf 	R2
		clrf	R1
		clrf	R0
		bsf 	R1, 7
m1:
		rrf 	A1, f
		rrf 	A0, f
		skpc
		goto 	m2
		movf 	B0, w
		addwf 	R2, f
		movf	B1, w
		skpnc
		incfsz 	B1, w
		addwf 	R3, f
m2:
		rrf 	R3, f
		rrf 	R2, f
		rrf 	R1, f
		rrf 	R0, f
		skpc
		goto 	m1

		endm


;******************************************************************************************


;Här talar vi om för assemblerprogrammet vilken processor vi har och vilka adresser
;som vi ska starta ifrån

		list    p=12f683			;direktiv till assemblern om vilken process. som valts

		#include <p12f683.inc>  	; processor specific variable definitions
	
		ERRORLEVEL -302 			; suppress message because of page change
		;konfigureringsordet till processorn	
	__config _INTOSCIO & _WDT_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_ON & _CPD_OFF & _BOD_NSLEEP & _IESO_OFF & _FCMEN_OFF


		org     0	     			;adress vid power on eller reset
		goto    init   				;gå till initiering av kretsen.. i slutet av programmet


			
;************************************************************************************
									;Subrutin för att läsa in analogvärdet från potentiometern, frekvensen
									;Värdet läses in med 10 bitar.. 0..1023 steg
AD3	
		btfss	TX					;ändra inte freq under sändning
		return							

		bsf		ADCON0,2			;välj ad-ingång 3
		bsf		ADCON0,3
		bcf		ADCON0,4
		bsf		ADCON0,GO			;starta ad-omvandlingen
		btfsc	ADCON0,GO			;kolla om ad-omvandlingen är färdig
		goto	$-1					;vänta tills ad-omvandlingen är färdig
		BANK1						;banka till sida 1
		movfw	ADRESL				;ladda det nya låga ad-värdet från AD-omvandlaren
		BANK0						;banka tebaks till sida 0
		movwf   B0					;placera låga delen i register B0...
		movfw	ADRESH				;och höga delen
		movwf	B1					;i B1
		clrf	B2					;rensa registren B2, B3
		clrf	B3

		call	hz100				;ladda in 100Hz steg i register "A" Potentiometern finns i register "B"
		mpy16b16					;multiplicera (A × B) potentiometern med 100Hz steg
									;Nu har vi potentiometern (0...1023) multiplicerad med antal 100Hz
		call	khz3500				;kolla och ladda vilket frekvensband som skall köras
		call	add32				;svaret ovan ligger i "R" och frekvensbandet i "A"  addera ihop dem

		return



;**********************************************************************************
khz3500	
										;30.720 MHz kristall
		movlw	0xaa					;
		movwf	A0
		movlw	0xaf
		movwf	A1						;testade siffror mot frekvensräknare
		movlw	0x2a	
		movwf	A2
		movlw	0x1d
		movwf	A3
		return
										;125MHz kristall 1B6244D9
;***********************************************************************************
hz100
		movlw	0x71				;30.720 MHz kristall
		movwf	A0					;
		movlw	0x35				;
		movwf	A1					;trimmade siffror /UCZ
		clrf	A2
		clrf	A3
		return
		

;***************************************************************************
									; 32-bit Addition  R=R+A
add32   movf    A0,W
        addwf   R0,F
        movf    A1,W
        btfsc   STATUS,C
        incfsz  A1,W
        addwf   R1,F
        movf    A2,W
        btfsc   STATUS,C
        incfsz  A2,W
        addwf   R2,F
        movf    A3,W
        btfsc   STATUS,C
        incfsz  A3,W
        addwf   R3,F
		return

;***********************************************************************************
SendSynth  		     			;Send Tx registers as a serial data to DDS
								;snipp hämtat från nätet


					
		clrf	R4				;cleara phase registret det skall vara 0

		btfsc	TX				;om nyckeln uppe
		bsf		R4,2			;sätt bit power down
	
        movf    R0 , W			;skicka en byte i taget till AD9850 börja med R0
        call    Write9850
        movf    R1 , W			;skicka R1
        call    Write9850
        movf    R2 , W			;Skicka R2
        call    Write9850
        movf    R3 , W			;Skicka R3
        call    Write9850
        movf    R4 , W          ;Sist skickar vi Phase word R4 som skall vara nollor
        call    Write9850
 	    bsf     FQud      		;uppdatera frekvensen i AD9850
        nop						;vänta lite...
        bcf     FQud			;sänk signalen
        bcf     FData			;nollställ databiten
        nop
        return
;*****************
Write9850						;klockar ut datat till AD9850
								;snipp hämtat från nätet
		movwf	Temp			;skriv in data biten från "w" i Temp
        movlw   8				;ladda in "8"  antalet databitar i varje byte
        movwf   BitCount		;placera i biträknaren
Loop9850
        bcf     WClk       		;data changes with -ve edge of clock
        rrf     Temp,f			;rotera åt höger
        btfss   STATUS , C		;kolla om biten som ramlade över kanten var 0 eller 1
        bcf     FData			;om "0" reset databiten
        btfsc   STATUS , C
        bsf     FData			;om "1" sätt databiten
		nop						;vänta lite...
	    bsf     WClk     		;höj clockbiten
		nop						;vänta lite
		bcf		WClk			;sänk klocksignalen
		nop						;vänta lite
		bcf		FData			;sänk datasignalen
        decfsz  BitCount,f      ;räkna ner biträknaren ett steg   
        goto    Loop9850		;om räknaren inte är 0... kör ett varv till
        return					;om räknaren var 0... denna byte är nu sänt klart

;**********************************************************************
main
	
		call	AD3				;läs in potentiometerläget för VFO
		call	SendSynth		;skicka resultatet till AD9850
		goto	main

;********************************************************************
	
							;Initiering av kretsen
							;detta sker endast vid uppstart av processorn
init   
	
		BANK0		
		clrf	GPIO
		movlw	b'00000111'
		movwf	CMCON0			;comparators OFF
		movlw   b'10000001'  	;ladda 0000 0001 = vänsterjust, AD=on 
		movwf   ADCON0     		;placera i ADCON0	
		BANK1
		movlw	b'11111000'		;välj vilka pinnar som skall vara IN=1
		movwf	TRISIO			
    	movlw   b'11110001'     ;8MHz Clk, IntOsc, SysClk via IntOsc
    	movwf   OSCCON
		movlw	b'01111000'		;välj vilka pinnar som skall vara analoga in 1=analog
		movwf	ANSEL
		bcf		OPTION_REG,7	;enable pullup
		movlw	b'00100000'		;pullup on GPIO5
		movwf	WPU
		BANK0					;välj registersida
		clrf	GPIO			;rensa utgångarna
		goto    main   			;gå till huvudprogrammet
	
		end

