Welcome on DL4UNY's Radio-Page!



A simple PLL circuit with prescaler and ATtiny45

My good friend DL7CH asked me one day to build a Low Phase Noise and frequency-stable 1GHz oscillator for one of his RF projects. As such oscillators are a significant part for many HAM homemade projects, I decided to publish my design and my source code to make it easier for you to make your own PLL Oscillator :)
I used a Crystek 1 GHz VCO, divided by 8 with a MC12093D and the PLL IC itself is a ADF4002. Quite simple, quite effective, quite cheap. The output signal is coupled by a MiniCircuits 17dB coupler DBTC-17-5 (U106 in the schematic). To amplify the decoupled signal I used a cheap and small BGA614.
Schematic (click to enlarge)

The PLL PCB



Find the source code below:
/*
* =====================================================================================
*
* Filename: pll.c
*
* Description: ADF4002 mit 1GHz Crystek und 10MHz Ref, ATtiny45
*
* Version: 1.0
* Created: 17.12.2019 21:17:36
* Revision: none
* Compiler: gcc
*
* Author: Andre Schoch (), contact@dl4uny.de
* Organization: DL4UNY
*
* =====================================================================================
*/


/*********************************************************

USI to SPI communication routine

Controller: ATtiny 45, Osc. = 1 MHz

*********************************************************/

#define F_CPU 1000000UL
#include <avr/io.h>
#include <stdlib.h>
#include <util/delay.h>

#define LED PB3
#define USCK PB2 //CLK
#define DO PB1 //Data Out
#define DI PB0 //Data In
#define LE PB4 //Latch Enable

void SPI_init(void)
{
DDRB |= (1<<USCK)|(1<<DO); //Output: PB2=USCK, PB1=DO
DDRB &= ~(1<<DI); //Input: PB0=DI
PORTB |= (1<<DI); //int. Pull-up an PB0 aktivieren
DDRB |= (1<<LED); //LED auf Ausgang

USICR = (1<<USIWM0) | (1<<USICLK)|(1<<USITC)| (1<<USICS1);
// USIWM0 = 1: SPI-Betrieb mit DO, DI und USCK
// USICLK = 1, USITC = 1, USICS1 = 1: generiert den Taktimpuls für das Schieberegister und
// den 4bit Timer. Der Takt wird am USCK-Pin (PA4) ausgegeben.
}



void SPI_transfer(int data)
{
USIDR = data; //Daten in Data Register laden
USISR |= (1<<USIOIF); //Überlaufflag löschen

while (!(USISR & (1<<USIOIF))) //solange kein Timerüberlauf...
{
USICR |= (1<<USITC); //Toggle clk (2x)
USICR |= (1<<USITC);
}
}

void pll(void)
{
//ADF4002
//initialization latch
uint8_t I_LATCH_H = 0b00011011; //X X PD2 CPI6 CPI5 CPI4 CPI3 CPI2
uint8_t I_LATCH_M = 0b01110000; //CPI1 TC4 TC3 TC2 TC1 F5 F4 F3
uint8_t I_LATCH_L = 0b00000011; //F2 M3 M2 M1 PD1 F1 C2 C1

//function latch
uint8_t F_LATCH_H = 0b00011011; //X X PD2 CPI6 CPI5 CPI4 CPI3 CPI2
uint8_t F_LATCH_M = 0b01110000; //CPI1 TC4 TC3 TC2 TC1 F5 F4 F3
uint8_t F_LATCH_L = 0b00000010; //F2 M3 M2 M1 PD1 F1 C2 C1

//main counter
uint8_t N_COUNTER_H = 0b00100000; //X X G1 B13 B12 B11 B10 B9
uint8_t N_COUNTER_M = 0b01111101; //B8 B7 B6 B5 B4 B3 B2 B1
uint8_t N_COUNTER_L = 0b00000001; //X X X X X X C2 C1

//reference counter
uint8_t R_COUNTER_H = 0b00010011; //X 0 0 LDP T2 T1 ABP2 ABP1
uint8_t R_COUNTER_M = 0b00000000; //R14 R13 R12 R11 R10 R9 R8 R7
uint8_t R_COUNTER_L = 0b00101000; //R6 R5 R4 R3 R2 R1 C2 C1

PORTB &= ~(1<<LE); //LE auf Low
SPI_transfer(I_LATCH_H);
SPI_transfer(I_LATCH_M);
SPI_transfer(I_LATCH_L);
PORTB |= (1<<PB0); //LE auf High

_delay_us(1);
PORTB &= ~(1<<LE); //LE auf Low
SPI_transfer(F_LATCH_H);
SPI_transfer(F_LATCH_M);
SPI_transfer(F_LATCH_L);
PORTB |= (1<<LE); //LE auf High

_delay_us(1);
PORTB &= ~(1<<LE); //LE auf Low
SPI_transfer(R_COUNTER_H);
SPI_transfer(R_COUNTER_M);
SPI_transfer(R_COUNTER_L);
PORTB |= (1<<LE); //LE auf High

_delay_us(1);
PORTB &= ~(1<<LE); //LE auf Low
SPI_transfer(N_COUNTER_H);
SPI_transfer(N_COUNTER_M);
SPI_transfer(N_COUNTER_L);
PORTB |= (1<<LE); //LE auf High
_delay_ms(1);
}

void blink(void)
{
PORTB &= !(1<<LED); // LED on
_delay_ms(100);
PORTB |= (1<<LED); // LED off
_delay_ms(100);
}


int main(void)
{
blink();
SPI_init();
blink();
pll();
_delay_ms(10);
pll();
blink();
_delay_ms(500);
blink();
/* while(1)
{
pll();
PORTB |= (1<<LED); // Led on
_delay_ms(100);
PORTB &= !(1<<LED); // Led off
_delay_ms(100);
}
*/
}