L’ADF4351 est un circuit intégré de type PLL, pilotable par un bus SPI pouvant générer un signal RF de 35MHz à 4.4GHz.
Les 4 premières parties sont de la documentation sur l’ADF4351 (permet d’aller plus vite que de lire la datasheet quand il s’agit de produire un programme de zéro). La partie ‘Métrologie’ est une ébauche pour caractériser l’ADF4351. La dernière partie est une annexe contenant le code pour pouvoir contrôler l’ADF en fréquence et puissance.
Branchement de la plaquette avec l’arduino
Arduino | ADF4351 | commentaire |
---|---|---|
D8 | MUXOUT | pas besoin d’étage d’adaptation |
D9 | LE | adapation 5->3.3V requis (à l’état bas ce signal indique le début du communication, c’est en gros une pin qui active le registre à décalage de l’ADF) |
D11 | DATA | adapatation (donné qui sera écrite dans le registre à décalage pendant que CLK sera sur un front montant) |
D13 | CLK | adaptation |
VCC | la plaquette s’alimente en 5V (même si la tension d’entrée de l’ADF est de 3.3V) |
Communication avec l’ADF
Un registre à décalage est remplie pendant 32 coups d’horloge (correspondant aux 32 bits des registres). Une fois ce registre remplie, son contenu est envoyé dans l’un des 6 registres de l’ADF (les 3 bits de poid faible indique le bon registre). L’ensemble des 6 registres peux donc être programmé en coups d’horloge.
Description grossière des registres
(voir la fin de cette section pour la sémantique des valeurs)
Registre 0
FRAC
du bit 3 au bit 14INT
du bit 15 au bit 30
Registre 1
MOD
du bit 3 au bit 14Prescaler
bit 27
Registre 2
MUXOUT
du bit 26 au bit 28
Registre 4
RF Divider Select
du bit 20 à 22Output Power
bit 3 et 4RF Output Enable
bit 5
Sémantique
RF Output Enable
active la sortie RF si ce bit est à 1 et la désactive sinon.Output Power
règle la puissance du signal de sortie selon:| 00 -> -4 dbm
| 01 -> -1 dbm
| 10 -> +2 dbm
| 11 -> +5 dbm
La fréquence de sortie de l’ADF va être donné par le calcul suivant:
Structure typique d’un programme
La valeur de chaque registre est stocké dans un tableau de taille 6:
uint32_t registers[6] = {0x8F8008, 0x80080A1, 0x18005E42, 0x8004B3, 0x814004, 0x580005};
Il s’agit ici des valeurs initiales à mettre dans l’ADF. Il est également nécessaire de renseigner la fréquence du quartz au début du programme double PFDRFout = 10;
. Voici le contenu typique du setup d’un programme utilisant l’ADF :
#include <SPI.h>
// etat initial des registres
uint32_t registers[6] = {0x8F8008, 0x80080A1, 0x18005E42, 0x8004B3, 0x814004, 0x580005};
// Fréquence du quartz de la plaquette
double PFDRFout = 10;
void setup() {
SPI.begin()
// Block initialement le transfert de donnee
pinMode(ADF4351_LE, OUTPUT);
digitalWrite(ADF4351_LE, HIGH);
// Programmation de l'etat initial dans l'ADF
SetADF4351();
}
Le squelette d’une fonction qui communique avec l’ADF est le suivant:
void some_function(int some_parameter) {
// manipulate registers table
SetADF4351();
}
où SetADF4351
est une fonction qui programme les registres de l’ADF conformément aux valeurs contenues dans registers
(voir code en annexe).
Métrologie
Lien vers une association de radio-amateur utilisant l’ADF4351 avec l’Arduino : ADF4351 et Arduino. On peut voire différentes mesures effectués à l’analyseur de spectre.
Annexe
Le code suivant permet de générer n’importe quelle fréquence dans la plage de fréquence de l’ADF avec la fonction SetFreq(unfloat)
, d’activer la sortie RF avec la fonction PowerEnable(0 ou 1)
et de régler la puissance avec SetPower(1 2 3 ou 4)
(pour -4, -1, +2, +5dbm)
#include <SPI.h>
// ADF4351 setting ////////////////////////////////////////////////////////////////
// Arduino PIN D8 ADF4351 MUXOUT
// Arduino PIN D9 ADF4351 LE
// Arduino MOSI PIN D11 ADF4351 DATA
// Arduino SCK PIN D13 ADF4351 CLK
#define ADF4351_LE 9 // LE pin of ADF4351
// #define LOCK 8 // Input to detect lock-in from AD4351 (optional), a check of the lock can be performed after setting the ADF4351
uint32_t registers[6] = {0x8F8008, 0x80080A1, 0x18005E42, 0x8004B3, 0x814004, 0x580005}; // Default values to initialize the ADF4351 registers (from Analog Devices software)
double PFDRFout = 10; // Default, reference frequency of the ADF4351 module on-board oscillator (10 MHz)
void setup() {
// put your setup code here, to run once:
SPI.begin();
// Initialize ADF4351
// pinMode(LOCK, INPUT); // Not used because AD4351 has 3.3V output logic
pinMode(ADF4351_LE, OUTPUT);
digitalWrite(ADF4351_LE, HIGH); // Set LE high to block data trasfer
SetADF4351();
SetPower(4); // Set ouput power, possible values are 1,2,3,4
PowerEnable(1); // Set power on (1), or off (0)
SetFreq(2800.0); // Set up a starting frequency for test
}
void loop() {
// put your main code here, to run repeatedly:
// Do whatever you want with SetFreq, SetPower and PowerEnable
}
// Send the 32 bits of the register to the AD4351
void WriteRegister32(const uint32_t value) // Register 32 bit
{
SPI.setDataMode(SPI_MODE0); // See the AD4351 datasheet for SPI communication
SPI.setBitOrder(MSBFIRST);
digitalWrite(ADF4351_LE, LOW); // Latch low starts the data transfer
// delayMicroseconds(1);
for (int i = 3; i >= 0; i--)
{ // Loop to send 32 bits as 8 bits four times
SPI.transfer((value >> 8 * i) & 0xFF); // Set offset, byte masking and send via SPI
}
digitalWrite(ADF4351_LE, HIGH); // Latch high to complete the data transfer
// delayMicroseconds(1);
}
// Program all the six registers of the AD4351
void SetADF4351()
{
for (int i = 5; i >= 0; i--)
{ // Registers writing starts with the last register
WriteRegister32(registers[i]);
}
delay(10);
}
// Enable or disable power of the ADF4351
void PowerEnable(byte val)
{
if (val == 0)
{ // MW Disabled
bitWrite(registers[4], 5, 0);
}
if (val == 1)
{ // MW Enabled
bitWrite(registers[4], 5, 1);
}
SetADF4351();
}
// Set power of the ADF4351
void SetPower(byte val)
{
if (val == 1)
{ // DB3, DB4 00 -4dbm
bitWrite(registers[4], 4, 0);
bitWrite(registers[4], 3, 0);
}
else if (val == 2)
{ // DB3, DB4 01 -1dbm
bitWrite(registers[4], 4, 0);
bitWrite(registers[4], 3, 1);
}
else if (val == 3)
{ // DB3, DB4 10 +2dbm
bitWrite(registers[4], 4, 1);
bitWrite(registers[4], 3, 0);
}
else if (val == 4)
{ // DB3, DB4 11 +5dbm
bitWrite(registers[4], 4, 1);
bitWrite(registers[4], 3, 1);
}
SetADF4351();
}
// Set the output frequency of the ADF4351
void SetFreq(double val)
{
double RFout = val;
double FRACF;
byte OutputDivider; // Parameters to set the range of frequency
if (RFout > 4400 && RFout < 35)
{
} // Frequency not available // Maximum and Minimum frequency of the ADF
else
{
if (RFout >= 2200)
{ // 2200-4400 MHz is the recommended range with a fundamental frequency
OutputDivider = 1;
bitWrite(registers[4], 22, 0);
bitWrite(registers[4], 21, 0);
bitWrite(registers[4], 20, 0);
}
if (RFout < 2200)
{
OutputDivider = 2;
bitWrite(registers[4], 22, 0);
bitWrite(registers[4], 21, 0);
bitWrite(registers[4], 20, 1);
}
if (RFout < 1100)
{
OutputDivider = 4;
bitWrite(registers[4], 22, 0);
bitWrite(registers[4], 21, 1);
bitWrite(registers[4], 20, 0);
}
if (RFout < 550)
{
OutputDivider = 8;
bitWrite(registers[4], 22, 0);
bitWrite(registers[4], 21, 1);
bitWrite(registers[4], 20, 1);
}
if (RFout < 275)
{
OutputDivider = 16;
bitWrite(registers[4], 22, 1);
bitWrite(registers[4], 21, 0);
bitWrite(registers[4], 20, 0);
}
if (RFout < 137.5)
{
OutputDivider = 32;
bitWrite(registers[4], 22, 1);
bitWrite(registers[4], 21, 0);
bitWrite(registers[4], 20, 1);
}
if (RFout < 68.75)
{
OutputDivider = 64;
bitWrite(registers[4], 22, 1);
bitWrite(registers[4], 21, 1);
bitWrite(registers[4], 20, 0);
}
unsigned int long INTA, MOD, FRAC; // Parameters to set the frequency, use the unsigned int long 32 bit to save easily on the register by using the shifts command >> <<
// Rfout = fpdf * (INTA +FRAC/MOD) Equation to use for the calculation
INTA = (RFout * OutputDivider) / PFDRFout;
MOD = (PFDRFout / 0.05);
FRACF = (((RFout * OutputDivider) / PFDRFout) - INTA) * MOD;
FRAC = round(FRACF); // Results is rounded in case of divisions with remainder
// Register 0 is only to save FRAC and INT values
registers[0] = 0; // Set all the bit zero and the control bits 000 to indicate register 0
registers[0] = INTA << 15; // Save the INTA in the register by using the shift
FRAC = FRAC << 3; // Shift the FRAC to save
registers[0] = registers[0] + FRAC; // Save the FRAC in the register
// Register 1 is to save the MOD values, prescaler and phase value
registers[1] = 0; // Reset the register for calculation, phase adjust DB28 remains set to zero
registers[1] = MOD << 3; // Store the MOD values
registers[1] = registers[1] + 1; // Add +1 to make the control bits 001 and indicate the register 1
bitWrite(registers[1], 27, 1); // Set prescaler of 8/9 on DB27
// Set mux-out on digital-lock detect mode [110] for B28, B27, B26 bits (no need if it is already in default)
bitWrite(registers[2], 28, 1);
bitWrite(registers[2], 27, 1);
bitWrite(registers[2], 26, 0);
SetADF4351();
}
RFint = RFout;
}
Github avec un code pour contrôler un ADF4351: https://github.com/dfannin/adf4351