Phase Locked Loop Synthesizer Software Drivers
by Voltage Ventures in Circuits > Arduino
465 Views, 0 Favorites, 0 Comments
Phase Locked Loop Synthesizer Software Drivers
A phase-locked loop (PLL) is a control system that generates an output signal with a phase related to the phase of an input signal. PLLs are electronic circuits that constantly adjust to match the frequency of an input
I did an Instructables project before for PLL in great detail.
this new project is about a new software driver for a PLL IC chip, that has been used in an analog TV tuner.
with a good antenna and analog TV tuner, you can listen to FM radio, truck driver's radio, and any emergency services in your area that use FM analog transmission, because the analog TV tuner has a 3-band mixer/oscillator and PLL for
terrestrial tuners. that is capable of operating from 40MHZ to 1GHZ RF frequency
by knowing the channel frequency you want to listen to, you can select the right band and frequency.
any Arduino board will do, PLL uses I2C.
Supplies
datasheet for different analog TV tuner PLL IC chip
New Software Drivers
I programmed everything using Visual Studio Code IDE platform IO, am still learning new things in programming when I come up with new drivers, like auto scan and save channels getting notification when the PLL is locked, and saving user
favorite channel, I will update the new driver soon
you can use this software with any Arduino board.
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Encoder.h>
// I2C device address
#define DEVICE_ADDRESS 0x10
// Reference Divider
#define REFERENCE_DIVIDER 640
// Step Size
#define STEP_SIZE 50000 // 50 kHz
// LCD Configuration
LiquidCrystal_I2C lcd(0x27, 16, 2); // Change the address if needed, and adjust the dimensions
// Rotary Encoder Configuration
Encoder encoder(2, 3); // Adjust the pin numbers based on your setup
// Switch Input Configuration
const int switchPin = 4; // Adjust the PIN based on your setup
bool switchState = LOW;
bool lastSwitchState = LOW;
unsigned long lastSwitchTime = 0;
unsigned long switchDebounceTime = 50; // Adjust the debounce time as needed
// Frequency variables for each band with minimum and maximum values
uint32_t minFrequencyBandI = 54.0e6;
uint32_t maxFrequencyBandI = 88.0e6;
uint32_t rfFrequencyBandI = minFrequencyBandI; // Starting frequency for Band I (VHF-LO)
uint32_t minFrequencyBandII = 174.0e6;
uint32_t maxFrequencyBandII = 216.0e6;
uint32_t rfFrequencyBandII = minFrequencyBandII; // Starting frequency for Band II (VHF-HI)
uint32_t minFrequencyBandIII = 470.0e6;
uint32_t maxFrequencyBandIII = 806.0e6;
uint32_t rfFrequencyBandIII = minFrequencyBandIII; // Starting frequency for Band III (UHF)
uint32_t minFrequencyBandIV = 807.0e6;
uint32_t maxFrequencyBandIV = 1.4e9;
uint32_t rfFrequencyBandIV = minFrequencyBandIV; // Starting frequency for Band IV
uint8_t dividerByte1, dividerByte2;
uint8_t slaveAddress = 0x20; // Replace with your actual slave address
uint8_t controlByte = 0x3C; // Replace with your actual control byte
uint8_t portControlBandI = 0x01; // Port control value for Band I
uint8_t portControlBandII = 0x02; // Port control value for Band II
uint8_t portControlBandIII = 0x03; // Port control value for Band III
uint8_t portControlBandIV = 0x04; // Port control value for Band IV
void setDeviceConfiguration(uint8_t slaveAddress, uint8_t dividerByte1, uint8_t dividerByte2, uint8_t controlByte, uint8_t portControl) {
Wire.beginTransmission(DEVICE_ADDRESS);
Wire.write(dividerByte1);
Wire.write(dividerByte2);
Wire.write(controlByte);
Wire.write(portControl);
Wire.endTransmission();
delay(10);
Wire.requestFrom(0x61,1); //in-lock flag (FL = 1 when the loop is phase-locked)
while (Wire.available())
{
lockst = Wire.read();
}
}
void calculateDividerBytes(uint32_t rfFrequency, uint8_t ÷rByte1, uint8_t ÷rByte2) {
uint16_t dividerValue = rfFrequency / (REFERENCE_DIVIDER * STEP_SIZE);
dividerByte1 = (dividerValue >> 8) & 0xFF;
dividerByte2 = dividerValue & 0xFF;
}
void displayConfigurationOnLCD(uint32_t rfFrequency) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("RF Frequency:");
lcd.setCursor(0, 1);
lcd.print(rfFrequency / 1e6, 1); // Display frequency in MHz with one decimal place
lcd.print(" MHz");
}
void switchBand() {
// Switch to the next band
if (portControlBandI == 0x01) {
// Switch from Band I to Band II
portControlBandI = 0x00;
portControlBandII = 0x01;
rfFrequencyBandI = minFrequencyBandII;
calculateDividerBytes(rfFrequencyBandII, dividerByte1, dividerByte2);
setDeviceConfiguration(slaveAddress, dividerByte1, dividerByte2, controlByte, portControlBandII);
displayConfigurationOnLCD(rfFrequencyBandII);
} else if (portControlBandII == 0x02) {
// Switch from Band II to Band III
portControlBandII = 0x00;
portControlBandIII = 0x01;
rfFrequencyBandII = minFrequencyBandIII;
calculateDividerBytes(rfFrequencyBandIII, dividerByte1, dividerByte2);
setDeviceConfiguration(slaveAddress, dividerByte1, dividerByte2, controlByte, portControlBandIII);
displayConfigurationOnLCD(rfFrequencyBandIII);
} else if (portControlBandIII == 0x03) {
// Switch from Band III to Band IV
portControlBandIII = 0x00;
portControlBandIV = 0x01;
rfFrequencyBandIII = minFrequencyBandIV;
calculateDividerBytes(rfFrequencyBandIV, dividerByte1, dividerByte2);
setDeviceConfiguration(slaveAddress, dividerByte1, dividerByte2, controlByte, portControlBandIV);
displayConfigurationOnLCD(rfFrequencyBandIV);
} else if (portControlBandIV == 0x04) {
// Switch from Band IV back to Band I
portControlBandIV = 0x00;
portControlBandI = 0x01;
rfFrequencyBandIV = minFrequencyBandI;
calculateDividerBytes(rfFrequencyBandI, dividerByte1, dividerByte2);
setDeviceConfiguration(slaveAddress, dividerByte1, dividerByte2, controlByte, portControlBandI);
displayConfigurationOnLCD(rfFrequencyBandI);
}
}
void setup() {
Wire.begin();
lcd.begin(16, 2); // Adjust these values based on your LCD module
pinMode(switchPin, INPUT_PULLUP); // Internal pull-up resistor for the switch
// Set the initial configuration for Band I (VHF-LO)
calculateDividerBytes(rfFrequencyBandI, dividerByte1, dividerByte2);
setDeviceConfiguration(slaveAddress, dividerByte1, dividerByte2, controlByte, portControlBandI);
// Display the initial configuration on the LCD for Band I
displayConfigurationOnLCD(rfFrequencyBandI);
}
void loop() {
static long lastEncoded = 0;
long encoderValue = encoder.read();
// Read the switch input and debounce
int reading = digitalRead(switchPin);
if (reading != lastSwitchState) {
lastSwitchTime = millis();
}
if ((millis() - lastSwitchTime) > switchDebounceTime) {
if (reading != switchState) {
switchState = reading;
// Toggle between bands on switch press
if (switchState == HIGH) {
switchBand();
}
}
}
if (encoderValue != lastEncoded) {
// Adjust the frequency based on the encoder rotation (for simplicity, using a fixed step)
if (encoderValue > lastEncoded) {
if (rfFrequencyBandI + 0.1e6 <= maxFrequencyBandI) {
rfFrequencyBandI += 0.1e6; // Increase frequency by 0.1 MHz
}
} else {
if (rfFrequencyBandI - 0.1e6 >= minFrequencyBandI) {
rfFrequencyBandI -= 0.1e6; // Decrease frequency by 0.1 MHz
}
}
// Calculate new divider bytes and set the device configuration
calculateDividerBytes(rfFrequencyBandI, dividerByte1, dividerByte2);
setDeviceConfiguration(slaveAddress, dividerByte1, dividerByte2, controlByte, portControlBandI);
// Update the LCD display
displayConfigurationOnLCD(rfFrequencyBandI);
lastEncoded = encoderValue;
}
// Your other loop code, if needed
}