116MHz LO using PIC12F629 and ADF4351

After replacing the fake synth chip with a real one, I needed a small and reliable controller to upload the parameters to the six registers in the ADF4351.  I decided to use a PIC instead of an Arduino as it is about 12 years since I last used a PIC and back then it was a UV-erasure job (16C74A I think?) and a programmer with a ZIF socket, and an early version of MPASM.

Part of the reason was a request for advice on the rsgbtech Yahoo group from Mike G6TRM, so grateful thanks to Mike for providing the spur.  The rest of the reason is all of the pieces written by Andy Talbot G4JNT that use a PIC.  Andy makes it seem quite straightforward, so I thought I’d better get the soldering iron out and just get on with learning about new-fangled chips and in-circuit programming.

I decided to push myself a bit and learn how to use the PICkit3 in-circuit programmer and MPLAB-X IDE, coding in C using XC8.

The project is a 116MHz local oscillator with dual outputs via a 5th order Chebyshev LPF with a corner at 140MHz and 0.1dB ripple.  I edge-soldered the Chinese ADF4351 board into a tinplate box and fitted a 5V regulator and protection diode.  As I wasn’t sure about the design of the PIC daughterboard, I decided to go back to the 1970s and use Veroboard for a change.

I need a few more of these little controllers, so I might order a batch of PCBs and use a surface-mount PIC and level-shifting resistors.  For now, the Veroboard is doing a fine job.

pic12f629-for-adf4351

The 6-pin and 2-pin sockets fit the ADF4351 board.  The 6-pin header is for the PICkit3 in-circuit programmer.  The resistors are required because the PIC is a 5V version and the 4351 is 3.3V.  The PIC runs fine on 3.3V, but I can’t then use the in-circuit programmer.

It all works fine, the output looks clean enough at 116MHz.  I am using it as an injection-lock stabiliser for the Anglian overtone crystal LOs.

The code is still rather ugly and uncommented.

#pragma config FOSC=INTRCIO, WDTE=OFF, PWRTE=ON, MCLRE=OFF, BOREN=OFF, CP = OFF, CPD = OFF
#define _XTAL_FREQ 1000000
////////////////////////////////
// Change these parameters    //
// This is for 116MHz, with   //
// 3712MHz VCO divided by 32  //
// and 10 MHz PFD so INT=371  //
// FRAC=1, MOD=5 and DIV=32   //
////////////////////////////////
#define FRAC 1
#define INT 371
#define MOD 5
#define DIV 32
/////////////////////////////
#define R0 (INT*32768)+(FRAC*8)
#define R1 (0x08008001)+(MOD*8)
#define R2 0x78004E42
#define R3 0xB
#define R5 0x580005
#if DIV == 64
#define DIVX 6
#elif DIV == 32
#define DIVX 5
#elif DIV == 16
#define DIVX 4
#elif DIV == 8
#define DIVX 3
#elif DIV == 4
#define DIVX 2
#elif DIV == 2
#define DIVX 1
#elif DIV == 1
#define DIVX 0
#endif
#define R4 (0x84003C)+(DIVX*1048576)
#define SEN GPIO5
#define SCL GPIO4
#define SDA GPIO2
#if defined(__XC)
 #include <xc.h> /* XC8 General Include File */
#elif defined(HI_TECH_C)
 #include <htc.h> /* HiTech General Include File */
#endif

#include <stdint.h> /* For uint8_t definition */
#include <stdbool.h> /* For true/false definition */

#include "system.h" /* System funct/params, like osc/peripheral config */
#include "user.h" /* User funct/params, such as InitApp */

void send(void)
{
 SCL=1; 
 SCL=0; 
}
void SPIsend(uint32_t reg)
{
 SEN=0;
 for(int n=31;n>=0;n--)
 {
 SDA=(reg&0x80000000)?1:0;
 send();
 reg<<=1;
 } 
 SEN=1;
 SEN=0;
 SDA=0;
}
void SPIsetup(void)
{
 TRISIO5=0;
 TRISIO4=0;
 TRISIO2=0;
 SCL=0;
}
void main(void) 
{
 __delay_ms(1000);
 SPIsetup();
 SPIsend(R5);
 SPIsend(R4);
 SPIsend(R3);
 SPIsend(R2);
 SPIsend(R1);
 SPIsend(R0); 
 SLEEP();
}

Leave a Reply

Your email address will not be published. Required fields are marked *