; Frequencies needed for a PM5507 clone based on SAA1043
; Outputs CLK0 for SAA and CLK1&2 for subcarrier +/- f(h)
; The PM5507 generates a PAL rainbow test pattern for aligning color TVs.
; v0.0 230728 Start project, copy-paste from cmcd_pll_tx.asm
; v0.1 240211 Fix phase relation HSYNC and color subcarrier not defined
; v0.2 240211 Move to PIC12F675 because phase detector is not fast enough. Need external HEF4046
; v0.3 240212 Implement clock skip circuit to enable proper phase detection with 74HC4046
; v0.4 240213 Read voltage of phase detector
; v1.0 240214 Release
LIST P=12F675, F=INHX8M
#include <P12F675.INC>
__CONFIG _INTRC_OSC_NOCLKOUT & _WDT_OFF & _CP_OFF & _CPD_OFF & _BODEN_OFF & _MCLRE_ON & _PWRTE_OFF
ERRORLEVEL -302 ; remove message about using proper bank
; Equates
RESET_V EQU 0x00 ; Address of RESET Vector
; Registers
FLAGS EQU 0x20 ; Various flags
I2CBUF EQU 0x21 ; Used for I2C data
I2CCNT EQU 0x22 ; Used for I2C bitbanger
CTR1 EQU 0x24 ; Counter for delay (inner)
CTR2 EQU 0x25 ; Second Counter (outer)
CTRP EQU 0x26 ; Number of nudges
; Defines
#define SDA GPIO,0 ; I2C Data
#define SCL GPIO,1 ; I2C Clock
#define LED GPIO,4 ; LOW: Red, HIGH: Green to show successful phase chase
#define SKIP GPIO,5 ; Drive to transistor to short SAA1043 clock input to GND in order to nudge phase
#define NAK FLAGS,1 ; Not Acknowledge after I2C byte
#define SYSINIT FLAGS,2 ; Clear when system init of Si5351A has completed
; GPIO,2 is defined as analog input (AN2)
ORG 0
GOTO START
ORG 4
; There are no interrupts
RETFIE
; End interrupts
START
; Init stuff
CLRF STATUS ; Do initialization, select Bank 0
CLRF INTCON ; Clear int-flags, disable interrupts
CLRF PCLATH ; Keep in lower 2KByte
BSF STATUS,RP0 ; Select Bank 1
MOVLW B'00000111' ; TMR0 Prescaler 1:256, enable weak pullups
MOVWF OPTION_REG
MOVLW B'00000100'
MOVWF TRISIO ; GPIO,0,1,5 outputs, GPIO,2 input
MOVLW B'01010100'
MOVWF ANSEL ; GPIO,2 is analog input
BCF STATUS,RP0 ; Select Bank 0
MOVLW B'00001001'
MOVWF ADCON0 ; A/D config
CLRF T1CON
MOVLW B'00000111' ; Comparators off
MOVWF CMCON
CLRF INTCON
CLRF GPIO
CLRF FLAGS
BSF SCL
BSF SDA
; Initialize Si5351A
INITOSC
CALL I2CSTART
MOVLW 0xC0 ; Address
CALL I2CBYTE
CLRW ; Prepare register 0 for reading
CALL I2CBYTE
CALL I2CSTOP
Readsysinit ; Check if Si5153A is ready (SYS_INIT)
CALL I2CSTART
MOVLW 0xC1 ; Read address
CALL I2CBYTE
CLRF I2CCNT ; Used for ACK timeout
BSF STATUS,RP0 ; Select Bank 1
BSF TRISIO,0 ; Set SDA as input to float SDA line
BCF STATUS,RP0 ; Select Bank 0
CALL I2CDELAY
BSF SCL ; Read SYS_INIT bit
CALL I2CDELAY
BTFSS SDA
BCF SYSINIT
BCF SCL
MOVLW 0x07
MOVWF I2CCNT
DUMMYREAD
CALL I2CDELAY
BSF SCL
CALL I2CDELAY
BCF SCL
DECFSZ I2CCNT,F
GOTO DUMMYREAD
BSF STATUS,RP0 ; Select Bank 1
BCF TRISIO,0 ; Set SDA as output to assert SDA line
BCF STATUS,RP0 ; Select Bank 0
BCF SDA ; Present NAK
CALL I2CDELAY
BSF SCL
CALL I2CDELAY
BCF SCL
CALL I2CSTOP
BTFSC SYSINIT ; System init done?
GOTO Readsysinit ; No
; Start configure
CALL I2CSTART
MOVLW 0xC0 ; Address
CALL I2CBYTE
MOVLW 0x03 ; Register 3
CALL I2CBYTE
MOVLW 0xFF ; Register 3 data (Output Enable Control)
CALL I2CBYTE
CALL I2CSTOP
CALL I2CSTART
MOVLW 0xC0 ; Address
CALL I2CBYTE
MOVLW 0x09 ; Register 9
CALL I2CBYTE
MOVLW 0xFF ; Register 9 data (OEB Pin Enable Control Mask)
CALL I2CBYTE
CALL I2CSTOP
CALL I2CSTART
MOVLW 0xC0 ; Address
CALL I2CBYTE
MOVLW 0x10 ; Register 16
CALL I2CBYTE
MOVLW 0x4F ; Register 16 data
CALL I2CBYTE
MOVLW 0x6F ; Register 17 data
CALL I2CBYTE
MOVLW 0x2F ; Register 18 data
CALL I2CBYTE
MOVLW 0x80 ; Register 19 data
CALL I2CBYTE
MOVLW 0x80 ; Register 20 data
CALL I2CBYTE
MOVLW 0x80 ; Register 21 data
CALL I2CBYTE
MOVLW 0x80 ; Register 22 data
CALL I2CBYTE
MOVLW 0x80 ; Register 23 data
CALL I2CBYTE
CALL I2CSTOP
CALL I2CSTART
MOVLW 0xC0 ; Address
CALL I2CBYTE
MOVLW 0xB7 ; Register 183
CALL I2CBYTE
MOVLW 0xD2 ; Register 183 data: XTAL load capacitance and mandatory bit pattern
CALL I2CBYTE
CALL I2CSTOP
CALL I2CSTART
MOVLW 0xC0 ; Address
CALL I2CBYTE
MOVLW 0x1B ; Register 27
CALL I2CBYTE
MOVLW 0x03 ; Register 27 data
CALL I2CBYTE
CLRW ; Register 28 data is zero
CALL I2CBYTE
MOVLW 0x0E ; Register 29 data
CALL I2CBYTE
MOVLW 0xAA ; Register 30 data
CALL I2CBYTE
CLRW ; Register 31 data is zero
CALL I2CBYTE
CLRW ; Register 32 data is zero
CALL I2CBYTE
MOVLW 0x02 ; Register 33 data
CALL I2CBYTE
MOVLW 0x0D ; Register 34 data
CALL I2CBYTE
MOVLW 0x40 ; Register 35 data
CALL I2CBYTE
CLRW ; Register 36 data (zero)
CALL I2CBYTE
MOVLW 0x0D ; Register 37 data
CALL I2CBYTE
MOVLW 0xE7 ; Register 38 data
CALL I2CBYTE
MOVLW 0x31 ; Register 39 data
CALL I2CBYTE
MOVLW 0xE6 ; Register 40 data
CALL I2CBYTE
MOVLW 0xC0 ; Register 41 data
CALL I2CBYTE
CLRW ; Register 42 data (zero)
CALL I2CBYTE
MOVLW 0x03 ; Register 43 data
CALL I2CBYTE
CLRW ; Register 44 data (zero)
CALL I2CBYTE
MOVLW 0x51 ; Register 45 data
CALL I2CBYTE
MOVLW 0x55 ; Register 46 data
CALL I2CBYTE
CLRW ; Register 47 data (zero)
CALL I2CBYTE
CLRW ; Register 48 data (zero)
CALL I2CBYTE
MOVLW 0x01 ; Register 49 data
CALL I2CBYTE
CALL I2CSTOP
CALL I2CSTART
MOVLW 0xC0 ; Address
CALL I2CBYTE
MOVLW 0x33 ; Register 51
CALL I2CBYTE
MOVLW 0x01 ; Register 51 data
CALL I2CBYTE
CLRW ; Register 52 data (zero)
CALL I2CBYTE
MOVLW 0x58 ; Register 53 data
CALL I2CBYTE
CALL I2CSTOP
CALL I2CSTART
MOVLW 0xC0 ; Address
CALL I2CBYTE
MOVLW 0x3A ; Register 58
CALL I2CBYTE
MOVLW 0x9E ; Register 58 data
CALL I2CBYTE
MOVLW 0xED ; Register 59 data
CALL I2CBYTE
CLRW ; Register 60 data (zero)
CALL I2CBYTE
MOVLW 0x57 ; Register 61 data
CALL I2CBYTE
MOVLW 0x5E ; Register 62 data
CALL I2CBYTE
MOVLW 0x30 ; Register 63 data
CALL I2CBYTE
MOVLW 0xA1 ; Register 64 data
CALL I2CBYTE
MOVLW 0xFA ; Register 65 data
CALL I2CBYTE
CALL I2CSTOP
CALL I2CSTART
MOVLW 0xC0 ; Address
CALL I2CBYTE
MOVLW 0xB1 ; Register 177
CALL I2CBYTE
MOVLW 0xA0 ; Register 177 data (Reset PLLA&B)
CALL I2CBYTE
CALL I2CSTOP
CALL I2CSTART
MOVLW 0xC0 ; Address
CALL I2CBYTE
MOVLW 0x03 ; Register 3
CALL I2CBYTE
MOVLW 0xF8 ; Register 3 data: enable CLK0, CLK1 and CLK2
CALL I2CBYTE
CALL I2CSTOP
; Done setup Si5351A
MOVLW 0x14 ; 20 nudges to ensure PC2 is positive
MOVWF CTRP
BSF SKIP ; Skip phase (~10 clock pulses SAA1043)
BCF SKIP
CALL DELAY
DECFSZ CTRP
GOTO $-4
NUDGE1
BSF SKIP ; Skip phase (~10 clock pulses SAA1043)
BCF SKIP
CALL DELAY
BSF ADCON0,GO
BTFSC ADCON0,GO
GOTO $-1
MOVLW 0x80
SUBWF ADRESH,W
BTFSC STATUS,C ; Carry set (ADRESH>=0x80)?
GOTO NUDGE1 ; Yes
NUDGE2
BSF SKIP ; Skip phase (~10 clock pulses SAA1043)
BCF SKIP
CALL DELAY
BSF ADCON0,GO
BTFSC ADCON0,GO
GOTO $-1
MOVLW 0xD4
SUBWF ADRESH,W
BTFSS STATUS,C ; Carry set (ADRESH>=0xD4)?
GOTO NUDGE2 ; No
BSF LED
GOTO $ ; Loop forever
; Subroutines
I2CSTART
BCF SDA
CALL I2CDELAY
BCF SCL
CALL I2CDELAY
RETURN
I2CBYTE ; Sends byte in W
MOVWF I2CBUF
MOVLW 0x08
MOVWF I2CCNT
NEXTBIT
BCF STATUS,C ; Clear carry
RLF I2CBUF,F ; Rotate MSB into carry
BTFSC STATUS,C ; Carry clear?
BSF SDA ; No, set SDA
BTFSS STATUS,C ; Carry set?
BCF SDA ; No, clear SDA
CALL I2CDELAY
BSF SCL ; Send clock
CALL I2CDELAY
BCF SCL ; Done clock
DECFSZ I2CCNT,F
GOTO NEXTBIT
; ACK handler
BSF STATUS,RP0 ; Select Bank 1
BSF TRISIO,0 ; Set SDA as input to float SDA line
BCF STATUS,RP0 ; Select Bank 0
BSF NAK
CALL I2CDELAY
BSF SCL ; Solicit ACK
CLRF I2CCNT
TESTACK
BTFSC SDA ; SDA pulled low?
GOTO CONTACK ; No, continue testing for ACK until timeout (~20 ms)
BCF NAK ; Clear NAK
GOTO EXITACK ; Exit loop
CONTACK
DECFSZ I2CCNT,F
GOTO TESTACK
EXITACK
BSF STATUS,RP0 ; Select Bank 1
BCF TRISIO,0 ; Set SDA as output
BCF STATUS,RP0 ; Select Bank 0
BTFSC NAK ; NAK handler
GOTO START ; Timeout, no ACK, force reset
BSF SDA ; Just in case
CALL I2CDELAY
BCF SCL
CALL I2CDELAY
RETURN
I2CSTOP
BCF SDA
CALL I2CDELAY
BSF SCL
CALL I2CDELAY
BSF SDA
RETURN
I2CDELAY
NOP ; 8 us delay
NOP
NOP
NOP
RETURN
DELAY
DECFSZ CTR1,F ; Set up 178 ms delay
GOTO DELAY
DECFSZ CTR2,F
GOTO DELAY
RETURN
END