include p12F629.inc
Dout equ 0x00
Dout_port equ GPIO
Enb equ 0x04
Enb_port equ GPIO
Clk equ 0x05
Clk_port equ GPIO
Clock_count equ 0x20
Out_data_2 equ 0x21
Out_data_1 equ 0x22
Out_data_0 equ 0x23
clock_count2 equ 0x24
Out_data_2_b equ 0x25
Out_data_1_b equ 0x26
Out_data_0_b equ 0x27
org 0
clrf Clock_count
decfsz clock_count2, f
goto $-1
decfsz Clock_count, f
goto $-3 ;startup pause
movlw 0x07
movwf CMCON ;turn off comparators
bsf STATUS, RP0 ;go to bank 1
bcf Enb_port, Enb
bcf Dout_port, Dout
bcf Clk_port, Clk ;enable the outputs
bcf STATUS, RP0 ;back to bank 0
bsf Enb_port, Enb ;start off with the enable line high
bcf Clk_port, Clk ;and the clock low
clrf Clock_count
decfsz clock_count2, f
goto $-1
decfsz Clock_count, f
goto $-3 ;pause to make sure the PLL has started
call reset_PLL
reset_PLL
;With the data line low, and the enable line high
;this needs to clock out 4 cycles
bcf Dout_port, Dout
bsf Enb_port, Enb
movlw 0x04
movwf Clock_count
reset_clock_loop
bsf Clk_port, Clk
nop
bcf Clk_port, Clk
decfsz Clock_count, f
goto reset_clock_loop
movlw 0x05
movwf Clock_count
movlw 0x02
movwf Out_data_0
call data_out ;clock out the remaining 5 bits of the reset sequence
;This outputs 0 to the configuration register
;That is the default so it does nothing but it's here so that other numbers can be output
movlw 0b00000000
movwf Out_data_0
movlw 0x08
movwf Clock_count
call data_out
;This now outputs 80 to the reference divider.
;The 15 clock cycles cause it to be addressed to the reference divider
;With a 4 MHz reference and a resolution of 50 kHz, the reference needs to be divided by 80
movlw 0x0f
movwf Clock_count
movlw 0
movwf Out_data_1
movlw 0x50
movwf Out_data_0
call data_out
;Now this outputs 2140 to the frequency divider.
;The 16 clock cycles cause it to be addressed to the frequency divider
;2140 x 50 kHz = 107 MHz
movlw 0x10
movwf Clock_count
movlw 0x08
movwf Out_data_1
movlw 0x5C ;there might be a neat way of getting the assembler
; to split 2140 into two bytes.
movwf Out_data_0
call data_out
;that's it
;All the program does now is die
goto $ ;This needs the watchdog to be disabled
data_out
;the data needs to be msb first, but the length of the data varies.
;So it has to be reversed first
movf Clock_count, w
movwf clock_count2
data_reverse_loop
;This reverses the Clock_count bits of data into Out_data_n_b
;so that the MSB ends up in the LSB of Out_data_0_b
rrf Out_data_2, f
rrf Out_data_1, f
rrf Out_data_0, f ;rotate data towards LSB
rlf Out_data_0_b, f
rlf Out_data_1_b, f
rlf Out_data_2_b, f ;rotate data towards MSB
decfsz clock_count2, f
goto data_reverse_loop
movwf clock_count2 ;collect count again from w
bcf Enb_port, Enb ;lower enable line
data_out_loop
;This output data starting with the LSB of Out_data_0_b
btfsc Out_data_0_b, 0
bsf Dout_port, Dout
btfss Out_data_0_b, 0
bcf Dout_port, Dout ;output data
rrf Out_data_2_b, f
rrf Out_data_1_b, f
rrf Out_data_0_b, f ;rotate data to LSB
bsf Clk_port, Clk
nop
bcf Clk_port, Clk ;clock data into PLL
decfsz clock_count2, f
goto data_out_loop
bsf Enb_port, Enb ;raise enable line to save data
return
end